diff --git a/docs/advance/helpers.md b/docs/advance/helpers.md index 650de82..ae4e16c 100644 --- a/docs/advance/helpers.md +++ b/docs/advance/helpers.md @@ -169,6 +169,16 @@ const validFields = [ enumValues: ["abc", "def", "xyz"], required: true, }, + { key: "someFunc", type: "function", required: true }, + { key: "someJson", type: "json", required: true }, + { key: "someObjectCollection", type: "object", required: true, isCollection: true }, + { + key: "someEnumCollection", + type: "enum", + enumValues: ["abc", "def", "xyz"], + required: true, + isCollection: true + }, ]; const toValidate1 = { @@ -182,6 +192,10 @@ const toValidate1 = { someEmail: "email@mail.com", someArray: ["aaa", "bbb", "ccc"], someEnum: "def", + someFunc: () => 'bar', + someJson: "{\"foo\":\"bar\",\"isTest\":1}", + someObjectCollection: [{ "foo": "bar", "isTest": 1 }, [{ "another": "object" }], + someEnumCollection: ["def", "abc", "abc"], }; const validated = validateFields(toValidate1, validFields)); @@ -198,6 +212,10 @@ const validated = validateFields(toValidate1, validFields)); someEmail: "email@mail.com", someArray: ["aaa", "bbb", "ccc"], someEnum: "def", + someFunc: () => 'bar', + someJson: "{\"foo\":\"bar\",\"isTest\":1}", + someObjectCollection: [{ "foo": "bar", "isTest": 1 }, [{ "another": "object" }], + someEnumCollection: ["def", "abc", "abc"], } */ ``` diff --git a/docs/basics/middleware.md b/docs/basics/middleware.md deleted file mode 100644 index 0450265..0000000 --- a/docs/basics/middleware.md +++ /dev/null @@ -1,133 +0,0 @@ -# Middleware - -Middlewares can be executed before or after a request, usually handled by the handlers. This will be useful for cases where an action is required prior to reaching the handler, or when an action is required to execute prior to the returning of the response. - -Middlewares require [Middy npm](https://www.npmjs.com/package/middy) to work. - -Middlewares should be written in the `src/middlewares/` directory. - -## Available Middlewares - -Lesgo! comes with 3 pre-existing middlewares. - -You may also import other ready-made middlewares from the [Middy repository](https://www.npmjs.com/package/middy#available-middlewares). - -### Http - -This middleware normalizes all HTTP requests, handles, and formats success and error responses, and should be used for all HTTP endpoints. Will also provide any or both JSON body and url querystring parameters into a single `event.input`. This middleware will also populate with `event.auth.sub` when JWT is used and presented with the `Authorization` header. - -**Usage** - -```js -import middy from '@middy/core'; -import httpMiddleware from "Middlewares/httpMiddleware"; - -const originalHandler = event => { - return event.input; -}; - -export const handler = middy(originalHandler); - -handler.use(httpMiddleware()); -``` - -#### Success Response - -The successfuly response will be formatted in this way -```json -{ - "status": "success", - "data": {}, - "_meta": {} -} -``` - -#### Error Response - -The successfuly response will be formatted in this way -```json -{ - "status": "error", - "data": null, - "error": { - "code": "Core/users/getUser::USER_NOT_EXIST", - "message": "UserException: User does not exist", - "details": { - "err": { - "name": "UserException", - "message": "User not found", - "statusCode": 404, - "code": "Core/users/getUser::USER_NOT_EXIST", - "extra": {} - } - } - }, - "_meta": {} -} -``` - -### Normalize SQS Message - -This middleware will normalize records coming from sqs message event. The `Records` object in the `handler.event` will be normalized into `handler.event.collection`. This middleware executes _before_ the handler is called. - -**Usage** - -```js -import middy from '@middy/core'; -import normalizeSQSMessage from "Middlewares/normalizeSQSMessage"; - -const originalHandler = event => { - return event.collection; -}; - -export const handler = middy(originalHandler); - -handler.use(normalizeSQSMessage()); -``` - -### Verify JWT - -This middleware will verify any JWT passed to the `Authorization` header of the http request. The decoded JWT can be accesed through `handler.event.decodedJwt`. If the JWT is verified, `handler.event.auth.sub` is set to the JWT's sub, else a `403` response will be thrown. - -**Configuration** - -The JWT configuration for your application is located at `src/config/jwt.js`. Or copy [this file](https://raw.githubusercontent.com/reflex-media/lesgo/master/src/config/jwt.js) to that path. - -You may also simply update the respective environment files in `config/environments/*` as such: - -```apache -# SHA256 JWT secret key, used to verify the token passed to "Authorization" header -JWT_SECRET="" - -# Leave empty if you don't want the issuer to be validated -JWT_ISS_SHOULD_VALIDATE= - -# Comma-separated list of domains to validate -JWT_ISS_DOMAINS="" - -# Leave empty if you don't want the custom claims to be validated -JWT_CUSTOM_CLAIMS_SHOULD_VALIDATE= - -# List of custom claims to valdiate. -# Visit https://auth0.com/docs/tokens/jwt-claims for more info -JWT_CUSTOM_CLAIMS_DATA="" -``` - -**Usage** - -```js -import middy from '@middy/core'; -import verifyJwtTokenMiddleware from "Middlewares/verifyJwtTokenMiddleware"; - -const originalHandler = event => { - return event.collection; -}; - -export const handler = middy(originalHandler); - -handler.use(verifyJwtTokenMiddleware()); -``` - -## Custom Middlewares - -You can write your own custom middleware with [Middy](https://www.npmjs.com/package/middy#writing-a-middleware). diff --git a/docs/basics/middlewares/auth.md b/docs/basics/middlewares/auth.md new file mode 100644 index 0000000..fc2c7aa --- /dev/null +++ b/docs/basics/middlewares/auth.md @@ -0,0 +1,105 @@ +These middlewares can be utilized as a layer of authentication before going through your HTTP requests. + +## Verify JWT + +This middleware will verify any JWT passed to the `Authorization` header of the http request. If the JWT is verified, the decoded JWT can be accesed through `handler.event.decodedJwt`, else a `403` response will be thrown. + +**Configuration** + +The JWT configuration for your application is located at `src/config/jwt.js`. Or copy [this file](https://raw.githubusercontent.com/reflex-media/lesgo/master/src/config/jwt.js) to that path. + +You may also simply update the respective environment files in `config/environments/*` as such: + +```apache +# SHA256 JWT secret key, used to verify the token passed to "Authorization" header +JWT_SECRET="" + +# Leave empty if you don't want the issuer to be validated +JWT_ISS_SHOULD_VALIDATE= + +# Comma-separated list of domains to validate +JWT_ISS_DOMAINS="" + +# Leave empty if you don't want the custom claims to be validated +JWT_CUSTOM_CLAIMS_SHOULD_VALIDATE= + +# List of custom claims to valdiate. +# Visit https://auth0.com/docs/tokens/jwt-claims for more info +JWT_CUSTOM_CLAIMS_DATA="" +``` + +**Usage** + +```js +import middy from '@middy/core'; +import verifyJwtTokenMiddleware from "Middlewares/verifyJwtTokenMiddleware"; + +const originalHandler = event => { + return event.collection; +}; + +export const handler = middy(originalHandler); + +handler.use(verifyJwtTokenMiddleware()); +``` + +## Basic Auth + +This middleware will verify any basic auth passed to the `Authorization` header of the http request. Throws `Middlewares/basicAuthMiddleware::AUTH_INVALID_CLIENT_OR_SECRET_KEY` when a basic auth cannot be found in the clients list configuration. + +This middleware can be used together with `clientAuthMiddleware`, as long as `clientAuthMiddleware` is declared first. +This is to allow the middleware to identify the matched `handler.event.platform`. + +**Configuration** + +The basic auth configuration for your application is located at `src/config/client.js`. Or copy [this file](https://raw.githubusercontent.com/reflex-media/lesgo/master/src/config/client.js) to that path. + +**Usage** + +```js +import middy from '@middy/core'; +import basicAuthMiddleware from "Middlewares/basicAuthMiddleware"; + +const originalHandler = event => { + return event.collection; +}; + +export const handler = middy(originalHandler); + +handler.use(basicAuthMiddleware()); + +// or + +handler.use(basicAuthMiddleware({ + // This is set as an override for Config/client.js when needed + client: { + myApp: { + key: 'myappkeystring', + secret: 'myappsecretstring' + } + } +})); +``` + +## Client Auth + +This middleware will verify key passed to `x-client-id` header of the http request and sets the matched key to `handler.event.platform`. Throws `Middlewares/clientAuthMiddleware::INVALID_CLIENT_ID` when a basic auth cannot be found in the clients list configuration. + +**Configuration** + +The basic auth configuration for your application is located at `src/config/client.js`. Or copy [this file](https://raw.githubusercontent.com/reflex-media/lesgo/master/src/config/client.js) to that path. + +**Usage** + +```js +import middy from '@middy/core'; +import clientAuthMiddleware from "Middlewares/clientAuthMiddleware"; + +const originalHandler = event => { + return event.collection; +}; + +export const handler = middy(originalHandler); + +handler.use(clientAuthMiddleware()); +``` \ No newline at end of file diff --git a/docs/basics/middlewares/event-parsing.md b/docs/basics/middlewares/event-parsing.md new file mode 100644 index 0000000..8f3cb03 --- /dev/null +++ b/docs/basics/middlewares/event-parsing.md @@ -0,0 +1,20 @@ +These middlewares can be utilized for parsing data from specific services such as AWS Services, and just instead directly accessing it from a single list of recors inside `handler.event.collection`. + +## Normalize SQS Message + +This middleware will normalize records coming from sqs message event. The `Records` object in the `handler.event` will be normalized into `handler.event.collection`. This middleware executes _before_ the handler is called. + +**Usage** + +```js +import middy from '@middy/core'; +import normalizeSQSMessage from "Middlewares/normalizeSQSMessage"; + +const originalHandler = event => { + return event.collection; +}; + +export const handler = middy(originalHandler); + +handler.use(normalizeSQSMessage()); +``` \ No newline at end of file diff --git a/docs/basics/middlewares/http.md b/docs/basics/middlewares/http.md new file mode 100644 index 0000000..672b9fa --- /dev/null +++ b/docs/basics/middlewares/http.md @@ -0,0 +1,129 @@ +These middlewares can be utilized to parse HTTP requests and output HTTP in different specific formats. + +## Http + +This middleware normalizes all HTTP requests, handles, and formats success and error responses, and should be used for all HTTP endpoints. Will also provide any or both JSON body and url querystring parameters into a single `event.input`. This middleware will also populate with `event.auth.sub` when JWT is used and presented with the `Authorization` header. + +**Usage** + +```js +import middy from '@middy/core'; +import httpMiddleware from "Middlewares/httpMiddleware"; + +const originalHandler = event => { + return event.input; +}; + +export const handler = middy(originalHandler); + +handler.use(httpMiddleware()); +``` + +#### Success Response + +The successfuly response will be formatted in this way +```json +{ + "status": "success", + "data": {}, + "_meta": {} +} +``` + +#### Error Response + +The successfuly response will be formatted in this way +```json +{ + "status": "error", + "data": null, + "error": { + "code": "Core/users/getUser::USER_NOT_EXIST", + "message": "UserException: User does not exist", + "details": { + "err": { + "name": "UserException", + "message": "User not found", + "statusCode": 404, + "code": "Core/users/getUser::USER_NOT_EXIST", + "extra": {} + } + } + }, + "_meta": {} +} +``` + +#### Custom Response + +Or you can override the response by passing a function +```js +handler.use(httpMiddleware({ + formatError: (options) => { + return JSON.stringify({ + status: 'error', + data: null, + error: { + code: options.error.code || 'UNHANDLED_ERROR', + message: options.error.name + ? `${options.error.name}: ${options.error.message}` + : options.error.message || options.error, + details: options.error.extra || '', + }, + _meta: options.debugMode ? options.event : {}, + }); + }, + formatSuccess: (options) => { + return JSON.stringify({ + status: 'success', + data: options.response, + _meta: options.debugMode ? options.event : {}, + }) + } +})); +``` + +## Http No Output + +This middleware normalizes all HTTP requests, handles, and formats success and error responses to make sure it always returns a success 200 with no body. + +**Usage** + +```js +import middy from '@middy/core'; +import httpNoOutputMiddleware from "Middlewares/httpNoOutputMiddleware"; + +const originalHandler = event => { + return event.input; +}; + +export const handler = middy(originalHandler); + +handler.use(httpNoOutputMiddleware()); +``` + +**Enabling Output** + +By default, a response will be returned when debug is turned on either by passing `debug=1` as a query parameter such as: + +``` +http://my.api.com/v1/upload?debug=1 +``` + +or by passing `debugMode` as an option such as: + +```js +handler.use(httpNoOutputMiddleware({ + debugMode: true +})); +``` + +But this can be overriden by passing `allowResponse` as an option + +```js +handler.use(httpNoOutputMiddleware({ + allowResponse: (options) => { + return false; + } +})); +``` \ No newline at end of file diff --git a/docs/basics/middlewares/introduction.md b/docs/basics/middlewares/introduction.md new file mode 100644 index 0000000..6d43574 --- /dev/null +++ b/docs/basics/middlewares/introduction.md @@ -0,0 +1,21 @@ +# Middlewares + +Middlewares can be executed before or after a request, usually handled by the handlers. This will be useful for cases where an action is required prior to reaching the handler, or when an action is required to execute prior to the returning of the response. + +Middlewares require [Middy npm](https://www.npmjs.com/package/middy) to work. + +Middlewares should be written in the `src/middlewares/` directory. + +## Available Middlewares + +Lesgo! comes with pre-existing middlewares. + +- [HTTP Middlewares](/lesgo-docs/basics/middlewares/http) +- [Event Parsing Middlewares](/lesgo-docs/basics/middlewares/event-parsing) +- [Auth Middlewares](/lesgo-docs/basics/middlewares/auth) + +You may also import other ready-made middlewares from the [Middy repository](https://www.npmjs.com/package/middy#available-middlewares). + +## Custom Middlewares + +You can write your own custom middleware with [Middy](https://www.npmjs.com/package/middy#writing-a-middleware). diff --git a/mkdocs.yml b/mkdocs.yml index 3c9efeb..ed3e110 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -53,7 +53,11 @@ nav: - Deployment: getting-started/deployment.md - Available Scripts: getting-started/available-scripts.md - The Basics: - - Middleware: basics/middleware.md + - Middlewares: + - Introduction: basics/middlewares/introduction.md + - HTTP Middlewares: basics/middlewares/http.md + - Event Parsing Middlewares: basics/middlewares/event-parsing.md + - Auth Middlewares: basics/middlewares/auth.md - Error Handling: basics/error-handling.md - Logging: basics/logging.md - Digging Deeper: