Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Simple, flexible and lightweight TypeScript library for creating express routers using decorators.

License

NotificationsYou must be signed in to change notification settings

marlonbernardes/expressive

Repository files navigation

Simple, flexible and lightweight library for creating express routersusing decorators.

npm versioncodecovbuild

demo

Features

  • Create routers using@Controller (or its alias,@Router) in a class.
  • Define endpoints by decorating methods with@Get,@Post,@Put,@Delete,@All, etc. More obscure http methods can be used via@Route(<http-method>, <path>)
  • Define class or method-level middlewares using@Middleware
  • Optionally wrap your methods using@Wrapper - ideal for handling errors in async methods!
  • Provides aliases for most commonly used http methods (e.gGet, @Post, @Put, etc) and also allows custom http methods to be used via@Route(<verb>)
  • Lightweight: depends directly only onreflect-metadata and the codebase has around 250 lines of code!
  • Can be gradually adopted: you can use it only for parts of your api, if you desire.

Installation

Install both@bitmountain/expressive andexpress (orexpress@next if you want to give express 5.x a try).

npm install @bitmountain/expressive express

Expressive is compatible with express 4.x and express 5.x (alpha).

Note that this library make heavy use of decorators - so make sure you have them enabled in your TypeScript settings:

{"compilerOptions":{"emitDecoratorMetadata":true,"experimentalDecorators":true,// other compiler options}}

Getting started

importbootstrap,{Controller,Get}from'@bitmountain/expressive';importexpressfrom'express';@Controller('/hello')exportclassFooController{  @Get('/world')publicbar(req:Request,res:Response){res.send('Hello world!');}}// create your express app like you normally wouldconstapp=express();//  the line below will create and register the routers into the app// (you can also pass additional options or use .create to manually register the routers// - see the rest of the documentation below)expressive.bootstrap(app,[newFooController()])app.listen(3000);

Decorators

DecoratorDescriptionWhere can it be applied?
@Controller(basePath: string, options?: RouterOptions)Allow classes to group methods/endpoints under a common base path. An expressRouterOptions object can also be provided with additional configurationClasses
@Router(basePath: string, options: RouterOptions)Alias for@ControllerClasses
@Get/@Post/@Put/@Delete/@Options/@Patch/@Head(path: string | RegExp | string[] | RegExp[])Used to convert a class method/property to an express route for serving requests matching the equivalent HTTP Verb.Methods
@Route(verb: string, path: string | RegExp | string[] | RegExp[])Same as above, but allows you to manually specify the http verb you want to use.Methods
@All(path: string | RegExp | string[] | RegExp[])Same as above, but matches all http verbs (seeexpress.all())Methods
@Middleware(RequestHandler | RequestHandler[])Used to apply one or more middlewares to a method or a class. Middlewares applied to classes will be invoked for each method of the class.Classes and methods
@ErrorMiddleware(ErrorRequestHandler | ErrorRequestHandler[])Used to apply one or more error middlewares to a method or a class. Error middlewares applied to classes will be invoked for each method of the class.Classes and methods
@Wrapper(wrapperFunction: () => RequestHandler)Can be applied to a method or class. When applied to a class, wraps all methods of the class with the provided function.Classes and methods

API

expressive.bootstrap(app, [controllers], options?)

Creates one express router for each controller instance provided andregisters them in the given express app.

  • options:
{// Array of middlewares which will be applied to all routes.// Middlewares can also be specified at a class/method level// using the@Middleware decorator.globalMiddlewares?:[]// Wrapper function which will "wrap" each one of the routes.// Wrappers can also be specified at a class/method level using the//@Wrapper decorator.globalWrapper?:(fn)=>(req,res,next)=>fn(req,res,next)// By default, expressive uses express.Router(opts) to construct// router instances (where the "opts" variable is optionally provided// via the@Controller decorator. You can use this variable if you want// expressive to use a custom router.routerFactory:(opts?:RouterOptions)=>Router;}

expressive.create([controllers], options?)

Creates one express router for each one of the controller instances provided.When using this function you have to manually register the controllers in the express app,like so:

constapp=express();constcfgs=expressive.create([newUsersController()]);cfgs.forEach(cfg=>app.use(cfg.basePath,cfg.router));
  • options:
{// Wrapper function which will "wrap" each one of the routes.// Wrappers can also be specified at a class/method level using the//@Wrapper decoratorglobalWrapper?:(fn)=>(req,res,next)=>fn(req,res,next)// By default, expressive uses express.Router(opts) to construct// router instances (where the "opts" variable is optionally provided// via the@Controller decorator. You can use this variable if you want// expressive to use a custom router.routerFactory:(opts?:RouterOptions)=>Router;}

Examples

Applying a middleware to a single method in a controller

@Controller('/users')exportclassUsersController{  @Get('/:id')// the middleware below will be invoked before findById is executed  @Middleware([loggingMiddleware()])publicfindById(req:Request,res:Response){res.json({foo:'bar'});}}

Applying a middleware to all methods in a controller

@Controller('/users')// the middleware below will be executed for all methods in this controller@Middleware([authMiddleware()])exportclassUsersController{  @Get('/:id')publicfindById(req:Request,res:Response){res.json({foo:'bar'});}  @Get('/')publicfindAll(req:Request,res:Response){res.send([{user:'']);}}

Adding a middleware to all methods in ALL controllers

@Controller('/users')exportclassUsersController{/* methods here */}@Controller('/projects')exportclassProjectsController{/* methods here */}constapp=express();expressive.bootstrap(app,[newUsersController(),newProjectsController()],{// The middleware below will be added to all methods in all controllers registered above.// You can also add middlewares at controller or method level using the@Middleware decorator.globalMiddlewares:[loggingMiddleware()]})

Handling async methods

One way to handle async methods is to wrap the functions using an async handler. You can wrapall the methods in a controller using@Wrapper or provide a value to theglobalWrapper propertywhen callingexpressive.bootstrap:

Note: This is only needed for express 4.x or below.Starting from express 5.x an async wrapper will no longer be needed, as express automaticallytakes care of handlers that return promises.

importasyncHandlerfrom'express-async-handler';@Controller('/users')@Wrapper(asyncHandler)exportclassUsersController{  @Get('/:id')publicasyncfindById(req:Request,res:Response){constuser=awaitdb.findUserById(req.params.id);res.json(user);}}constapp=express();express.bootstrap(app,[newUsersController()]);// alternatively, you can get rid of the @Wrapper decorator above// and apply it to all controllers at once:// express.bootstrap(app, [new UsersController()], {//  globalWrapper: asyncHandler//});

FAQ

- In what order are routes matched?

If a request match 2 different routes, only the first matched route (the one the appears first in the class) will be executed. This matches express' behaviours, wherethe first route always takes priority. As an example:

@Controller('/users')exportclassUsersController{  @Get('/:id')publicfoo(){}// IMPORTANT: this will never be executed, as the route above (GET /:id) was// registered first and also matches the endpoint GET /users/hello  @Get('/hello')publichello(){}}

- In what order are middlewares executed?

In the order they were provided (just like in express)

// execution order goes from left to right@Middleware([first(),second(),third()])@Get('/:id')publicloadById(req:Request,res:Response){}

- How do I handle async methods?

If using express 5.x (in alpha as of this writing) you don't have to do anything,as async routes are automatically handled by express. If using express <= 4.x you need toeither add a try/catch block around your async methods (and callnext() accordingly) or use an async wrapper. You canwrite your own async wrapper in a few lines of code or use a library such asexpress-async-handler.

There's one example above in this documentation that covers how to use an async wrapper.

Why expressive?

  • There are other libraries/frameworks out there that serve a similar purpose (NestJS, tsed, Overnight, inversify-express-utils), but they either have a much steeper learning curve or they are too opinionated in the way you create your app and controllers. Expressive just provides decorators so you can create and register the routers in a more elegant way.

Contributing

→ SeeContribution Guidelines for more details.

Code of Conduct

→ SeeCode of Conduct for more details.

License

MIT

About

Simple, flexible and lightweight TypeScript library for creating express routers using decorators.

Topics

Resources

License

Code of conduct

Stars

Watchers

Forks

Contributors2

  •  
  •  

[8]ページ先頭

©2009-2025 Movatter.jp