Girouette

Basic Routing

Define routes using HTTP method decorators

Basic Routing

Girouette provides decorators for all standard HTTP methods, allowing you to define routes directly on your controller methods.

HTTP Method Decorators

Available Decorators

DecoratorHTTP MethodExample
@GetGETRetrieve resources
@PostPOSTCreate resources
@PutPUTReplace resources
@PatchPATCHUpdate resources
@DeleteDELETERemove resources
@AnyAll methodsMatch any HTTP method

Basic Usage

import {
  Get,
  Post,
  Put,
  Patch,
  Delete,
  Any,
} from '@adonisjs-community/girouette'
import { HttpContext } from '@adonisjs/core/http'

export default class ArticlesController {
  @Get('/articles') 
  async index() {
    return Article.all()
  }

  @Get('/articles/:id') 
  async show({ params }: HttpContext) {
    return Article.findOrFail(params.id)
  }

  @Post('/articles') 
  async store({ request }: HttpContext) {
    return Article.create(request.body())
  }

  @Put('/articles/:id') 
  async replace({ params, request }: HttpContext) {
    const article = await Article.findOrFail(params.id)
    return article.merge(request.body()).save()
  }

  @Patch('/articles/:id') 
  async update({ params, request }: HttpContext) {
    const article = await Article.findOrFail(params.id)
    return article.merge(request.only(['title'])).save()
  }

  @Delete('/articles/:id') 
  async destroy({ params }: HttpContext) {
    const article = await Article.findOrFail(params.id)
    await article.delete()
    return { deleted: true }
  }

  @Any('/webhook') 
  async webhook({ request }: HttpContext) {
    return { method: request.method() }
  }
}

Route Parameters

Basic Parameters

Use :param syntax to define route parameters:

@Get('/users/:id') 
async show({ params }: HttpContext) {
  return User.findOrFail(params.id) 
}

Multiple Parameters

@Get('/users/:userId/posts/:postId') 
async show({ params }: HttpContext) {
  const user = await User.findOrFail(params.userId) 
  return user.related('posts').query().where('id', params.postId).firstOrFail() 
}

Optional Parameters

Use ? to mark a parameter as optional:

@Get('/articles/:category?') 
async index({ params }: HttpContext) {
  if (params.category) {
    return Article.query().where('category', params.category)
  }
  return Article.all()
}

Wildcard Parameters

Use * to capture the rest of the path:

@Get('/files/*path') 
async serve({ params }: HttpContext) {
  // /files/images/logo.png → params.path = 'images/logo.png'
  return serveFile(params.path) 
}

Named Routes

You can optionally name your routes by passing a second argument to any HTTP method decorator:

@Get('/users', 'users.index') 
async index() {
  return User.all()
}

@Get('/users/:id', 'users.show') 
async show({ params }: HttpContext) {
  return User.findOrFail(params.id)
}

@Post('/users', 'users.store') 
async store({ request }: HttpContext) {
  return User.create(request.body())
}

Named routes can be used to generate URLs:

import router from '@adonisjs/core/services/router'

// Generate URL from route name
const url = router.makeUrl('users.show', { id: 1 })
// Result: /users/1

When using the @Resource decorator, routes are automatically named following RESTful conventions (e.g., posts.index, posts.show, posts.store).

Using Response Object

For more control, use the response object:

@Get('/download/:file')
async download({ params, response }: HttpContext) {
  return response.download(`./uploads/${params.file}`)
}

@Post('/users')
async store({ request, response }: HttpContext) {
  const user = await User.create(request.body())
  return response.status(201).json(user)
}

@Get('/redirect')
async redirect({ response }: HttpContext) {
  return response.redirect('/new-location')
}

Best Practices

Controller Organization

Keep related routes in the same controller:

// Good: Single responsibility
export default class UsersController {
  @Get('/users')
  async index() { /* ... */ }

  @Get('/users/:id')
  async show() { /* ... */ }

  @Post('/users')
  async store() { /* ... */ }
}

// Avoid: Mixing unrelated routes
export default class MixedController {
  @Get('/users')
  async users() { /* ... */ }

  @Get('/products')
  async products() { /* ... */ }
}

Route Naming Conventions

Follow consistent naming patterns:

// RESTful conventions
@Get('/resources', 'resources.index')          // List
@Get('/resources/:id', 'resources.show')       // Show single
@Post('/resources', 'resources.store')         // Create
@Put('/resources/:id', 'resources.update')     // Full update
@Patch('/resources/:id', 'resources.update')   // Partial update
@Delete('/resources/:id', 'resources.destroy') // Delete

Next Steps

On this page