Girouette
Elegant decorator-based routing for AdonisJS v7
Introduction
Girouette provides a beautiful, fluent API for defining your AdonisJS routes using decorators. By bringing route definitions closer to your controller methods, Girouette makes your application's routing more intuitive and maintainable.
Documentation
The full documentation is available at girouette.raphalr.dev.
Installation
You can install Girouette via the AdonisJS CLI:
node ace add @adonisjs-community/girouette
Configuration
To manually generate the configuration file, you can run:
node ace configure @adonisjs-community/girouette
By convention, Girouette will recursively scan all files in the ./app folder that end with _controller.ts. You can change this behavior by modifying the controllersGlob regex in the configuration file.
Basic Routing
After installation, you can start using decorators to define your routes.
Import the decorators you need in your controller:
import {
Get,
Post,
Put,
Patch,
Delete,
Any,
Middleware,
ResourceMiddleware,
GroupMiddleware,
Resource,
Where,
Group,
GroupDomain,
} from '@adonisjs-community/girouette'
import { HttpContext } from '@adonisjs/core/http'
export default class UsersController {
@Get('/users')
async index({ response }: HttpContext) {
// Handle GET request
}
@Post('/users')
async store({ request }: HttpContext) {
// Handle POST request
}
}
Available Decorators
HTTP Methods
@Get(pattern: string, name?: string)@Post(pattern: string, name?: string)@Put(pattern: string, name?: string)@Patch(pattern: string, name?: string)@Delete(pattern: string, name?: string)@Any(pattern: string, name?: string)
Route Configuration
@Group(name?: string)- Define optional route name prefix@GroupDomain(domain: string)- Restrict routes to a specific domain@GroupMiddleware(middleware: Middleware[])- Apply middleware to all routes@Middleware(middleware: Middleware[])- Apply middleware to a single route@Resource({name: string, params?: { [resource: string]: string } })- Create RESTful resource routes@ResourceMiddleware(actions: string | string[], middleware: Middleware[])- Apply middleware to resource actions@Where(param: string, matcher: string | RegExp | Function)- Add route parameter constraints
Resource Actions
@Pick(actions: string | string[])- Include only specified actions in a resource@Except(actions: string | string[])- Exclude specified actions from a resource@ApiOnly()- Include only API actions in a resource (index, show, store, update, destroy)
Tuyau Integration (Type-safe API Client)
Girouette fully supports Tuyau, AdonisJS's type-safe API client generator. To enable type generation for your Girouette routes, you need to register the generateGirouetteRoutes hook in your adonisrc.ts file before the Tuyau generateRegistry hook:
import { defineConfig } from '@adonisjs/core/app'
import { generateRegistry } from '@tuyau/core/hooks'
import { generateGirouetteRoutes } from '@adonisjs-community/girouette/hooks'
export default defineConfig({
hooks: {
init: [
generateGirouetteRoutes(), // Register Girouette routes FIRST
generateRegistry(), // Then generate Tuyau types
],
},
providers: [
// ... other providers
() => import('@adonisjs-community/girouette/girouette_provider'),
],
})
This hook scans your controllers during the codegen phase and registers routes with the AdonisJS router, allowing Tuyau to properly infer request and response types from your controller methods and validators.
How it works
-
When the dev server starts:
- The dev server child process initializes the AdonisJS application
- The
GirouetteProviderscans your controllers and registers routes with the router - Tuyau's
routesScanninghook runs and finds all registered routes - Tuyau analyzes the routes and generates TypeScript types
-
At runtime:
- The same routes registered by the provider handle incoming requests
The generateGirouetteRoutes() hook ensures compatibility with Tuyau by documenting the integration pattern. The actual route registration is handled by the GirouetteProvider at runtime, which means:
- Your frontend gets proper TypeScript types for API calls
- Request body types are inferred from your validators (e.g., VineJS schemas)
- Response types are inferred from your controller method return types
- No duplicate route registration or complex codegen logic needed
Example
// app/controllers/posts_controller.ts
import { Post } from '@adonisjs-community/girouette'
import { createPostValidator } from '#validators/post'
export default class PostsController {
@Post('/posts', 'posts.store')
async store({ request }: HttpContext) {
const data = await request.validateUsing(createPostValidator)
const post = await Post.create(data)
return post
}
}
With the hook configured, Tuyau will generate types like:
// .adonisjs/client/registry/schema.d.ts
'posts.store': {
methods: ["POST"]
pattern: '/posts'
types: {
body: ExtractBody<InferInput<typeof createPostValidator>>
response: Awaited<ReturnType<PostsController['store']>>
}
}
Note regarding TC39 experimental decorators
We're well aware about the uncertain future of TC39 decorators, which are still in experimental phase, but we are closely following the AdonisJS team's position on this topic. As of now, AdonisJS v6 is still using the experimental decorators proposal, and Girouette is built to work seamlessly with it.
License
Girouette is open-sourced software licensed under the MIT license.
Credits
All credit goes to Alexis Bouchez, who initiated this package. Thanks to him! It is now maintained by the AdonisJS community.