UNPKG

6.2 kBMarkdownView Raw
1# Epsilon
2
3A tiny library to simplify serving consistent apis from Lambda with OpenAPI
4
5# TODO:
6
7- Discuss pros/cons of single lambda for http/batch in this document
8- path/query var checking against open api doc
9- check compression handling
10
11## How better than just using straight Node?
12
13- Uses typescript instead of the Godforsaken straight javascript
14- Handles route mapping (multiple ends, single lambda)
15- Uses Promises and has a top level .catch to convert to 500
16- Adds compression
17- Adds CORS
18- Adds JWT handling
19- Consistent error handling
20- Can serve static content as well
21- Kinda-persistent objects allow for optimistic caching
22- Built in support for Non-HTTP (Batch) processing via SaltMint, SNS, SQS, Email, etc
23
24# How better than using Express?
25
26- Doesn't have req/res architecture to fake so much easier to test
27- Much lighter
28
29# Other service
30
31- Environmental service
32- Simple redirects
33
34# Version 0.4.0 Release Notes
35
36- Switched logging for GraphQL introspection calls on local-server down to silly level
37- Updated to new version of libraries
38- Switched to js-yaml instead of node-yaml
39- Moved api-gateway package to http package to reflect that this also handles ALB endpoints
40
41# Version 0.3.0 Release Notes
42
43- Remapped CRON handler to be able to filter on more than just the incoming Event name. Given the new mapping,
44 I'd recommend just setting up an "every minute" Cloudwatch event and using filters. Filters now allow
45 running multiple Batch processors, eg Dev/QA/Prod
46- Adding logging of request ID to output errors
47- Added default error (to allow masking of 500 errors in prod and prevent information leakage)
48- Allow optional access to the request context for handlers (esp for the request id, remaining time)
49
50# GraphQL Support (v0.1.x and above)
51
52If you are just doing straight GraphQL then you don't really need to use Epsilon at all (I'd recommend just
53going with straight https://www.npmjs.com/package/apollo-server-lambda). However, if you want to start messing
54with GraphQL while maintaining your existing OpenAPI 3.0 endpoints, Epsilon allows you to designate a regular
55expression for which all matching requests are delegated to a supplied ApolloServer, bypassing Epsilon.
56
57To do this, you must include the following libraries (They aren't marked as dependencies of Epsilon since they
58aren't required if you don't support GraphQL)
59
60```
61 "apollo-server-lambda": "2.8.1",
62 "graphql": "14.4.2",
63```
64
65Then, in your router-config, you must set an ApolloServer and an Apollo Regex:
66
67```typescript
68const typeDefs = gql`
69 type Query {
70 hello: String
71 }
72`;
73
74// Provide resolver functions for your schema fields
75const resolvers = {
76 Query: {
77 hello: () => 'Hello world!'
78 }
79};
80
81const server: ApolloServer = new ApolloServer({ typeDefs, resolvers });
82
83// ...
84
85const cfg: RouterConfig = RouterUtil.openApiYamlToRouterConfig(yamlString, handlers, authorizers, options);
86
87// ...
88cfg.apolloServer = server;
89cfg.apolloCreateHandlerOptions = {
90 origin: '*',
91 credentials: true
92} as CreateHandlerOptions;
93cfg.apolloRegex = new RegExp('.*graphql.*');
94```
95
96# Usage
97
98## Using WebHandler to simplify the Lambda
99
100You will configure a RouterConfig, and then create a WebHandler from that. Your lambda
101function should look like:
102
103```
104const handler: Handler = (event: APIGatewayEvent, context: Context, callback: Callback) => {
105 const routerConfig: RouterConfig = getMyRouterConfig(); // Implement this function
106 const commonHandler: WebHandler = new WebHandler(routerConfig);
107 commonHandler.lambdaHandler(event, context, callback);
108};
109
110export {handler};
111
112```
113
114## Using auth/AuthHandler to simplify a JWT token based auth
115
116Your auth lambda should look like this (I here assume you are storing your encryption key in AWS
117System Manager so you can keep it encrypted at rest, which you definitely should be doing):
118
119```
120
121import {AuthHandler} from '@bitblit/epsilon/dist/auth/auth-handler';
122import {Callback, Context, CustomAuthorizerEvent, Handler} from 'aws-lambda';
123import {EnvironmentService} from '@bitblit/ratchet/dist/aws/environment-service';
124import 'reflect-metadata';
125
126const handler: Handler = (event: CustomAuthorizerEvent, context: Context, callback: Callback) => {
127
128 EnvironmentService.getConfig('MyConfigurationName').then(cfg => {
129 const commonAuth: AuthHandler = new AuthHandler('api.mycompany.com', cfg['encryptionKey']);
130 commonAuth.lambdaHandler(event, context, callback);
131 });
132};
133
134export {handler};
135
136```
137
138This will pass through anyone with a valid JWT token. Note that Epsilon doesn't yet support role based
139filtering in this version.
140
141To create valid JWT tokens, your authentication endpoint can use the **auth/WebTokenManipulator** class like so
142(after you have verified the users principal/credentials pair) :
143
144```
145 // Other authentication stuff happens up here.
146 const email: string = 'user-email@test.com';
147 const roles: string[] = ['USER','NOT-AN-ADMIN'];
148 const userData: any = {'other': 'stuff'};
149 const myConfig: any = await EnvironmentService.getConfig('MyConfigurationName'); // same as above
150 const encryptionKey: string = cfg['encryptionKey'];
151 const adminUser: any = null; // Set this if the user is an admin doing run-as (this is the admin user)
152 const expSec: number = 3600; // How long until this token expires in seconds
153
154 const tokenHandler: WebTokenManipulator = new WebTokenManipulator(encryptionKey, 'api.mycompany.com');
155 const token: string = tokenHandler.createJWTString(email, userData, roles, expSec, admin);
156
157```
158
159# Notes on adding a new gateway/stage
160
161You'll need to auth the gateway to hit the lambda (yes, as of 2018-10-13 this is still ugly) :
162
163```
164aws lambda add-permission --function-name "arn:aws:lambda:us-east-1:{accountId}:function:{lambda-function-name}"
165 --source-arn "arn:aws:execute-api:us-east-1:{account number}:{api id}/*/*/*"
166 --principal apigateway.amazonaws.com
167 --statement-id b57d8a0f-08e5-407c-9093-47d7e8e840bc
168 --action lambda:InvokeFunction
169
170```
171
172And you'll need to remember to go to IAM / Keys and authorize the new stack user to use your KMS key (if you are
173using KMS to encrypt your config via SystemManager, which you should be doing)