diff --git a/package-lock.json b/package-lock.json index 7cbff64..9e6e851 100644 --- a/package-lock.json +++ b/package-lock.json @@ -754,6 +754,11 @@ } } }, + "@types/aws-lambda": { + "version": "8.10.33", + "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.33.tgz", + "integrity": "sha512-BZ8lPY/vyUq+Bid/BgYrKbUF36SZYuGOAMgOq/VgqnTQnCn9GBo3HejKZ6xrUzA8zLf9Pjs707amkt4f7rWujw==" + }, "@types/babel__core": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.2.tgz", diff --git a/package.json b/package.json index 023752c..db91e11 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "semantic-release": "^15.13.21" }, "dependencies": { + "@types/aws-lambda": "^8.10.33", "accepts": "^1.3.7", "type-is": "^1.6.18" } diff --git a/src/lambda-wrapper.d.ts b/src/lambda-wrapper.d.ts new file mode 100644 index 0000000..2c3b684 --- /dev/null +++ b/src/lambda-wrapper.d.ts @@ -0,0 +1,12 @@ +import { Request } from './request'; +import { Response } from './response'; +import { APIGatewayProxyHandler } from 'aws-lambda'; + +export interface Middleware { + (request: Request, response: Response, next: Function): void +} + +export function use(...handlers: Middleware[]): ApiGatewayProxyHandler; + +export { Request } from './request'; +export { Response } from './response'; diff --git a/src/request.d.ts b/src/request.d.ts new file mode 100644 index 0000000..514bd55 --- /dev/null +++ b/src/request.d.ts @@ -0,0 +1,122 @@ + +import { APIGatewayProxyEvent } from 'aws-lambda'; +import { Accepts } from 'accepts'; +import { Readable } from 'stream'; + +export class Request extends Readable { + constructor(event: APIGatewayProxyEvent); + headers: { [name: string]: string }; + hostname: string | null; + method: string; + query: { [name: string]: string } | null; + path: string; + params: { [name: string]: string } | null; + protocol: 'http' | 'https'; + secure: boolean; + ips: string[]; + ip: string; + host: string | null; + xhr: boolean; + event: APIGatewayProxyEvent; + accept: Accepts; + /** + * Check if the given `type(s)` is acceptable, returning + * the best match when true, otherwise `undefined`, in which + * case you should respond with 406 "Not Acceptable". + * + * The `type` value may be a single MIME type string + * such as "application/json", an extension name + * such as "json", a comma-delimited list such as "json, html, text/plain", + * an argument list such as `"json", "html", "text/plain"`, + * or an array `["json", "html", "text/plain"]`. When a list + * or array is given, the _best_ match, if any is returned. + * + * Examples: + * + * // Accept: text/html + * req.accepts('html'); + * // => "html" + * + * // Accept: text/*, application/json + * req.accepts('html'); + * // => "html" + * req.accepts('text/html'); + * // => "text/html" + * req.accepts('json, text'); + * // => "json" + * req.accepts('application/json'); + * // => "application/json" + * + * // Accept: text/*, application/json + * req.accepts('image/png'); + * req.accepts('png'); + * // => undefined + * + * // Accept: text/*;q=.5, application/json + * req.accepts(['html', 'json']); + * req.accepts('html', 'json'); + * req.accepts('html, json'); + * // => "json" + * + * @param {String|Array} type(s) + * @return {String|Array|Boolean} + */ + accepts(args: string | string[]): string | boolean | string[]; + /** + * Check if the given `encoding`s are accepted. + * @param {String|Array} ...encoding + * @return {String|Array} + */ + acceptsLanguages(args: string | string[]): string | string[]; + /** + * Return request header. + * + * The `Referrer` header field is special-cased, + * both `Referrer` and `Referer` are interchangeable. + * + * Examples: + * + * req.get('Content-Type'); + * // => "text/plain" + * + * req.get('content-type'); + * // => "text/plain" + * + * req.get('Something'); + * // => undefined + * + * Aliased as `req.header()`. + * + * @param {String} key + * @return {String} + */ + get(key: string): string | undefined; + + header(name: string): string | undefined; + + /** + * Check if the incoming request contains the "Content-Type" + * header field, and it contains the give mime `type`. + * + * Examples: + * + * // With Content-Type: text/html; charset=utf-8 + * req.is('html'); + * req.is('text/html'); + * req.is('text/*'); + * // => true + * + * // When Content-Type is application/json + * req.is('json'); + * req.is('application/json'); + * req.is('application/*'); + * // => true + * + * req.is('html'); + * // => false + * + * @param {String|Array} types... + * @return {String|false|null} + */ + is(types: string | string[]): string | boolean | null; +} diff --git a/src/response.d.ts b/src/response.d.ts new file mode 100644 index 0000000..81adf57 --- /dev/null +++ b/src/response.d.ts @@ -0,0 +1,102 @@ +import { Request } from "./request"; +import { APIGatewayProxyCallback, APIGatewayProxyResult } from 'aws-lambda'; + +export class Response { + /** + * Response object constructor + * + * @param {Request} req Request object for this Response + * @param {APIGatewayProxyCallback} callback AWS Lambda callback function + */ + constructor(req: Request, callback: APIGatewayProxyCallback); + req: Request; + callback: APIGatewayProxyCallback; + responseObj: APIGatewayProxyResult; + /** + * Ends the response process. + */ + end: () => void; + /** + * Get response header value for given key + * @param {string} key Header key to get + * @return {string} + */ + get: (key: string) => string; + /** + * Performs content-negotiation on the Accept HTTP header + * on the request object, when present. It uses `req.accepts()` + * to select a handler for the request, based on the acceptable + * types ordered by their quality values. If the header is not + * specified, the first callback is invoked. When no match is + * found, the server responds with 406 “Not Acceptable”, or invokes + * the `default` callback. + * + * The `Content-Type` response header is set when a callback is + * selected. However, you may alter this within the callback using + * methods such as `res.set()` or `res.type()`. + * + * The following example would respond with `{ "message": "hey" }` + * when the `Accept` header field is set to “application/json” + * or “*\/json” (however if it is “*\/*”, then the response will + * be “hey”). + * + * res.format({ + * 'text/plain': function(){ + * res.send('hey'); + * }, + * + * 'text/html': function(){ + * res.send('

hey

'); + * }, + * + * 'appliation/json': function(){ + * res.send({ message: 'hey' }); + * } + * }); + * + * By default it passes an `Error` + * with a `.status` of 406 to `next(err)` + * if a match is not made. If you provide + * a `.default` callback it will be invoked + * instead. + * + * @param {Object} obj + * @return {Response} for chaining + */ + format: (obj: Object) => Response; + /** + * Sends a JSON response. This method sends a response (with the correct content-type) that is the parameter converted to a JSON string using JSON.stringify(). + * + * The parameter can be any JSON type, including object, array, string, Boolean, number, or null, and you can also use it to convert other values to JSON. + * + * ```js + * res.json(null) + * res.json({ user: 'tobi' }) + * res.status(500).json({ error: 'message' }) + * ``` + * @param {Object} body Any type of oject + */ + json: (body: Object) => void; + /** + * Sends the HTTP response. + * @param {Object} body + */ + send: (body: Object) => void; + /** + * Set response header + * @param {string} key Header key + * @param {string} value Header value + */ + set: (key: string, value: string) => Response; + /** + * Set status code for response + * @param {number} status Status code. Ex: 200, 201, 400, 404, 500 etc. + */ + status: (status: number) => Response; + /** + * Sets the Content-Type HTTP header + * + * @param {string} type Mime type will be set as Content-Type response header + */ + type: (type: string) => Response; +}