Apoyo - Express
HTTP server utilities for express.
Features
- Better async support for handlers
const getHealth = Request.reply(async () => {
return Http.Ok({
message: 'Everything is alright'
})
})
- Dependency injection integration with
@apoyo/scopes
const listTodos = Request.reply(
TodoService.$findAll,
async (findTodos) => {
const todos = await findTodos()
return Http.Ok(todos)
})
- Validation with
@apoyo/decoders
const updateTodoSchema = ObjectDecoder.struct({
title: TextDecoder.string,
completed: BooleanDecoder.boolean
})
const $id = Request.param('id', TextDecoder.uuid)
const $body = Request.body(updateTodoSchema)
const updateTodo = Request.reply(
$id,
$body,
TodoService.$findById,
TodoService.$update,
(id, body, findTodo, updateTodo) => {
const todo = await findTodo(id)
if (!todo) {
throw Http.NotFound()
}
const saved = await updateTodo(todo.id, body)
return Http.Ok(saved)
})
- Easier routing configuration:
const todoRoutes = Route.group('/todos', {
children: [
Route.get('/', ListTodos),
Route.get('/:id', GetTodo),
Route.post('/', CreateTodo)
]
})
const routes = Route.group({
middlewares: [],
children: [
Route.get('/health', GetHealth),
todoRoutes
]
})
- Easier error catching and handling:
const catchAll =
Request.catch(
Logger,
async (err, logger) => {
logger.error('An internal error occured while executing HTTP request', err)
throw err
}
)
const routes = Route.group({
middlewares: [],
children: [
Route.get('/health', GetHealth),
todoRoutes
],
catch: [
catchAll
]
})
- Exception filtering can be done via error catchers
const catchCustomErrors = Request.catch((err) => {
if (err instanceof AccessException) {
throw Http.Forbidden({
message: err.message
})
}
if (err instanceof ValidationException) {
throw Http.UnprocessableEntity({
message: err.message,
errors: err.errors
})
}
throw err
})
const todoRoutes = Route.group('/todos', {
children: [
Route.get('/', ListTodos),
Route.get('/:id', GetTodo),
Route.post('/', CreateTodo)
],
catch: [
catchCustomErrors
]
})
- Easy to setup from scratch:
const $router = Express.createRouter(routes)
const $config = Injectable.of({
port: 3000
})
const $app = Injectable.define($router, (router) => {
const app = express()
...
app.use(router)
return app
})
const $server = Express.createServer($app, $config)
async function main () {
const scope = Scope.create()
await scope.get($server)
}
main()
- Easy to integrate in existing applications: you only need a
Scope
instance to create the router middleware
const app = express()
...
const $router = Express.createRouter(routes)
const scope = Scope.create()
const router = await scope.get($router)
app.use(router)
...
app.listen(3000)
Installation
Install express:
npm install express @types/express
Install peer dependencies:
npm install @apoyo/std @apoyo/decoders @apoyo/scopes
Install package:
npm install @apoyo/express
Documentation
Please visit the documentation for more information.
License
This project is licensed under the MIT License - see the LICENSE file for details.