Skip to content

Rewrite in ESM

Pre-release
Pre-release
Compare
Choose a tag to compare
@thetutlage thetutlage released this 03 Dec 10:33

Highlights

  • Added a new layer of middleware called server middleware. Server middleware runs before the route matching happens. So now, we have three types of middleware.
    • Server: Runs for all the HTTP requests.
    • Router: Runs for all the HTTP requests only if a route for the request URL is defined.
    • Named: Individually applied on the routes.
  • Code is way faster than earlier. However, keeping fastify as the performance benchmark, we are 2%-3% slower than fastify.
  • The internals are a lot simpler. We have removed around 3000 lines of code (though we have added many more tests).
  • No longer using ambient modules. Ambient modules was a hack to get @ioc style imports to work.
  • Introduced a new layer of middleware stack called server middleware. Server middleware runs on all HTTP requests, even if no routes for that URL exist.
  • Allow configuring the query string parser and serializer.

Breaking changes

  • The code is rewritten in ESM and will not work with CJS anymore
  • A lot of interfaces have been removed. So, for example, instead of using HttpContextContract you can import and use the HttpContext class directly for type annotation.
  • Removed standalone.ts export. Instead, the main entry point now exports everything (except types).
  • The types are exported from the /types subpath.
  • Removed all providers. The AdonisJS core will be creating providers for all the underlying packages.
  • Removed the forceContentNegotiationTo config option. Instead, we will ship with a default middleware to force content negotiation.

Router - Breaking changes

  • Removed the Route.namespace method. We no longer use the concept of namespaces in favor of Node.js sub-path imports.

  • Underlying storage of routes has changed. Each route's middleware property is no longer an array of names and arguments. Instead, it is an instance of the Middleware class. Also, the route middleware is now a list of the router's global middleware + route's middleware.

     // Earlier
     const routesJSON = router.toJSON()
     routesJSON[0].middleware.map(({ name, args }) => {})
    
     // Now
     const routesJSON = router.toJSON()
     const routeMiddleware = [...routesJSON[0].middleware.all()]
    
     routeMiddleware.forEach((middleware) => {
       if (typeof middleware === 'function') {
       	// Middleware defined on the route as a function	  
       }
    
       if (middleware.name) {
       	// Named middleware defined on the route	  
       }
    
       // else it is a global middleware
     })
  • Remove the Route.resource.paramFor method in favor of the Route.resource.params method. The latter allows overwriting param names in bulk.

     // Earlier
     Route
       .resource('posts.comments', 'CommentsController')
       .paramFor('posts', 'post')
       .paramFor('comments', 'comment')
    
     // Now
     Route
       .resource('posts.comments', '#controllers/comments')
       .params({ 'posts': 'post', comments: 'comment' })
  • Remove the Route.resource.middleware method in favor of Route.resource.tap. The tap method allows you to access the underlying route for a given resource action.

     // Earlier
     Route
       .resource('posts', 'PostsController')
       .middleware({
         '*': 'auth',
         create: ['acl:admin'],
         update: ['acl:admin'],
         destroy: ['acl:admin'],
       })
    
     // Now
     Route
       .resource('posts', 'PostsController')
       .tap((route) => {
          route.middleware('auth')
       })
       .tap(['create', 'update', 'destroy'], (route) => {
          route.middleware('acl', { role: 'admin' })
       })
  • Remove Route.name and Route.deleted properties in favor of Route.getName() and Route.isDeleted() methods.

Middleware breaking change

  • The Route.middleware method now has type safety. The method will list all the available middleware and the options accepted by them. Also, the middleware options will be passed as a separate argument. Earlier, we used to concatenate the options within the middleware name.

     // Earlier
     Route
       .get('me', 'ProfileController.show')
       .middleware('auth:web')
    
     // Now
     Route
       .get('me', 'ProfileController.show')
       .middleware('auth', { guard: 'web' })

    Multiple middleware needs to be defined by calling the middleware method multiple times.

     // Earlier
     Route
       .get('me', 'ProfileController.show')
       .middleware(['auth:web', 'acl:admin'])
    
     // Now
     Route
       .get('me', 'ProfileController.show')
       .middleware('auth', { guard: 'web' })
       .middleware('role', { role: 'admin' })
  • Remove properties BriskRoute, RouteGroup, RouteResource, Route, and RouteMatchers from the router class. You will have to import these classes separately.

     // Earlier
     import Route from '@ioc:Adonis/Core/Route'
    
     Route.RouteGroup.macro()
     Route.RouteResource.macro()
    
     // Now
     import { RouteGroup, RouteResource } from '@adonisjs/core/http'
    
     RouteGroup.macro()
     RouteResource.macro()
  • The Route.makeUrl and Route.makeSignedUrl no longer accept deprecated options. Therefore, if currently using these methods does not give any deprecation warnings, you will not see any breaking changes here.

Http Context breaking changes

  • Remove the HttpContext.create static method. The method was helpful during testing to create a fake instance of HTTP context. We will be shipping with a factory to create the HTTP context.

Server - Breaking changes

  • Removed Server.hooks in favor of Server middleware. They were never documented because we knew hooks were a makeshift arrangement.
  • Removed middleware property. Middleware is not defined using the defineMiddleware and definedNamedMiddleware methods.
  • Remove Server.optimize in favor of async Server.boot method.
  • Remove the server.instance property in favor of the server.getNodeServer method.
  • Remove the server.router property in favor of the server.getRouter method.

Request breaking changes

  • Remove request.updateParams. The request.params method reads the params from the HttpContext and does not maintain its copy anymore.
  • Remove deprecated request.get and request.post methods.

Response - Breaking changes

  • Changed the data structure of the response.lazyBody property. It is now an object with known properties.

    // Earlier
    const responseContent = response.lazyBody[0]
    
    // Now
    if (response.lazyContent.content)
      const responseContent = response.lazyContent.content[0]
    }

Commits

  • feat: add defineMiddleware and defineNamedMiddleware helpers 890b7c3
  • feat: add support to customize the query string parser da8a24c
  • feat: allow configuring the query string parser 3b85adc
  • test: improve coverage 854a478
  • refactor: move config normalization to defineConfig method c46b254
  • refactor: make router and instance properties private 901060f
  • refactor: small improvements in the server 81c1cb9
  • refactor: remove redundant custom exceptions 31a4441
  • docs(README): update readme file 0dac61f
  • feat: main define_config helper and main exports 11b8b79
  • refactor: increase cool off time between benchmarks 7027c9e
  • test: skip test that needs on-demand SSL certificates c4f6d4f
  • chore: use cross-env to set env variables ecb40e0
  • chore: fix peer dependencies range 671ec52
  • refactor: bunch of improvements 0848671
  • refactor: a huge refactor f089f57
  • refactor: the routing layer a8dba96

Full Changelog: v5.12.0...v6.0.0-0