1.0.64 • Published 6 years ago

smallorange-gateway v1.0.64

Weekly downloads
4
License
ISC
Repository
-
Last release
6 years ago

CircleCI

Small Orange Gateway

Simple HTTP gateway for lambdas

This gateway takes care to create a HTTP server, call lambda functions, cache into Redis according to provided strategy and log into cloudWatch.

Sample

Setup

	// used env vars
	process.env.ACCESS_KEY_ID = 'xxxxx'; // (required)
	process.env.SECRET_ACCESS_KEY = 'xxxxx'; // (required)
	process.env.REGION = 'xxxxx'; // (optional)
	process.env.REDIS_URL = 'xxxxx'; // (optional)
	process.env.LOG_GROUP = 'xxxxx'; // (optional)
	process.env.PORT = 8080; // (optional)
	process.env.CACHE_PREFIX = ''; // (optional)
	process.env.CACHE_TTL = 2592000; // time in seconds to live (optional) default: 30 days
	process.env.CACHE_TTR = 7200; // time in seconds to refresh (optional) default: 2 hours
	process.env.CACHE_TIMEOUT = 1000; // time in ms to wait before route to the origin (optional) default: 1 second

	// lambdas manifest
	const lambdas = {
		'/': {
			name: 'functionName' // required,
			cache: {
				driver: {}, // Object like https://github.com/feliperohdee/smallorange-rxjs-cache-driver
				enabled: args => args.method === 'GET' && !args.hasExtension && !args.url.query || boolean,
				namespace: args => args.host, // required 
				key: args => args.url.pathname  || string // required,
				options: args => ({
					ttl: number, // optional, override default
					ttr: number // optional, override default
				})
			},
			transform: {
				args: args => { // it happens immediately after authentication is handled
					args.headers = {
						...args.headers,
						customHeader: 'customHeaderValue'
					};
				},
				response: (response, req, res) => {
					response.body = ...;
					
					return response;
				},
				error: err => {
					return err;
				}
			}
		},
		// or with HTTP verb
		'POST /': {
			name: 'functionName' // required,
			cache: {
				enabled: args => args.method === 'GET' && !args.hasExtension && !args.url.query || boolean,
				namespace: args => args.host, // required 
				key: args => args.url.pathname  || string // required
			},
			transform: {
				args: args => {
					args.headers = {
						...args.headers,
						customHeader: 'customHeaderValue'
					};
				}
			}
		},
		'/functionName': {
			name: 'functionName', // required
			// pass just params (not all args as described below) to the lambda function
			paramsOnly: true,
			defaults: {
				// default request params, it will be merged with params fetched from req.query, in case of key collision, the latter is going to have precedence
				requestParams: {
					width: 100,
					height: 100
				},
				// default response base64 value, lambda response can override this value, if checked, value will be converted to a buffer before returns to the browser
				responseBase64: true,
				// default response headers, lambda response headers will be merged with this value, in case of key collision, the latter is going to have precedence
				respondeHeaders: {
					'content-type': 'image/png'
				}
			}
		},
		'/local': {
			name: 'functionName', // required,
			local: path.resolve('...path to local function index')	
		},
		'/mocked': {
			mocked: args => 'anything'
		},
		'/authOnly': {
			name: 'functionName' // required,
			auth: {
				enabled: true,
				allowedFields: ['role', 'user', 'loggedAt'], // (optional)
				handleInvalidSignature: false, // (optional)
				secret: (payload, params, headers) => 'mySecret' || 'mySecret', // (required)
				token(params, headers) => params.token || headers.authorization // (optional),
				options: {
					/*
					algorithms: List of strings with the names of the allowed algorithms. For instance, ["HS256", "HS384"].
					audience: if you want to check audience (aud), provide a value here
					issuer (optional): string or array of strings of valid values for the iss field.
					ignoreExpiration: if true do not validate the expiration of the token.
					ignoreNotBefore...
					subject: if you want to check subject (sub), provide a value here
					clockTolerance: number of seconds to tolerate when checking the nbf and exp claims, to deal with small clock differences among different servers
					*/
				},
				resolve: (auth, args) => object || Observable<Object> // (optional)
			}
		},
		'/adminOnly': {
			enabled: args => true,
			name: 'functionName' // required,
			auth: {
				// ...
				requiredRoles: ['admin']
			}
		},
		'/adminOrPublic': {
			name: 'functionName' // required,
			auth: {
				// ...
				requiredRoles: ['admin', 'public']
			}
		},
		
		// note: JWT should have role property, like:
		// {
		// 	role: string, // (required)
		// 	...anyOtherParams
		// }

		// full wildcards
		'/*': {
			name: 'functionName' // required,
		},
		'/*/*': {
			name: 'functionName' // required,
		},
		// partial wildcards
		'/*/functionName': {
			name: 'functionName' // required,
		},
		'/*/*/functionName': {
			name: 'functionName' // required,
		}
	};

	const gateway = new Gateway({
		logGroup: 'myAppLogs', // || env.LOG_GROUP
		lambdas,
		redisUrl: 'redis://localhost:6380', // || env.REDIS_URL
		cachePrefix: '', || // env.CACHE_PREFIX
	});

Usage Details

	// for a request like
	GET http://localhost/functionName/resource?string=value&number=2&boolean=true&nulled=null

	// lambda function will receive args like:
	{
		auth: {}, // if enabled
		body: {},
		hasExtension: false, // if url ends with .jpg or .png
		headers: {
			//...request headers
		},
		host: 'http://localhost',
		method: 'GET',
		// fetched from req.query
		params: {
			string: 'value',
			number: 2,
			boolean: true,
			nulled: null,
		},
		url: {
			path: '/functionName/resource?string=value&number=2&boolean=true&nulled=null',
			pathname: '/functionName/resource',
			query: 'string=value&number=2&boolean=true&nulled=null'
		},
		uri: '/functionName/resource'
	}

	// or just params if explicity declared at lambdas manifest with "paramsOnly = true":
	{
		string: 'value',
		number: 2,
		boolean: true,
		nulled: null
	}

	// lambdas can responds with just string, or an object with following signature
	{	
		//string or stringified object,
		body: string,
		headers: object,
		base64: boolean,
		statusCode: number // is statusCode >= 400, gateway is going to handle as an error following the Http/1.1 rfc (https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html)
	}

Cache handling

	// you can manually mark cache to refresh making a request like:
	POST http://yourhost/cache
	{
		operation: 'markToRefresh',
		namespace: 'http://localhost'
	}

	// or unset
	POST http://yourhost/cache
	{
		operation: 'unset',
		namespace: 'http://localhost',
		keys: ['/', '/cart']
	}
1.0.64

6 years ago

1.0.63

6 years ago

1.0.62

6 years ago

1.0.61

6 years ago

1.0.60

6 years ago

1.0.59

6 years ago

1.0.58

6 years ago

1.0.57

6 years ago

1.0.56

6 years ago

1.0.55

6 years ago

1.0.54

6 years ago

1.0.53

6 years ago

1.0.52

6 years ago

1.0.51

6 years ago

1.0.50

6 years ago

1.0.49

6 years ago

1.0.48

6 years ago

1.0.47

6 years ago

1.0.46

6 years ago

1.0.45

6 years ago

1.0.44

6 years ago

1.0.43

6 years ago

1.0.42

7 years ago

1.0.41

7 years ago

1.0.40

7 years ago

1.0.39

7 years ago

1.0.38

7 years ago

1.0.37

7 years ago

1.0.36

7 years ago

1.0.35

7 years ago

1.0.34

7 years ago

1.0.33

7 years ago

1.0.32

7 years ago

1.0.31

7 years ago

1.0.30

7 years ago

1.0.29

7 years ago

1.0.28

7 years ago

1.0.27

7 years ago

1.0.26

7 years ago

1.0.25

7 years ago

1.0.24

7 years ago

1.0.23

7 years ago

1.0.22

7 years ago

1.0.21

7 years ago

1.0.20

7 years ago

1.0.19

7 years ago

1.0.18

7 years ago

1.0.17

7 years ago

1.0.16

7 years ago

1.0.15

7 years ago

1.0.14

7 years ago

1.0.13

7 years ago

1.0.12

7 years ago

1.0.11

7 years ago

1.0.10

7 years ago

1.0.9

7 years ago

1.0.8

7 years ago

1.0.7

7 years ago

1.0.6

7 years ago

1.0.5

7 years ago

1.0.4

7 years ago

1.0.3

7 years ago

1.0.2

7 years ago

1.0.1

7 years ago

1.0.0

7 years ago