GithubHelp home page GithubHelp logo

authress-engineering / openapi-factory.js Goto Github PK

View Code? Open in Web Editor NEW
10.0 4.0 7.0 542 KB

API as first class node library to generate clients, servers, and documentation.

License: Apache License 2.0

JavaScript 100.00%
aws lambda apigateway

openapi-factory.js's Introduction

OpenAPI Factory (Javascript)

npm version

Provides an simple event interceptor for AWS Lambda. Handles events tha come from API Gateway, SQS, EventBridge, and all other AWS services and routes them to appropriate lambda code. This enables you to have single AWS Lambda function for your whole service instead of needing tons of nano-ones to handle every route.

By merging your lambda functions together, you eliminate 99% of all cold starts, and simplify deployment to AWS Lambda.

Partner libraries

Each of these usable completely independently. But both work together as well:

With the aws-architect npm package, you can also develop your lambda locally, spinning up a full HTTP API to have quick development cycles.

  • The OpenAPI Factory provides the production runtime wrapper to convert all the different AWS events into a simple format and processes the result
  • The AWS Architect library, let's you build, test, and run locally your lambda. And when you are ready it automatically packages your lambda and publishes it in S3, making it ready to pull into your Infrastructure as Code solution as soon as you would like.

Create an API

const ApiFactory = require('openapi-factory');
const options = {
  requestMiddleware(request, context) {
    return request;
  },
  responseMiddleware(request, response) {
    return response;
  },
  errorMiddleware(request, error) {
    return { statusCode: 500, body: { message: 'Unexpected Error' } };
  }
};
const api = new ApiFactory(options);

api.get('/example', async request => {
  // Short hand for returning a JSON object
  return { value: 'test' };

  // Or explicitly return the whole response
  return {
    body: { value: 'testWithStatus' },
    statusCode: 200,
    headers: { 'Content-Type': 'application/json' }
  };
});

// converts dynamic variables paths
api.get('/example/{id}/subpath', request => {
  const idFromPath = request.pathParameters.id;
  const stageVariable = request.stageVariables.VARIABLE_NAME;
  const query = request.queryStringParameters.QUERY_NAME;
  const headers = request.headers.HEADER_NAME;
});

api.setAuthorizer(request => {
  return 'valid-policy-document';
});

api.onEvent(event => {
  console.log('triggered by a direct invocation from a Lambda Event Source.');
// AWS Documentation: https://docs.aws.amazon.com/lambda/latest/dg/lambda-services.html
// Example payloads: https://lambda.101i.de/
});

api.onSchedule(data => {
  console.log('triggered by a CloudWatch Rule schedule');
});

api.get('/items/{itemid}', async request => {
  console.log(request.path.itemId);
  return {
    body: { value: 'testWithStatus' },
    statusCode: 200,
    headers: { 'Content-Type': 'application/json' }
  };
});

// paths have an optional options object which has property "rawBody" to return the raw body only.
api.get('/items/{itemid}', { rawbody: true }, async request => {
  console.log('This is he raw body of the request: ', request.body);
  return { statusCode: 200 };
});

// Example: AWS Api Gateway magic string handling for CORS and 404 fallbacks.
api.options('/{proxy+}', () => {
  return {
    statusCode: 200,
    headers: {
      'Access-Control-Allow-Headers': 'Content-Type,X-Amz-Date,Authorization,X-Api-Key',
      'Access-Control-Allow-Methods': 'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT',
      'Access-Control-Allow-Origin': '*'
    }
  };
});

api.any('/{proxy+}', () => {
  return {
    statusCode: 404,
    headers: {
      'Content-Type': 'application/json',
      'Access-Control-Allow-Origin': '*'
    }
  };
});

Default Headers

The default headers returned unless overwritten are:

  • For a JSON Object: { 'Content-Type': 'application/links+json', 'Access-Control-Allow-Origin': '*' }
  • For a binary Object: { 'Content-Type': 'application/octet-stream', 'Access-Control-Allow-Origin': '*' }

Custom PathResolver

It is possible that the default handling of REST routes does not match explicitly match your strategy for resolution. Since there is nothing more than string matching it is fairly easy to hoist this function.

const ApiFactory = require('openapi-factory');
// The default path resolver is the one contained in the PathResolver.
// * It parses the registered paths, stores them in a dictionary, and then looks them up later when necessary.
options.pathResolver = new PathResolver();
const api = new ApiFactory(options);

// However this can be replaced by a custom implementation which includes storePath and resolvePath
class PathResolver {
  constructor() {
    this.currentPathDictionary = {
      GET: {},
      POST: {}
      // ...
    };
  }

  // will get in the current dictionary object as well, there is a specific dictionary for each verb
  // * the current path string
  // * the object associated with that path
  // and returns the updated dictionary
  storePath(currentVerbPathDictionary, dynamicPath, storageObject) {
    return new PathDictionary();
  }

  // Later resolvePath is called to get back the currentPathDictionary and raw path,
  // * and expect to return the pre-stored storageObject
  resolvePath(currentPathDictionary, resolvedPath) {
    return storageObject;
  }
}

Lambda@Edge example

See Example here

openapi-factory.js's People

Contributors

wparad avatar dependabot[bot] avatar kretolus avatar subham0207 avatar mmaruniak avatar acchaulk avatar

Stargazers

Mike Nason avatar Marco Gonzalez avatar Shawn Torsitano avatar Dorota avatar Rhosys Service Account avatar Lewt avatar Andrej Kincel avatar Markus Thurner avatar Adrian Carballo avatar  avatar

Watchers

 avatar Markus Thurner avatar  avatar Rhosys Service Account avatar

openapi-factory.js's Issues

Support proxy path with prefixes

If I define a path with the following form :

/v1/{proxy+}

This framework will not be able to resolve the path since on line 91 of index.js it checks if the event.resource is exactly '/{proxy+}' . In this case the event.resource will be '/v1/{proxy+}' .
Instead the code should check if the event.resource contains '/{proxy+}' which will allow the proper route to be used.

Also line 99
let map = mapExapander.getMapValue(apiFactory.ProxyRoutes[event.httpMethod], event.pathParameters.proxy);
Should be changed to
let map = mapExapander.getMapValue(apiFactory.ProxyRoutes[event.httpMethod], event.path);

since the event.pathParameters.proxy will not include the /v1 suffix

Is HttpApi with payload version 2.0 supported ?

I have seen convertEvent function do some transformation with a few keys present in httpapi event(like routeKey) but i am not sure. I was able to get it to work for payload version 1.0(since the eventobject is same as RestAPI) but not 2.0.

Support for custom methods

Add explicit support for custom methods. I.e. that contain a resourceId followed by a colon followed by some static path without a path / delimiter.

Unable to handle proxy path when using Serverless

I have a serverless.yml with the following configuration

functions: app: handler: index.handler events: - http : path: /{proxy+} method : any cors: true

In the following line of code in index.js L89 - 91

let proxyPath = '/{proxy+}'; // default to defined path when proxy is not specified. if (event.resource !== proxyPath) {

event.resource resolves to '/{proxy*}' not /{proxy+}

in addition on L99

let map = mapExapander.getMapValue(apiFactory.ProxyRoutes[event.httpMethod], event.pathParameters.proxy);

event.pathParameters.proxy has '/' char url encode to %2F

ex /resource/foo is %2Fresource%2Ffoo

so the mapExpander.getMapValue will return null since it expects to split the string by '/'

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.