{"id":21410164,"url":"https://github.com/rune/aileron","last_synced_at":"2025-07-14T02:30:51.208Z","repository":{"id":47069837,"uuid":"78137919","full_name":"rune/aileron","owner":"rune","description":"Functional Rest API framework for Connect / Express","archived":false,"fork":false,"pushed_at":"2022-12-06T15:26:24.000Z","size":206,"stargazers_count":2,"open_issues_count":5,"forks_count":2,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-07-03T22:36:06.947Z","etag":null,"topics":["connectjs","middleware","nodejs","router"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rune.png","metadata":{"files":{"readme":"readMe.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-01-05T18:32:12.000Z","updated_at":"2021-09-14T21:42:01.000Z","dependencies_parsed_at":"2023-01-24T01:45:50.531Z","dependency_job_id":null,"html_url":"https://github.com/rune/aileron","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/rune/aileron","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rune%2Faileron","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rune%2Faileron/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rune%2Faileron/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rune%2Faileron/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rune","download_url":"https://codeload.github.com/rune/aileron/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rune%2Faileron/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265233753,"owners_count":23731825,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["connectjs","middleware","nodejs","router"],"created_at":"2024-11-22T17:38:01.678Z","updated_at":"2025-07-14T02:30:50.854Z","avatar_url":"https://github.com/rune.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Aileron\n\n[![Build Status](https://travis-ci.org/rune/aileron.svg?branch=master)](https://travis-ci.org/rune/aileron.svg?branch=master)\n\nAileron simplifies an API server to these steps:\n\n- The connect server maps `URL pattern` strings to `handler` functions.\n- If the `handler` returns a value (typically a JSON object), this is sent as a 200 response.\n- If the `handler` throws an error, this is sent as a 500 response.\n\nAdditional features:\n\n- `URL pattern` strings support `:wildcards`, which are useful for specifying IDs in the URL string for example.\n- You can specify different `handler` functions for different request methods (GET, POST, PUT, PATCH, DELETE).\n- You can customize the centralized `successHandler` and `errHandler` functions to perform tasks like logging, specifying different status codes etc.\n- You can specify type definitions for `inputs` to APIs. Aileron will check requests and reject incorrect inputs with a 409 response. This response can also be customized through a centralized `badInputHandler` function.\n\nMiddlewares:\n\n- For tasks like authentication, we require a way to create a \"gatekeeper\" functions, that allow only some requests through.\n- For this, aileron allows you to define a `middleware`.\n- Middleware are different from normal routes in two ways:\n  - You can use `middleware` when you only want to match against the beginning of the URL, rather than exact matches.\n  - When a middleware `handler` function returns, we don't send a response, we call `next()`, sending the request forward along the connect server chain.\n\n## Typical Use\n\n```javascript\nconst connect = require(\"connect\")\nconst aileron = require(\"aileron\")\n\nconst { router, middleware } = aileron()\n\nconst teamDetails = {\n  get: {\n    errMsg: \"Unable to retrieve team details\"\n    handler: async (req, data) =\u003e {\n      const teamDetails = await getTeamDetails(data.teamId)\n      return { id: data.teamId, teamDetails }\n    }\n  },\n  put: {\n    errMsg: \"Unable to update team details\"\n    handler: async (req, data) =\u003e {\n      const result = await updateTeamDetails(data.teamId, data.teamList)\n      return result\n    }\n  }\n}\n\nconst authMiddleware = {\n  errMsg: \"Unauthorized request\",\n  handler: (req, data) =\u003e {\n    const isAuthorized = await authorize(req)\n  }\n}\n\nlet app = connect()\n\napp\n  .use(middleware(\"/api/:apiVersion\"), authMiddleware)\n  .use(router(\"/api/:apiVersion/team/:teamId\", teamDetails))\n```\n\n## Router\n\n```javascript\nrouter(urlFormat, routeConfig)\n```\n\n- `urlFormat` is a string URL, where you can have `:wildcard` placeholders by prefixing a `:`\n  ```javascript\n  // urlFormatExample\n  \"/api/:apiVersion/authenticate\"\n  ```\n- `routeConfig` is an object containing a handler for each supported request method.\n  ```javascript\n  // route config example\n  const routeConfig = {\n    post: // Request method\n      {\n        inputs: // Input type definitions,\n        errMsg: // Error message string,\n        handler: (req, data) =\u003e {\n          // Function that returns a value.\n          // Returned value is passed to the successHandler which sends a response\n          // If an err is thrown, it is passed errHandler which sends a response\n        }\n      }\n  }\n  ```\n- Each handler receives `(req, data)`\n- If the URL exactly matches the `urlFormat`, the handler for the corresponding `req.method` is called.\n- If the matching fails, `next()` is called.\n- Each route allows you to specify the `inputs` it receives and their types. If inputs are missing / incorrect, aileron will automatically invoke `badInputHandler` with a detailed error object. For advanced input validation, see the `Input Checking` section.\n- Each handler function is passed a `data` parameter. This will contain the wildcard values and the parsed inputs, ready for use.\n\nFor example:\n\n```javascript\nconst loginApi = {\n  post: {\n    inputs: { username: \"String\", password: \"String\" },\n    errMsg: \"Unable to login. Please try again!\",\n    handler: async (req, data) =\u003e {\n      const userDetails = await loginUser(data.username, data.password, data.apiVersion)\n      return {message: \"Login successful\", userDetails}\n    }\n  }\n}\n\nlet app = connect()\n\napp\n  // Other routes and middleware\n  .use(...)\n  .use(...)\n  // The team route\n  .use(router(\"/api/:apiVersion/team/:teamId\", teamApi))\n  // Other routes and middleware\n  .use(...)\n  .use(...)\n```\n\n- Note that the URL format that you provide decides the key (`apiVersion`) under which the variable is made available to the handler function.\n\n## Middleware\n\n```javascript\nmiddleware(urlFormat, routeConfig)\n```\n\nVery similar to router, so we only explain the differences:\n\n- If the beginning of the URL matches the provided `urlFormat`, the middleware function is called.\n- If the `handler` function returns, `next()` is called.\n- If the `handler` function throws, the `errHandler` is called.\n\nFor example:\n\n```javascript\nconst printRequestInfo = (req, data) =\u003e {\n  console.log(req.method, req.url, data.apiVersion)\n}\n\nlet app = connect()\n\napp\n  .use(middleware(\"/api/:apiVersion\", printVersionNumber))\n  // other middleware / routes follow\n  .use(...)\n  .use(...)\n```\n\n- Note that the URL format that you provide decides the key (`apiVersion`) under which the variable is made available to the middleware function.\n\n### Input checking\n\n- As mentioned above, aileron supports input checking by simply configuring an \"inputs\" object and an error message.\n- Aileron uses the [type-check](https://www.npmjs.com/package/type-check) library to validate inputs. Check the library docs for a list of valid type definitions.\n- For advanced input checking, aileron allows you to define an `inputCheck` function. This function receives all the parsed inputs specified in your `inputs` object. Simply throw an error inside this function and `badInputHandler` will be called with the thrown error.\n- For optional inputs, you can use `?` to specify they're optional. `{age: \"Number | Undefined\"}` can be written as `{age: \"Number?\"}`\n\n```javascript\nconst inputCheckingController = {\n  post: {\n    inputs: { name: \"String\", age: \"Number\" },\n    inputCheck: parsedInputs =\u003e {\n      // Custom check to disallow the name \"Jon Snow\"\n      if (parsedInputs.name === \"Jon Snow\") {\n        throw \"You know nothing, Jon Snow\"\n      }\n    },\n    errMsg: \"Unable to process your request.\",\n    handler: (req, res, next, data) =\u003e {\n      const { name, age } = data\n      res.ok().json({ name, age })\n    }\n  }\n}\n```\n\n## Error handling\n\n- Aileron automatically wraps all your middlewares / handlers in a try-catch block and sends an error response if an uncaught error occurs.\n- This prevents your node server from crashing :)\n- Aileron allows you customize these error handlers.\n- You can supply an `errHandler` and a `badInputHandler` when you initialize Aileron.\n- Here is an example:\n\n```javascript\n// MyCoolProject\nconst { router, middleware } = aileron({\n  badInputHandler: (req, res, err, errMsg) =\u003e\n    res.forbidden().json({ err, message: \"Bad Input: \" + errMsg }),\n  errHandler: (req, res, err, errMsg) =\u003e\n    res.error().json({ err, message: \"Uncaught error!!\" })\n})\n```\n\n## Strict Mode\n\n- Aileron allows a strict mode, where it will force you to provide `inputs` and `errMsg` for all handlers.\n- Strict mode will also complain if you have not supplied custom error handlers.\n- This ensures that error handling code is always supplied for every API in your project.\n- To enable strict mode, simply supply it as an option when you initialize aileron.\n\n```javascript\n// MyCoolProject\nconst { router, middleware } = aileron({\n  strict: true,\n  badInputHandler: (req, res, err, errMsg) =\u003e\n    res.forbidden().json({ err, message: \"Bad Input: \" + errMsg }),\n  errHandler: (req, res, err, errMsg) =\u003e\n    res.error().json({ err, message: \"Uncaught error!!\" })\n})\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frune%2Faileron","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frune%2Faileron","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frune%2Faileron/lists"}