{"id":15068276,"url":"https://github.com/hugw/expressio","last_synced_at":"2025-10-12T18:34:18.460Z","repository":{"id":26328523,"uuid":"108186087","full_name":"hugw/expressio","owner":"hugw","description":"Light-weight Node.js library to build HTTP APIs using Express.","archived":false,"fork":false,"pushed_at":"2023-01-23T20:37:05.000Z","size":1750,"stargazers_count":5,"open_issues_count":15,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-04-25T02:25:15.788Z","etag":null,"topics":["auth","express","expressjs","framework","javascript","logging","nodejs"],"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/hugw.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-10-24T21:33:21.000Z","updated_at":"2020-03-03T18:11:26.000Z","dependencies_parsed_at":"2023-02-13T03:01:44.751Z","dependency_job_id":null,"html_url":"https://github.com/hugw/expressio","commit_stats":null,"previous_names":[],"tags_count":44,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hugw%2Fexpressio","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hugw%2Fexpressio/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hugw%2Fexpressio/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hugw%2Fexpressio/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hugw","download_url":"https://codeload.github.com/hugw/expressio/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248252721,"owners_count":21072701,"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":["auth","express","expressjs","framework","javascript","logging","nodejs"],"created_at":"2024-09-25T01:33:06.622Z","updated_at":"2025-10-12T18:34:13.413Z","avatar_url":"https://github.com/hugw.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Expressio\n\n[![CircleCI](https://circleci.com/gh/hugw/expressio/tree/master.svg?style=svg\u0026circle-token=db4b0da8980640852612ffcc2c368cf6e7104164)](https://circleci.com/gh/hugw/expressio/tree/master)\n\nLight-weight [Node.js](https://nodejs.org/en/) library to build HTTP APIs using [Express](https://expressjs.com/).\n\nExpressio is a simple catalyst to accelerates the development of modern web applications. With some opinion over configuration in mind, it reduces the initial time a developer has to spend setting up a production-ready service. Additionally, it still preserves the simplicity and flexibility of [Node.js](https://nodejs.org/en/) applications, leaving you in control. \n\nWhile extending [Express](https://expressjs.com/), it offers a base structure and environment-aware configurations to support the following features:\n\n    - Security\n    - Logging capability\n    - Third-party initialization using the server lifecycle events\n    - Asynchronous routes\n    - Enhanced error handlers\n    - Request data validation and sanitization middleware\n    - HTTP authentication using JWTs\n\n## Table of Contents\n\n* [Installation](#installation)\n* [Usage](#usage)\n* [Configuration](#configuration)\n* [Validation](#validation)\n* [Initializers](#initializers)\n* [API](#api)\n* [Contributing](#contributing)\n\n## Installation\nExpressio works with NodeJS v10 and later.\nTo install the package in your project using NPM, run the following command:\n\n```\n$ npm install expressio\n```\n\nIf using Yarn:\n\n```\n$ yarn add expressio\n```\n\n## Usage\nGetting your project up and running:\n\n```js\nimport expressio, { httpError } from 'expressio'\n\nconst app = expressio()\n\napp.get('/', (req, res) =\u003e {\n  res.json({ status: 'online' })\n})\n\napp.get('/error', async () =\u003e {\n  throw httpError(400, { message: 'Something went wrong over here' })\n})\n\napp.start()\n```\n\nAfter executing the code, you will notice the following info in the console:\n\n```\n[TIMESTAMP][info] Server running → 0.0.0.0:4000 @ development\n```\n\nNow you can visit [localhost:4000](http://localhost:4000/).\n\n\u003e Tip: If you inspect `app`  you will realize it is nothing more than an Express app instance with just a few additional functions/objects.\n\n## Configuration\n\nWhen the Expressio instance is created, it will automatically look for a `config.js` file inside the same folder. The file is optional and will be merged with the default config object provided by the library.\n\nPlease check all the available core [config options](src/config.js).\n\nExpressio will compute the environment config variables by doing a deep merge of the **default** attribute and the current environment where your code is running (defaults to **development**).\n\nE.g.\n\n```js\n// config.js\n\nexport default {\n  default: {\n    core: {\n      port: '4040',\n\n      // Logger\n      logger: {\n        level: 'debug',\n      },\n    },\n\n    foo: 'foo-def',\n    bar: 'bar-def',\n  },\n\n  // Production environment\n  production: {\n    core: {\n      logger: {\n        level: 'info',\n      },\n    },\n\n    foo: 'foo-prod',\n  },\n}\n```\n\nIf you `console.log` the config object after initializing your server in a Production environment (`process.env.NODE_ENV === \"production\"`), you will get the following computed object:\n\n```js\n\nconst app = expressio()\nconsole.log(app.config)\n\n// Returns:\n// {\n//  core: {\n//    ...\n//    port: '4040',\n//    logger: {\n//      ...\n//      level: 'info',\n//    },\n//  }\n//  foo: 'foo-prod',\n//  bar: 'bar-def',\n// }\n```\n\n\u003e Tip: Avoid creating custom config variables inside the `core` object to not mix with the default library settings.\n\n#### dotenv\n\nBy default, Expressio uses the **dotenv** package to load custom environment variables if needed. Simply add a `.env`  file inside the root folder of the project (cwd).\n\n## Validation\nThe library provides you a middleware for faster request `body`/`params`/`query` validation using [Joi](https://github.com/hapijs/joi).\n\nE.g.\n\n```js\nimport expressio, { validateRequest } from 'expressio'\nimport Joi from '@hapi/joi'\n\nconst app = expressio()\n\nconst name = Joi\n  .string()\n  .trim()\n  .required()\n  .label('Name')\n\nconst email = Joi\n  .string()\n  .lowercase()\n  .email()\n  .required()\n  .label('Email')\n\napp.post('/check', validateRequest('body', { name, email }), \n\nasync (req, res) =\u003e {\n  res.json(req.body)\n})\n```\n\nIf any validation fails, a formatted error object will automatically be returned in your response:\n\n```js\n{\n  status: 422,\n  type: 'VALIDATION',\n  message: 'Invalid request body data',\n  attributes: {\n    email: {\n      message: 'Email is required',\n      type: 'any.required',\n    },\n    name: {\n      message: 'Name is required',\n      type: 'any.required',\n    },\n  }\n}\n```\n\n\u003e Tip: After the validation runs and is successful, all attributes will be sanitized and keys not declared in your Joi schema will be automatically removed.  For more details please check the `stripUnknown`  option available in Joi.\n\n## Initializers\nExpressio provides a simple and powerful module system to customize your application. For naming convention, we call such modules as *initializers*.\n\nInitializers are functions that accepts a single argument, the `server` object. See the example bellow:\n\n```js\nimport Joi from '@hapi/joi'\nimport { sanitize } from 'expressio'\n\n/**\n * Object schemas\n * to validate configuration\n */\nconst schema = Joi.object({\n  enabled: Joi.boolean().required(),\n  // Misc config...\n})\n\nexport default (server) =\u003e {\n  // If schema is not valid, the server will stop the whole\n  // initialization process and provide a detailed error message\n  const config = sanitize(server.config.foo, schema, 'Invalid Foo config')\n\n  // If enabled attribute is not true, skip\n  // loading the initializer\n  if (!config.enabled) return\n\n  const foo = {\n    // Some API\n  }\n\n  // Expose Foo to the server object\n  server.foo = foo\n\n  // Expose Foo to the request object\n  server.use((req, res, next) =\u003e {\n    req.foo = foo\n    next()\n  })\n\n  // Execute some logic before the server start\n  server.events.on('beforeStart', srv =\u003e {\n    // Logic to run after routes/middlewares/other initializers were loaded but before the server starts.\n  })\n}\n```\n\nTo register your initializer you call the function `initializer` available in your app object.\n\n```js\nimport expressio from 'expressio'\nimport foo from './foo'\n\nconst app = expressio()\n\napp.initialize('foo', foo)\n\n// ...Middlewares\n// ...Routes\n\napp.start()\n```\n\n## API \nWhen your app is instantiated, in addition of the regular ExpressJS functions and variables, you also have the following API available as part of Expressio:\n\n### `app.start()`\n\nStart the server after all initializers, routes and core middlewares were loaded.\n\n### `app.initialize(name, fn)`\n\nRegister a custom initializer. For more details please check the initializers section.\n\n- `name`: String representing the name of the initializer.\n- `fn`: Function. The initializer function.\n\n### `app.logger`\n\nThe logger object is a Winston instance that logs to the console and environment named files by default according to the current level configured in your config file. Please refer to the configuration section for more details.\n\n### `app.logger.level(message)`\n\nCurrent levels available:  error, warn, info, verbose, silly, debug.\n\n- `message`: Any.\n\nE.g.\n\n```js\nconst app = expressio()\n\nconst { logger } = app\n\nlogger.info('A string')\nlogger.debug(new Error())\n```\n\n### `app.config`\n\nThe config object computed after the app is initialized. Please refer to the configuration section for more details.\n \n### `app.events`\n\nAsync event emitter object. By default the app executes the following events as part of its lifecycle:\n\n* **beforeStart**: Event executed right before the server is started. Usually used to append error handlers.\n* **afterStart**: Event executed right after the server is started.\n* **beforeStop**: Event executed right before the server is stopped.\n* **afterStop**: Event executed right after the server is stopped.\n\n### `app.events.on(event, cb)`\n\nAdds an event listener.\n\n- `event`:  any of beforeStart, afterStart, beforeStop, afterStop.\n- `cb`: Function. The first argument is the server instance in its current state.\n\nE.g.\n\n```js\napp.events.on('beforeStart', (server) =\u003e {\n  // Logic to execute\n})\n```\n\n\n### `app.stop()`\n\nFunction to stop the server.\n\n### `app.instance`\n\nThe current HTTP server instance that is listening for connections. \nIt is available after the server starts.\n\n### Helpers\n\n### `router`\n\nThe Express.JS router object. Usually used to create your routes and load them into the main server object.\n\nE.g.\n\n```js\nimport expressio, { router } from 'expressio'\n\nconst app = expressio()\nconst routes = router()\n\nroutes.get('/test', async (req, res) =\u003e {\n  res.json({ route: 'test' })\n})\n\nroutes.post('/data', async (req, res) =\u003e {\n  res.json(req.body)\n})\n\napp.use('/namespace', routes)\n\napp.start()\n```\n\n### `validateRequest(source, schema)`\n\nMiddleware that executes request data validation and returns formatted error objects in the response. For more details on how the validation works, check the validations section.\n\n- `source`: String. Can be one of the following values: body, query or params.\n- `schema`: Valid Joi schema.\n\n### `httpError(code, [meta])`\n\nReturns HTTP-friendly Error objects.\n\n- `code`: String or number representing the status code. Invalid or not found error codes will fallback to `500`.\n- `meta`: Object with extra information regarding the error. Possible options are `message`, `type` and `attributes`.\n\n```js\nhttpError()\n\n// Returns:\n// Error Object {\n//   stack...,\n//   isHttp: true,\n//   message: 'Internal Server Error'\n//   output: {\n//     message: 'Internal Server Error',\n//     type: 'INTERNAL_SERVER_ERROR',\n//     status: 500,\n//   }\n// }\n\nhttpError(400)\n\n// Returns:\n// Error Object {\n//   stack...,\n//   isHttp: true,\n//   message: 'Bad Request'\n//   output: {\n//     message: 'Bad Request',\n//     type: 'BAD_REQUEST',\n//     status: 400,\n//   }\n// }\n\nhttpError(422, {\n  message: 'Something is wrong with this validation',\n  type: 'VALIDATION',\n  attributes: {\n    email: 'Email is invalid',\n    name: 'Name is required'\n  },\n})\n\n// Returns:\n// Error Object {\n//   stack...,\n//   isHttp: true,\n//   message: 'Something is wrong with this validation'\n//   output: {\n//     message: 'Something is wrong with this validation',\n//     type: 'VALIDATION',\n//     attributes: {\n//       email: 'Email is invalid',\n//       name: 'Name is required'\n//     },\n//     status: 422,\n//   }\n// }\n```\n\n## Contributing\nPull requests and stars are always welcome. For bugs and feature requests,  please create an [issue](https://github.com/hugw/expressio/issues).\n\n---\nThe MIT License (MIT)\n\nCopyright (c) 2017 Hugo W. - [contact@hugw.io](mailto:contact@hugw.io) \n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhugw%2Fexpressio","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhugw%2Fexpressio","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhugw%2Fexpressio/lists"}