Route.get('/', () => 'Hello Adonis')
You are viewing the legacy version of AdonisJS. Visit https://adonisjs.com for newer docs. This version will receive security patches until the end of 2021.
Routes enable the outside world to interact with your app via URLs.
Routes are registered inside the start/routes.js
file.
The most basic route binding requires a URL and a closure:
Route.get('/', () => 'Hello Adonis')
The return value of the closure will be sent back to the client as a response.
You can also bind a route to a controller using a controller.method
signature:
Route.get('posts', 'PostController.index')
The above signature PostController.index
refers to the App/Controllers/Http/PostController.js
file’s index
method.
Resourceful routes use different HTTP verbs to indicate the type of request:
Route.get(url, closure)
Route.post(url, closure)
Route.put(url, closure)
Route.patch(url, closure)
Route.delete(url, closure)
To register a route that responds to multiple verbs, use Route.route
:
Route.route('/', () => {
//
}, ['GET', 'POST', 'PUT'])
To render a view directly (e.g. static pages), use Route.on.render
:
Route.on('/').render('welcome')
In the example above, when the root /
route is loaded, the resources/view/welcome.edge
file is rendered directly.
For dynamic routes, you can define route parameters like so:
Route.get('posts/:id', ({ params }) => {
return `Post ${params.id}`
})
In the example above, :id
is a route parameter.
Its value is then retrieved via the params
object.
To define an optional route parameter, append a ?
symbol to its definition:
Route.get('make/:drink?', ({ params }) => {
// use Coffee as fallback when drink is not defined
const drink = params.drink || 'Coffee'
return `One ${drink}, coming right up!`
})
In the example above, :drink?
is an optional route parameter.
You may want to render a single view from the server and handle routing using your preferred front-end framework:
Route.any('*', ({ view }) => view.render('...'))
Any specific routes need to be defined before your wildcard route:
Route.get('api/v1/users', closure)
Route.any('*', ({ view }) => view.render('...'))
Though routes are defined inside the start/routes.js
file, they are referenced everywhere else in the application (e.g. using the views
route helper to make a URL for a given route).
By using the as()
method, you can assign your route a unique name:
Route.get('users', closure).as('users.index')
This will enable you to use route
helpers in your templates and code, like so:
<!-- before -->
<a href="/users">List of users</a>
<!-- after -->
<a href="{{ route('users.index') }}">List of users</a>
foo ({ response }) {
return response.route('users.index')
}
Both route
helpers share the same signature and accept an optional parameters object as their second argument:
Route.get('posts/:id', closure).as('posts.show')
route('posts.show', { id: 1 })
route
helpers also accept an optional parameters object as a third argument to handle protocol
, domain
and query
options:
route('posts.show', { id: 1 }, {
query: { foo: 'bar' }
});
// resulting in /post/1?foo=bar
// Without parameters:
route('auth.login', null, {
domain: 'auth.example.com',
protocol: 'https',
query: { redirect: '/dashboard' }
});
// resulting in https://auth.example.com/login?redirect=%2Fdashboard
The same rules apply for the view.
<a href="{{ route('posts.show', { id: 1 }, {query: { foo: 'bar' }}) }}">Show post</a>
// href="/post/1?foo=bar"
Route formats open up a new way for content negotiation, where you can accept the response format as part of the URL.
A route format is a contract between the client and server for what type of response to return:
Route.get('users', async ({ request, view }) => {
const users = await User.all()
if (request.format() === 'json') {
return users
}
return view.render('users.index', { users })
}).formats(['json'])
For the example above, the /users
endpoint will be able to respond in multiple formats based on the URL:
GET /users.json # Returns an array of users in JSON
GET /users # Returns the view in HTML
You can also disable the default URL and force the client to define the format:
Route.get('users', closure).formats(['json', 'html'], true)
Passing true
as the second argument ensures the client specifies one of the expected formats. Otherwise, a 404 error is thrown.
You will often create resourceful routes to do CRUD operations on a resource.
Route.resource
assigns CRUD routes to a controller using a single line of code:
// This...
Route.resource('users', 'UserController')
// ...equates to this:
Route.get('users', 'UserController.index').as('users.index')
Route.post('users', 'UserController.store').as('users.store')
Route.get('users/create', 'UserController.create').as('users.create')
Route.get('users/:id', 'UserController.show').as('users.show')
Route.put('users/:id', 'UserController.update').as('users.update')
Route.patch('users/:id', 'UserController.update')
Route.get('users/:id/edit', 'UserController.edit').as('users.edit')
Route.delete('users/:id', 'UserController.destroy').as('users.destroy')
This feature is only available when binding routes to a Controller. |
You can also define nested resources:
Route.resource('posts.comments', 'PostCommentController')
You can limit the routes assigned by the Route.resource
method by chaining one of the filter methods below.
Removes GET resource/create
and GET resource/:id/edit
routes:
Route.resource('users', 'UserController')
.apiOnly()
Keeps only the passed routes:
Route.resource('users', 'UserController')
.only(['index', 'show'])
Keeps all routes except the passed routes:
Route.resource('users', 'UserController')
.except(['index', 'show'])
You can attach middleware to any resource as you would with a single route:
Route.resource('users', 'UserController')
.middleware(['auth'])
If you don’t want to attach middleware to all routes generated via Route.resource
, you can customize this behavior by passing a Map
to the middleware
method:
Route.resource('users', 'UserController')
.middleware(new Map([
[['store', 'update', 'destroy'], ['auth']]
]))
In the example above, the auth middleware is only applied to the store, update and destroy routes.
You can define response formats for resourceful routes via the formats
method:
Route.resource('users', 'UserController')
.formats(['json'])
Your application may use multiple domains.
AdonisJs make it super easy to deal with this use-case.
Domains can be a static endpoint like blog.adonisjs.com
, or a dynamic endpoint like :user.adonisjs.com
.
You can define the domain on a single route as well. |
Route.group(() => {
Route.get('/', ({ subdomains }) => {
return `The username is ${subdomains.user}`
})
}).domain(':user.myapp.com')
In the example above, if you visited virk.myapp.com
, you would see The username is virk
.
If your application routes share common logic/configuration, instead of redefining the configuration for each route, you can group them like so:
// Ungrouped
Route.get('api/v1/users', closure)
Route.post('api/v1/users', closure)
// Grouped
Route.group(() => {
Route.get('users', closure)
Route.post('users', closure)
}).prefix('api/v1')
Prefix all route URLs defined in the group:
Route.group(() => {
Route.get('users', closure) // GET /api/v1/users
Route.post('users', closure) // POST /api/v1/users
}).prefix('api/v1')
Assign one or many middleware to the route group:
Route.group(() => {
//
}).middleware(['auth'])
Group middleware executes before route middleware. |
Prefix the namespace of the bound controller:
Route.group(() => {
// Binds '/users' to 'App/Controllers/Http/Admin/UserController'
Route.resource('/users', 'UserController')
}).namespace('Admin')
Defines formats for all routes in the group:
Route.group(() => {
//
}).formats(['json', 'html'], true)
Specify which domain group routes belong to:
Route.group(() => {
//
}).domain('blog.adonisjs.com')