{"id":23593230,"url":"https://github.com/ggondim/azure-monofunction","last_synced_at":"2025-11-04T10:30:44.445Z","repository":{"id":82112292,"uuid":"271922389","full_name":"ggondim/azure-monofunction","owner":"ggondim","description":"A router for Single-Function APIs in ⚡ Azure Functions.","archived":false,"fork":false,"pushed_at":"2020-06-30T19:27:03.000Z","size":28,"stargazers_count":0,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-03-15T10:07:45.958Z","etag":null,"topics":["api","azure-functions","middlewares","monolith","router","serverless"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/azure-monofunction","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ggondim.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-06-13T01:52:42.000Z","updated_at":"2020-06-30T19:27:01.000Z","dependencies_parsed_at":null,"dependency_job_id":"a8a5dea8-84e6-478e-b84a-8199dc2bf862","html_url":"https://github.com/ggondim/azure-monofunction","commit_stats":{"total_commits":4,"total_committers":1,"mean_commits":4.0,"dds":0.0,"last_synced_commit":"e76841593c8cf2ac43df91d9369bb47a2138e186"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ggondim%2Fazure-monofunction","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ggondim%2Fazure-monofunction/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ggondim%2Fazure-monofunction/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ggondim%2Fazure-monofunction/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ggondim","download_url":"https://codeload.github.com/ggondim/azure-monofunction/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239432765,"owners_count":19637799,"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":["api","azure-functions","middlewares","monolith","router","serverless"],"created_at":"2024-12-27T08:18:33.178Z","updated_at":"2025-11-04T10:30:44.381Z","avatar_url":"https://github.com/ggondim.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003e\n  \u003cbr\u003e\n  ⛈ Azure Monofunction\n  \u003cbr\u003e\n\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003eA router for Single-Function APIs in ⚡ Azure Functions.\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://img.shields.io/npm/v/azure-monofunction\" /\u003e\n  \u003cimg src=\"https://img.shields.io/bundlephobia/min/azure-monofunction\" /\u003e\n  \u003cimg src=\"https://img.shields.io/github/last-commit/ggondim/azure-monofunction\" /\u003e\n\u003c/p\u003e\n\n\u003e Azure Monofunction is a router for Single-Function APIs (SFA) that makes possible for you to develop monolithic APIs and still use the power of serverless, like cost-per-consumption and automatic scalability. \n\nSee all [features](#features).\n\n## Table of contents\n\n\u003cul\u003e\n  \u003cli\u003e\n    \u003cdetails\u003e\n      \u003csummary\u003e\u003ca href=\"#Installation\"\u003eInstallation\u003c/a\u003e\u003c/summary\u003e\n      \u003cul\u003e\n        \u003cli\u003e\u003ca href=\"#Requirements\"\u003eRequirements\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003ca href=\"#Installing\"\u003eInstalling\u003c/a\u003e\u003c/li\u003e\n      \u003c/ul\u003e\n    \u003c/details\u003e\n  \u003c/li\u003e\n  \u003cli\u003e\n    \u003cdetails\u003e\n      \u003csummary\u003e\u003ca href=\"#Usage\"\u003eUsage\u003c/a\u003e\u003c/summary\u003e\n      \u003cul\u003e\n        \u003cli\u003e\u003ca href=\"#TLDR\"\u003eTL;DR - The most simple usage\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003ca href=\"#example\"\u003eAn example title\u003c/a\u003e\u003c/li\u003e\n      \u003c/ul\u003e\n    \u003c/details\u003e\n  \u003c/li\u003e\n  \u003cli\u003e\n    \u003cdetails\u003e\n      \u003csummary\u003e\u003ca href=\"#Extending\"\u003eExtending\u003c/a\u003e\u003c/summary\u003e\n      \u003cul\u003e\n        \u003cli\u003e\u003ca href=\"#example\"\u003eAn example title\u003c/a\u003e\u003c/li\u003e\n      \u003c/ul\u003e\n    \u003c/details\u003e\n  \u003c/li\u003e\n  \u003cli\u003e\n    \u003cdetails\u003e\n      \u003csummary\u003e\u003ca href=\"#Help\"\u003eHelp\u003c/a\u003e\u003c/summary\u003e\n      \u003cul\u003e\n        \u003cli\u003e\u003ca href=\"#FAQ\"\u003eFAQ\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003ca href=\"#Support\"\u003eSupport\u003c/a\u003e\u003c/li\u003e\n      \u003c/ul\u003e\n    \u003c/details\u003e\n  \u003c/li\u003e\n  \u003cli\u003e\n    \u003cdetails\u003e\n      \u003csummary\u003e\u003ca href=\"#API\"\u003eAPI\u003c/a\u003e\u003c/summary\u003e\n      \u003cul\u003e\n        \u003cli\u003e\u003ca href=\"#example\"\u003eAn example title\u003c/a\u003e\u003c/li\u003e\n      \u003c/ul\u003e\n    \u003c/details\u003e\n  \u003c/li\u003e\n  \u003cli\u003e\n    \u003cdetails\u003e\n      \u003csummary\u003e\u003ca href=\"#Tecnhical-concepts\"\u003eTechnical concepts\u003c/a\u003e\u003c/summary\u003e\n      \u003cul\u003e\n        \u003cli\u003e\u003ca href=\"#Motivation-and-design\"\u003eMotivation and design\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003ca href=\"#Features\"\u003eFeatures\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003ca href=\"#Related-projects\"\u003eRelated projects\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003ca href=\"#Similar-projects\"\u003eSimilar projects\u003c/a\u003e\u003c/li\u003e\n      \u003c/ul\u003e\n    \u003c/details\u003e\n  \u003c/li\u003e\n  \u003cli\u003e\n    \u003cdetails\u003e\n      \u003csummary\u003e\u003ca href=\"#Contributing\"\u003eContributing\u003c/a\u003e\u003c/summary\u003e\n      \u003cul\u003e\n        \u003cli\u003e\u003ca href=\"#If-you-don-t-want-to-code\"\u003eIf you don't want to code\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003ca href=\"#If-you-want-to-code\"\u003eIf you want to code\u003c/a\u003e\u003c/li\u003e\n      \u003c/ul\u003e\n    \u003c/details\u003e\n  \u003c/li\u003e\n  \u003cli\u003e\n    \u003cdetails\u003e\n      \u003csummary\u003e\u003ca href=\"#Hall-of-fame\"\u003eHall of fame\u003c/a\u003e\u003c/summary\u003e\n      \u003cul\u003e\n        \u003cli\u003e\u003ca href=\"#who-is-using\"\u003eWho is using\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003ca href=\"#Contributors\"\u003eContributors\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003ca href=\"#Backers\"\u003eBackers\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003ca href=\"#Sponsors\"\u003eSponsors\u003c/a\u003e\u003c/li\u003e\n      \u003c/ul\u003e\n    \u003c/details\u003e\n  \u003c/li\u003e\n  \u003cli\u003e\u003ca href=\"#License\"\u003eLicense\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\n---\n\n## Installation\n\n### Requirements\n\n![](https://img.shields.io/static/v1?label=npm\u0026message=6.14.5\u0026color=brightgreen) ![](https://img.shields.io/static/v1?label=node\u0026message=12.16.3\u0026color=brightgreen) ![](https://img.shields.io/static/v1?label=os\u0026message=ubuntu-20.04\u0026color=blueviolet) ![](https://img.shields.io/static/v1?label=platforms\u0026message=Azure%20Functions%20Host\u0026color=777) \n\nAzure Monofunction was tested for the environments below. Even we believe it may works in older versions or other platforms, **it is not intended to**.\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003cb\u003eSee tested environments\u003c/b\u003e\u003c/summary\u003e\n\n| Environment  |  Tested version  |\n| ------------------- | ------------------- |\n|  OS |  Ubuntu 20.04 |\n|  Node.js |  12.16.3 |\n|  Package Manager |  npm 6.14.5 |\n|  Platforms |  Azure Functions Host v2 and v3 |\n\n\u003c/details\u003e\n\n### Installing\n\n#### Via package manager\n\n![](https://nodei.co/npm/azure-monofunction.png?downloads=true\u0026downloadRank=true\u0026stars=true)\n\n```shell\n$ npm install --save azure-monofunction\n```\n\n#### Configuring the single function\n\n1. Create a HTTP trigger in you function app. It can have any name, like \"monofunction\".\n\n2. Change the `route` property for the trigger binding in `function.json` to a wildcard, like `{*segments}`. You can copy the [function.json template](templates/function.json).\n\n3. Create the function `index.js` at the function folder and start develop following the basic usage below.\n\n\u003cbr/\u003e\n\n\u003cp align=\"right\"\u003e\u003ca href=\"#Table-of-contents\"\u003e↟ Back to top\u003c/a\u003e\u003c/p\u003e\n\n---\n\n## Usage\n\n![](https://img.shields.io/static/v1?label=modules\u0026message=CommonJS\u0026color=yellow) \n![](https://img.shields.io/static/v1?label=javascript\u0026message=ECMA2015\u0026color=yellow) \n\n### TL;DR\n\nThe most simple usage\n\n```javascript\nconst app = require('azure-monofunction');\n\nconst routes = [{\n  path: '/example/:param',\n  methods: ['GET', 'PUT'],\n  run: async (context) =\u003e {\n    context.res.body = { it: 'works' };\n  },\n}]\n\napp.addRoutes(routes);\n\nmodule.exports = app.listen();\n```\n\nThe anatomy of a simple route is an URL `path`, its HTTP `methods` to match and some middleware to `run`.\n\nAn alternative to the `addRoutes` method that supports a list of route objects is the method `route` that adds a single route to the router.\n\n```javascript\napp.route(['GET','POST'], '/example/path', async (context) =\u003e {\n  // ...middleware logic\n});\n```\n\n### Defining route paths\n\nRoute paths must always start with `/` and be followed by valid URL paths.\n\nYou can define **dynamic parameters** prefixing a path level with `:`.\n\nFor example, the URL `/users/123` will match the route `/users/:id`.\n\nThe parameter will be available at the `context.params` object.\n\nExample:\n\n```javascript\napp.route(['GET'], '/users/:id', async (context) =\u003e {\n  const userId = context.params.id;\n});\n```\n\n### Defining the HTTP methods for a route\n\nHTTP verbs must always be defined as arrays of strings both in route objects and `route` method.\n\nThe supported HTTP verbs are: `['GET', 'POST', 'PATCH', 'PUT', 'DELETE']`.\n\nAdditionally, you can add routes with verbs corresponding methods: `get()`, `post()`, `patch()`, `put()`, `delete()`.\n\n```javascript\napp.addRoutes([{ \n  methods: ['GET', 'POST'],\n  path,\n  run,\n}]);\n\n// is the same of:\n\napp.route(['GET', 'POST'], path, run);\n\n// and the same of:\n\napp.get(path, run); // feels like Express 🙂\n```\n\n### Using middlewares for routes\n\nMiddlewares works with the power of [Azure Functions Middlewares](https://github.com/ggondim/azure-functions-middlewares) and are asynchronous functions that takes a required `context` argument and an optional `STOP_SIGNAL` argument.\n\nRequest object is available through `context.req` property and response should be set using the `context.res` property. Other [Azure Functions context properties](https://github.com/Azure/azure-functions-nodejs-worker/blob/master/types/public/Interfaces.d.ts#L18) are also available.\n\nWhen defining a middleware for a route with the `run` property/argument, you can use a single middleware function or an **array of middlewares**.\n\nExample:\n\n```javascript\nconst headerMiddleware = async (context) =\u003e {\n  context.res.headers['X-User-ID'] = context.params.id;\n  context.anything = true;\n};\n\nconst resourceMiddleware = async (context) =\u003e {\n  context.res.body = { added: context.anything };\n};\n\napp.get('/posts/:id', [headerMiddleware, resourceMiddleware]);\n\n// output of /posts request should be\n\n// HTTP 200 /posts/123\n// X-User-ID: 123\n// { \"added\": true }\n```\n\nIt is strongly recommended you read [Azure Functions Middlewares](https://github.com/ggondim/azure-functions-middlewares) docs, but, if you can't, please note:\n\n\u003e * Always use asynchronous functions as middlewares.\n\u003e * Do not return anything inside your middleware function, unless you want to throw an error.\n\u003e * You can pass values to the next middlewares using the `context` object reference.\n\u003e * Return the `STOP_SIGNAL` argument in the middleware if you need to prevent any following middleware to be executed. This is useful for Content-type negotiation or Authorization.\n\u003e * See other context-related docs in [Accessing and modifying the context](https://github.com/ggondim/azure-functions-middlewares#accessing-and-modifying-the-context) at the Azure Functions Middlewares reference.\n\u003e * [Common community middlewares](https://github.com/ggondim/azure-functions-middlewares#available-community-middlewares) are available under the Azure Functions Middlewares project.\n\n### Controller architecture\n\nUsing a single-function API leads you back to the need of middleware reusability and composition.\n\nThis monolithic approach is more maintainable than microservices approach, but requires more organization.\n\nWhen dealing with many routes and its middlewares, you certainly will fall to a controller separation pattern.\n\nControllers are often separated by resource entities or related services.\n\nIt is also good to separate your routes inside a route file for better reading.\n\nExample:\n\nFunction directory tree\n\n```\n.\n├── controllers\n│   └── user.controller.js\n├── monofunction\n│   ├── function.json\n│   ├── index.js\n│   └── routes.js\n└── host.json\n```\n\n`/controllers/user.controller.js`\n```javascript\n\nasync function getUser({ req, res, params }) {\n  context.res.body = await db.getUser(params.id);\n}\n\nasync function createUser({ req }) {\n  context.res.status = await db.createUser(req.body);\n}\n\nmodule.exports = {\n  getUser,\n  createUser,\n};\n```\n\n`/monofunction/routes.js`\n```javascript\nconst userController = require('../controllers/user.controller');\n\nmodule.exports = [{\n  path: '/users/:id',\n  methods: ['GET'],\n  run: userController.getUser,\n}, {\n  path: '/users',\n  methods: ['POST'],\n  run: userController.createUser,\n}];\n```\n\n`/monofunction/index.js`\n```javascript\nconst app = require('azure-monofunction');\nconst routes = require('./routes');\n\napp.addRoutes(routes);\n\nmodule.exports = app.listen();\n```\n\n### Capturing errors\n\nIf a middleware returns a value or throws an error, an error will also be forwarded to Azure Functions Host execution.\n\nIf you want to catch this unhandled errors, you can use the `onError` handler.\n\n```javascript\napp.onError((error, context) =\u003e {\n  // error argument contains the original value\n  // context is preserved until here\n});\n```\n\n### Global middlewares\n\nSometimes you need to run common middlewares for all the routes, regardless its resources, just like headers validation, authorization rules and content-type negotiation and parsing.\n\nYou can add middlewares for all the routes (\"global middlewares\") using the `use()` method.\n\n```javascript\napp.use(async (context) =\u003e {\n  context.res.headers['X-Powered-By'] = '⛈ Azure Monofunction';\n});\n\napp.addRoutes(routes);\n\n// now all the routes will respond with a 'X-Powered-By' header\n```\n\nYou can also add a conditional global middleware calling the `useIf()` method from [Azure Functions Middlewares](https://github.com/ggondim/azure-functions-middlewares#conditional-middlewares).\n\n```javascript\nconst isChromeAgent = (context) =\u003e {\n  return context.req.headers['User-Agent'].indexOf('Chrome') !== -1;\n}\n\napp.useIf(isChromeAgent, async (context) =\u003e {\n  context.res.headers['Content-Type'] = 'text/html';\n});\n\n// now if a route was called from Chrome browser, the response will be set to HTML COntent-Type\n```\n\nFind useful built middlewares in [Common community middlewares](https://github.com/ggondim/azure-functions-middlewares#available-community-middlewares) of Azure Functions Middlewares.\n\n### Defining a not found fallback\n\nIf no route was matched during a request, Azure Monofunction will throw a not found error.\n\nBut if you want to handle this not found event with a fallback route, you can use the `on404()` handler.\n\n```javascript\napp.on404((context) =\u003e {\n  // add your fallback logic here, like:\n  context.res.status = 404;\n});\n```\n\n### Route custom metadata\n\nYou can add custom route metadata in route object's `meta` property that will be available in `context.meta` property:\n\n```javascript\nconst routes = [{\n  path: '/route',\n  methods,\n  meta: {\n    something: 'value',\n  },\n  run: async (context) =\u003e {\n    context.res.body = context.meta;\n    // body will be { \"something\": \"value\" }\n  },\n}];\n```\n\nThis is useful when you need to recover this meta in other middlewares, specially conditional middlewares, like an authorization middleware:\n\n```javascript\nconst hasAuth = (context) =\u003e context.meta \u0026\u0026 context.meta.auth;\napp.useIf(hasAuth, async (context, STOP_SIGNAL) =\u003e {\n  if (!context.req.headers.Authorization) {\n    context.res.status = 401;\n    return STOP_SIGNAL;\n  }\n});\n\napp.addRoutes([{\n  path: '/resource',\n  methods: ['POST'],\n  meta: {\n    auth: true\n  },\n  run,\n}, {\n  path: '/resource',\n  methods: ['GET'],\n  run,\n}]);\n\n// POST /resource without an Authorization header will return HTTP 401\n// but GET /resource will not\n```\n\n### Debugging and customizing logger\n\nYou can log everything that is done by Azure Monofunction setting the `debug` property to `true`.\n\n```javascript\napp.debug = true;\n```\n\nYou can also use a different logger than console/context setting it in the `logger` property.\n\n```javascript\napp.logger = MyCustomLogger;\n```\n\n\u003e ℹ Note that your logger need to have a `log(message, ...args)` method.\n\n### Route prefix\n\nAzure Functions Host has a route prefix for all the requests. This defaults to `/api` but you can customize it in `host.json`:\n\n```json\n{\n  \"extensions\": {\n    \"http\": {\n      \"routePrefix\": \"api\",\n    }\n  }\n}\n```\n\nIf you customize the route prefix, Azure Monofunction will try to guess it from `extensions.http.routePrefix` configuration defined in `host.json` file.\n\nIf in a parallel universe you did not defined the route prefix in `host.json` but your function app has a route prefix different than `/api`, you need to specify that in the Azure Monofunction's `routePrefix` property.\n\n```javascript\napp.routePrefix = '/notapi';\n```\n\nMake sure if you need to change it you did this changing **before adding any route**.\n\n\u003cbr/\u003e\n\n\u003cp align=\"right\"\u003e\u003ca href=\"#Table-of-contents\"\u003e↟ Back to top\u003c/a\u003e\u003c/p\u003e\n\n---\n\n## Extending\n\nAzure Monofunction is not intended to be extensible, but the middleware approach is extensible itself.\n\nIf you want to publish a middleware (or an evaluation function) you developed and think it will be useful for any other developer, see [Writing and publishing common middlewares](https://github.com/ggondim/azure-functions-middlewares#writing-and-publishing-common-middlewares) in Azure Functions Middlwares.\n\n\u003cbr/\u003e\n\n\u003cp align=\"right\"\u003e\u003ca href=\"#Table-of-contents\"\u003e↟ Back to top\u003c/a\u003e\u003c/p\u003e\n\n---\n\n## Help\n\n\u003c!-- ### FAQ\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003cb\u003e1. First question?\u003c/b\u003e\u003c/summary\u003e\n\nAnswer here\n\n\u003c/details\u003e --\u003e\n\n### Support\n\n![](https://img.shields.io/github/issues/ggondim/azure-monofunction)\n\nIf you need help or have a problem with this project and you not found you problem in FAQ above, [start an issue](https://github.com/ggondim/azure-monofunction/issues).\n\n\u003e We will not provide a SLA to your issue, so, don't expect it to be answered in a short time.\n\n\u003cbr/\u003e\n\n\u003cp align=\"right\"\u003e\u003ca href=\"#Table-of-contents\"\u003e↟ Back to top\u003c/a\u003e\u003c/p\u003e\n\n---\n\n## API\n\n### `AzureMonofunctionRoute` _class_\n\n#### Fields\n\n\u003cdetails\u003e\n  \u003csummary\u003e\n    \u003cb\u003e\n      \u003ccode\u003epath\u003c/code\u003e \n      \u003ci\u003e_string_\u003c/i\u003e\n    \u003c/b\u003e\n  \u003c/summary\u003e\n\n\u003e The path should be matched for the route.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\n    \u003cb\u003e\n      \u003ccode\u003emethods\u003c/code\u003e \n      \u003ci\u003e_string[]_\u003c/i\u003e\n    \u003c/b\u003e\n  \u003c/summary\u003e\n\n\u003e The HTTP verbs that should be matched for the route.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\n    \u003cb\u003e\n      \u003ccode\u003erun\u003c/code\u003e \n      \u003ci\u003e_AsyncFunctionGenerator|AsyncFunctionGenerator[]_\u003c/i\u003e\n    \u003c/b\u003e\n  \u003c/summary\u003e\n\n\u003e A single middleware function or an array of middleware functions.\n\nA middleware should be in form of `async function (context, STOP_SIGNAL?):any`, as documented in [`asyncMiddleware` specification](https://github.com/ggondim/azure-functions-middlewares#asyncmiddleware).\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\n    \u003cb\u003e\n      \u003ccode\u003emeta\u003c/code\u003e \n      \u003ci\u003e_object_=\u003ccode\u003e{}\u003c/code\u003e\u003c/i\u003e\n    \u003c/b\u003e\n  \u003c/summary\u003e\n\n\u003e Custom route metadata to be available at `context.meta` property.\n\n\u003c/details\u003e\n\n### `AzureMonoFunction` _class_\n\n#### Fields\n\n\u003cdetails\u003e\n  \u003csummary\u003e\n    \u003cb\u003e\n      \u003ccode\u003edebug\u003c/code\u003e \n      \u003ci\u003e_boolean_=\u003ccode\u003efalse\u003c/code\u003e\u003c/i\u003e\n    \u003c/b\u003e\n  \u003c/summary\u003e\n\n\u003e Determines if Azure Monofunctions operations should be logged or not.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\n    \u003cb\u003e\n      \u003ccode\u003elogger\u003c/code\u003e \n      \u003ci\u003e_{ log: function }_=\u003ccode\u003econsole\u003c/code\u003e\u003c/i\u003e\n    \u003c/b\u003e\n  \u003c/summary\u003e\n\n\u003e The logger object containing a `log(message, ...args)` function that will be used for logging messages.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\n    \u003cb\u003e\n      \u003ccode\u003eroutePrefix\u003c/code\u003e \n      \u003ci\u003e_string_=\u003ccode\u003e\"/api\"\u003c/code\u003e\u003c/i\u003e\n    \u003c/b\u003e\n  \u003c/summary\u003e\n\n\u003e The route prefix that will be used in route matching.\n\n\u003c/details\u003e\n\n#### Methods\n\n\u003cdetails\u003e\n  \u003csummary\u003e\n    \u003cb\u003e\n      \u003ccode\u003eaddRoutes()\u003c/code\u003e \n      \u003ci\u003efunction(routes):void\u003c/i\u003e\n    \u003c/b\u003e\n  \u003c/summary\u003e\n\n\u003e Adds a list of routes to the monofunction router.\n\n**Arguments**\n\n| Argument | Type | Required | Default | Description |\n| - | - | - | - | - |\n| routes | `AzureMonofunctionRoute[]` | true | | A list of valid routes. |\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\n    \u003cb\u003e\n      \u003ccode\u003eget()\u003c/code\u003e, \u003ccode\u003epost()\u003c/code\u003e, \u003ccode\u003epatch()\u003c/code\u003e, \u003ccode\u003eput()\u003c/code\u003e, \u003ccode\u003edelete()\u003c/code\u003e \n      \u003ci\u003efunction(path, middlewares):void\u003c/i\u003e\n    \u003c/b\u003e\n  \u003c/summary\u003e\n\n\u003e Adds a single route to the monofunction router for HTTP verb corresponding to the method name.\n\nIt is an alias for the method `route()`, but with the argument `methods` already defined.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\n    \u003cb\u003e\n      \u003ccode\u003elisten()\u003c/code\u003e \n      \u003ci\u003efunction():AzureFunction\u003c/i\u003e\n    \u003c/b\u003e\n  \u003c/summary\u003e\n\n\u003e Returns the Azure Functions entrypoint `async (context) =\u003e {}` that will be called by the function HTTP trigger and will execute the entire router.\n\n**Returns**\n\n`AzureFunction`: the [Azure Functions entrypoint](https://github.com/Azure/azure-functions-nodejs-worker/blob/master/types/public/Interfaces.d.ts#L12).\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\n    \u003cb\u003e\n      \u003ccode\u003eonError()\u003c/code\u003e \n      \u003ci\u003efunction(catchCallback):void\u003c/i\u003e\n    \u003c/b\u003e\n  \u003c/summary\u003e\n\n\u003e Registers an error callback to be called when a middleware throws an error.\n\n**Arguments**\n\n| Argument | Type | Required | Default | Description |\n| - | - | - | - | - |\n| catchCallback | `function` | true | | A callback function that takes two arguments `(error, context)` |\n\n**Callbacks**\n\n##### catchCallback\n_function (error, context):any_\n\n| Argument | Type | Required | Default | Description |\n| - | - | - | - | - |\n| error | `Error|any` | true | | The error thrown by a middleware |\n| context | [`Context` ℹ](https://github.com/Azure/azure-functions-nodejs-worker/blob/master/types/public/Interfaces.d.ts#L18) | true | | The Azure Function context object. |\n\nReturns: anything returned by the callback will be ignored.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\n    \u003cb\u003e\n      \u003ccode\u003eon404()\u003c/code\u003e \n      \u003ci\u003efunction(notFoundHandler):void\u003c/i\u003e\n    \u003c/b\u003e\n  \u003c/summary\u003e\n\n\u003e Registers a fallback handler to be called when no route matches the current URL.\n\n**Arguments**\n\n| Argument | Type | Required | Default | Description |\n| - | - | - | - | - |\n| notFoundHandler | `function` | true | | A callback function that takes one argument `(context)` |\n\n**Callbacks**\n\n##### notFoundHandler\n_function (context):void_\n\n| Argument | Type | Required | Default | Description |\n| - | - | - | - | - |\n| context | [`Context` ℹ](https://github.com/Azure/azure-functions-nodejs-worker/blob/master/types/public/Interfaces.d.ts#L18) | true | | The Azure Function context object. |\n\nReturns: anything returned by the callback will be ignored.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\n    \u003cb\u003e\n      \u003ccode\u003eroute()\u003c/code\u003e \n      \u003ci\u003efunction(methods, path, middlewares):void\u003c/i\u003e\n    \u003c/b\u003e\n  \u003c/summary\u003e\n\n\u003e Adds a single route to the monofunction router.\n\n**Arguments**\n\n| Argument | Type | Required | Default | Description |\n| - | - | - | - | - |\n| methods | `Array\u003c'GET'|'POST'|'PATCH'|'PUT'|'DELETE'\u003e` | true | | List of HTTP verbs for the route. |\n| path | `string` | true | | The URL path for the route. |\n| middlewares | `AsyncGeneratorFunction|AsyncGeneratorFunction[]` | true | `default` | A single function middleware or a list of middlewares that should run for the route, in form of `async function (context, STOP_SIGNAL?):any`, as documented in [`asyncMiddleware` specification](https://github.com/ggondim/azure-functions-middlewares#asyncmiddleware). |\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\n    \u003cb\u003e\n      \u003ccode\u003euse()\u003c/code\u003e \n      \u003ci\u003efunction(asyncMiddleware, phase?):void\u003c/i\u003e\n    \u003c/b\u003e\n  \u003c/summary\u003e\n\n\u003e Adds a global middleware to be executed for every matched route.\n\nIdentical to [`use()` method from Azure Functions Middlewares](https://github.com/ggondim/azure-functions-middlewares#methods).\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\n    \u003cb\u003e\n      \u003ccode\u003euseIf()\u003c/code\u003e \n      \u003ci\u003efunction(expression, asyncMiddleware, phase?):void\u003c/i\u003e\n    \u003c/b\u003e\n  \u003c/summary\u003e\n\n\u003e Adds a global middleware to be conditionally executed for every matched route if the specified expression returns `true`.\n\nIdentical to [`useIf()` method from Azure Functions Middlewares](https://github.com/ggondim/azure-functions-middlewares#methods).\n\n\u003c/details\u003e\n\n\u003cbr/\u003e\n\n\u003cp align=\"right\"\u003e\u003ca href=\"#Table-of-contents\"\u003e↟ Back to top\u003c/a\u003e\u003c/p\u003e\n\n---\n\n## Tecnhical concepts\n\n### Motivation and design\n\nAzure Monofunction borned to help developers use the power of serverless in Azure Functions but with minimal complexity with function management.\n\nWhen using serverles, developers often end up with a microservices architecture, even with functions in the same Function App. Each function requires a HTTP binding, your own endpoint and an endpoint maps only to a single resource.\n\nThis complexity leads developers to create many triggers and functions to simple resource APIs, like CRUD APIs: you will ever need at least two functions (one for `/resource` and one for `/resource/:id`) and at least five `if` clauses in these functions to make it possible.\n\nThen, in the end you always end up with two options: mix logic and confuse next API maintainers or deal with a lot of functions for basic operations that could be aggregated.\n\nYou probably experienced this, as we experienced at [NOALVO](https://midianoalvo.com.br), and you sure were not satisfied with any of these two approaches. \n\n**If you want to keep up with Azure Functions powers, like cost-per-consumption and elastic, automatic scalability, now you can build a monolithic API architecture, just like in Express, Koa or HAPI, using Azure Monofunction**.\n\nAzure Monofunction was inspired specially from Express monolithic APIs.\n\n\u003e Curiosity: Azure is _the cloud_ ☁, Functions is _the flash_ ⚡, [Azure Functions Middlewares](https://github.com/NOALVO/azure-functions-middlewares) is _the thunder 🌩_ and Azure Monofunction is **_the thunderstorm_** ⛈. \n\n### Features\n\n* Multilevel route matching\n* Dynamic route params\n* Route HTTP verbs\n* Route middleware\n* Route metadada\n* Multiple middlewares (cascade) per route\n* Global standard and conditional middlewares\n* Error handler middleware\n* Not found/404 handler middleware\n\n### Related projects\n\n* [Azure Functions Middlewares](https://github.com/NOALVO/azure-functions-middlewares)\n* [Universal Router](https://github.com/kriasoft/universal-router)\n\n\u003c!-- ### Similar projects\n\n* [Project 1]() --\u003e\n\n\u003cbr/\u003e\n\n\u003cp align=\"right\"\u003e\u003ca href=\"#Table-of-contents\"\u003e↟ Back to top\u003c/a\u003e\u003c/p\u003e\n\n---\n\n## Contributing\n\n### If you don't want to code\n\nHelp us spreading the word or consider making a donation.\n\n#### Star the project\n\n![](https://img.shields.io/github/stars/ggondim/azure-monofunction?style=social)\n\n#### Tweet it\n\n![](https://img.shields.io/twitter/url?style=social\u0026url=https%3A%2F%2Fgithub.com%2Fggondim%2Fazure-monofunction)\n\n\u003c!-- #### Donate\n\n![](https://c5.patreon.com/external/logo/become_a_patron_button.png)\n\n![](https://camo.githubusercontent.com/b8efed595794b7c415163a48f4e4a07771b20abe/68747470733a2f2f7777772e6275796d6561636f666665652e636f6d2f6173736574732f696d672f637573746f6d5f696d616765732f707572706c655f696d672e706e67)\n\n\u003cimg src=\"https://opencollective.com/webpack/donate/button@2x.png?color=blue\" width=250 /\u003e --\u003e\n\n#### Add your company name to the [Who is using](#Who-is-using) secion\n\nMake a pull request or start an issue to add your company's name.\n\n### If you want to code\n\n![](https://img.shields.io/static/v1?label=code%20style\u0026message=eslint/airbnb\u0026color=orange) \n\n#### Code of conduct\n\n![](https://img.shields.io/static/v1?label=Code%20of%20conduct\u0026message=Contributor%20Covenant\u0026color=informational)\n\nWe follow [Contributor Covenant Code of Conduct](https://www.contributor-covenant.org/version/2/0/code_of_conduct/code_of_conduct.md). If you want to contribute to this project, you must accept and follow it.\n\n#### SemVer\n\n![](https://img.shields.io/static/v1?label=semver\u0026message=2.0.0\u0026color=informational)\n\nThis project adheres to [Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html).\n\n#### Roadmap\n\nIf you are not solving an issue or fixing a bug, you can help developing the roadmap below.\n\n\u003cdetails\u003e\n  \u003csummary\u003e\n    \u003cb\u003eSee the roadmap\u003c/b\u003e\n  \u003c/summary\u003e\n\n* [ ] Improve documentation\n* [ ] Conditional middlewares for routes\n* [ ] Async error and not found handlers\n\n\u003c/details\u003e\n\n\n\u003cbr/\u003e\n\n\u003cp align=\"right\"\u003e\u003ca href=\"#Table-of-contents\"\u003e↟ Back to top\u003c/a\u003e\u003c/p\u003e\n\n---\n\n## Hall of fame\n\n### Who is using\n\n* [NOALVO](https://midianoalvo.com.br)\n\n\u003c!-- ### Contributors\n\n[![](https://sourcerer.io/fame/$USER/$OWNER/$REPO/images/0)](https://sourcerer.io/fame/ggondim/${OWNER}/azure-monofunction/links/0)\n\n### Backers\n\n\u003cobject type=\"image/svg+xml\" data=\"https://opencollective.com/collective/tiers/backers.svg?avatarHeight=36\u0026width=600\"\u003e\u003c/object\u003e\n\n### Sponsors\n\n\u003cobject type=\"image/svg+xml\" data=\"https://opencollective.com/collective/tiers/Sponsors.svg?avatarHeight=36\u0026width=600\"\u003e\u003c/object\u003e\n\n\u003cbr/\u003e --\u003e\n\n\u003cp align=\"right\"\u003e\u003ca href=\"#Table-of-contents\"\u003e↟ Back to top\u003c/a\u003e\u003c/p\u003e\n\n---\n\n## License\n\n![](https://img.shields.io/github/license/ggondim/azure-monofunction)\n\nLicensed under the [MIT License](LICENSE.md).\n\n\u003cbr/\u003e\n\n\u003cp align=\"right\"\u003e\u003ca href=\"#Table-of-contents\"\u003e↟ Back to top\u003c/a\u003e\u003c/p\u003e\n\n---\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fggondim%2Fazure-monofunction","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fggondim%2Fazure-monofunction","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fggondim%2Fazure-monofunction/lists"}