UNPKG

voluptasmollitia

Version:
170 lines (156 loc) 5.1 kB
/** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { FunctionsErrorCode } from './public-types'; import { decode } from './serializer'; import { HttpResponseBody } from './service'; import { FirebaseError } from '@firebase/util'; import { FUNCTIONS_TYPE } from './constants'; /** * Standard error codes for different ways a request can fail, as defined by: * https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto * * This map is used primarily to convert from a backend error code string to * a client SDK error code string, and make sure it's in the supported set. */ const errorCodeMap: { [name: string]: FunctionsErrorCode } = { OK: 'ok', CANCELLED: 'cancelled', UNKNOWN: 'unknown', INVALID_ARGUMENT: 'invalid-argument', DEADLINE_EXCEEDED: 'deadline-exceeded', NOT_FOUND: 'not-found', ALREADY_EXISTS: 'already-exists', PERMISSION_DENIED: 'permission-denied', UNAUTHENTICATED: 'unauthenticated', RESOURCE_EXHAUSTED: 'resource-exhausted', FAILED_PRECONDITION: 'failed-precondition', ABORTED: 'aborted', OUT_OF_RANGE: 'out-of-range', UNIMPLEMENTED: 'unimplemented', INTERNAL: 'internal', UNAVAILABLE: 'unavailable', DATA_LOSS: 'data-loss' }; /** * An explicit error that can be thrown from a handler to send an error to the * client that called the function. */ export class FunctionsError extends FirebaseError { constructor( /** * A standard error code that will be returned to the client. This also * determines the HTTP status code of the response, as defined in code.proto. */ code: FunctionsErrorCode, message?: string, /** * Extra data to be converted to JSON and included in the error response. */ readonly details?: unknown ) { super(`${FUNCTIONS_TYPE}/${code}`, message || ''); } } /** * Takes an HTTP status code and returns the corresponding ErrorCode. * This is the standard HTTP status code -> error mapping defined in: * https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto * * @param status An HTTP status code. * @return The corresponding ErrorCode, or ErrorCode.UNKNOWN if none. */ function codeForHTTPStatus(status: number): FunctionsErrorCode { // Make sure any successful status is OK. if (status >= 200 && status < 300) { return 'ok'; } switch (status) { case 0: // This can happen if the server returns 500. return 'internal'; case 400: return 'invalid-argument'; case 401: return 'unauthenticated'; case 403: return 'permission-denied'; case 404: return 'not-found'; case 409: return 'aborted'; case 429: return 'resource-exhausted'; case 499: return 'cancelled'; case 500: return 'internal'; case 501: return 'unimplemented'; case 503: return 'unavailable'; case 504: return 'deadline-exceeded'; default: // ignore } return 'unknown'; } /** * Takes an HTTP response and returns the corresponding Error, if any. */ export function _errorForResponse( status: number, bodyJSON: HttpResponseBody | null ): Error | null { let code = codeForHTTPStatus(status); // Start with reasonable defaults from the status code. let description: string = code; let details: unknown = undefined; // Then look through the body for explicit details. try { const errorJSON = bodyJSON && bodyJSON.error; if (errorJSON) { const status = errorJSON.status; if (typeof status === 'string') { if (!errorCodeMap[status]) { // They must've included an unknown error code in the body. return new FunctionsError('internal', 'internal'); } code = errorCodeMap[status]; // TODO(klimt): Add better default descriptions for error enums. // The default description needs to be updated for the new code. description = status; } const message = errorJSON.message; if (typeof message === 'string') { description = message; } details = errorJSON.details; if (details !== undefined) { details = decode(details); } } } catch (e) { // If we couldn't parse explicit error data, that's fine. } if (code === 'ok') { // Technically, there's an edge case where a developer could explicitly // return an error code of OK, and we will treat it as success, but that // seems reasonable. return null; } return new FunctionsError(code, description, details); }