openapi-backend icon indicating copy to clipboard operation
openapi-backend copied to clipboard

API Gateway with event.headers not working as expected

Open Y2KForever opened this issue 4 months ago • 1 comments

Hi, trying to use this openapi-backend to validate and follow our openapi specification, but currently running into an issue with the handleRequest.

this is our lambda:

"use strict";

import { APIGatewayProxyEvent, Context } from "aws-lambda";
import search from "./controllers/search";
import { middyCore } from "./utils/middy/wrappers";
import OpenAPIBackend from "openapi-backend";
import addFormats from "ajv-formats";
import { OPENAPI_SPEC_LOCATION, VALIDATE_RESPONSES } from "./utils/env";
import { getRequesterInfo } from "./utils/authentication";
import { UnauthorizedError } from "api-utilities/error";

const headers = {
  "content-type": "application/json; charset=utf-8",
};

const api = new OpenAPIBackend({
  definition: OPENAPI_SPEC_LOCATION,
  quick: true,
  strict: true,
  customizeAjv: (ajv) => {
    addFormats(ajv, { formats: ["date", "date-time"] });
    return ajv;
  },
});

api.register({
  postSearch: async (c) => {
    try {
      const resp = await search(c);
      return JSON.stringify(resp);
    } catch (err) {
      return JSON.stringify({
        statusCode: 400,
        body: JSON.stringify({
          errors: err,
        }),
      });
    }
  },

  validationFail: async (c) => {
    const body = JSON.stringify({
      errors: c.validation.errors,
    });
    return {
      statusCode: 400,
      body: body,
      headers: {
        "content-length": body.length,
        ...headers,
      },
    };
  },

  unauthorizedHandler: async (c) => {
    const body = JSON.stringify(c.security.TokenAuthorizer.error);
    return {
      statusCode: JSON.parse(body).status ?? 401,
      body: body,
      headers: {
        "content-length": body.length,
        ...headers,
      },
    };
  },
});

api.registerSecurityHandler("TokenAuthorizer", (c) => {
  const auth = getRequesterInfo(c.request.headers);
  if (auth instanceof UnauthorizedError) {
    return false;
  }
  return JSON.stringify(auth);
});

const lambdaHandler = async (event: APIGatewayProxyEvent, context: Context) => {
  await api.init();
  return api.handleRequest(
    {
      method: event.httpMethod,
      path: event.path,
      body: event.body,
      headers: event.headers as any,
    },
    event,
    context
  );
};

export const handler = middyCore(lambdaHandler);

where header: event.headers currently are throwing a typescript error, forcing us to use any.

Error:

Type 'APIGatewayProxyEventHeaders' is not assignable to type '{ [key: string]: string | string[]; }'.
  'string' index signatures are incompatible.
    Type 'string | undefined' is not assignable to type 'string | string[]'.
      Type 'undefined' is not assignable to type 'string | string[]'.ts(2322)
router.d.ts(23, 5): The expected type comes from property 'headers' which is declared here on type 'Request'

I couldn't find anything in the documentation mentioning this, only that we should use headers: event.headers.

Y2KForever avatar Mar 27 '24 12:03 Y2KForever