Skip to main content


The shelf_modular is prepared to receive requests respecting the methods GET, POST, PUT, DELETE, PATCH, applying the REST. We can use the Route class constructors to inform the method, the path and the handler. Routes are added in modules. We'll take the AppModule as an example and add some routes:

import 'package:shelf/shelf.dart';import 'package:shelf_modular/shelf_modular.dart';
class AppModule extends Module {  @override  List<ModularRoute> get routes => [        Route.get('/products', () => Response.ok('All products')),        Route.get('/users', () => Response.ok('All users')),      ];}

Now you can test it in your browser or using some program (wget/curl):


Magic Handler#

Every route has a function that returns a Response. This function can have up to 3 optional parameters: Request, Injector and ModularArgments.

Route.get('/', (Request request) => Request.ok('ok'));Route.get('/2', (Request request, Injector injector) => Request.ok('ok'));Route.get('/3', (Request request, Injector injector, ModularArguments args) => Request.ok('ok'));//orRoute.get('/4', (Injector injector) => Request.ok('ok'));Route.get('/5', (ModularArguments args) => Request.ok('ok'));Route.get('/6', (Injector injector, ModularArguments args) => Request.ok('ok'));...

Magic Handler parameters are injected by shelf_modular and can be used in any order, making the handler function more dynamic even without using Reflection (dart:mirrors). So what are these parameters?

  • Request: Contains the information of the request coming from the client.
  • Injector: Similar to Modular.get. Service Locator is made available in this way to facilitate testing.
  • ModularArguments: It stores the parameters and queries of the request, as well as the payload (in json) of the body of a POST request, for example.

Feel free to shuffle or omit some parameters.


It is mandatory to specify the parameter's type. (ex: Request req);

Route Arguments.#

shelf_modular supports dynamic routing and also understands query and request body. The object that represents this is ModularArguments. Let's look at an example with a complete REST layer:

import 'package:shelf/shelf.dart';import 'package:shelf_modular/shelf_modular.dart';
class AppModule extends Module {  @override  List<ModularRoute> get routes => [        Route.get('/users', () => Response.ok('All users')),        Route.get('/users/:id', (ModularArguments args) => Response.ok('user id ${args.params['id']}')),        //passed json body in request'/users', (ModularArguments args) => Response.ok('New user added: ${}')),        Route.put('/users/:id', (ModularArguments args) => Response.ok('Updated user id ${args.params['id']}')),        Route.delete('/users/:id', (ModularArguments args) => Response.ok('Deleted user id ${args.params['id']}')),      ];}

You can use query instead of params by going to http://localhost:3000/users?id=1 and retrieving with ModularArguments.query using final id = ModularAguments.query[ 'id'];.


Note that in was used instead of ModularArguments.params. That's because takes the body of the request (such as a json).

To get a Multipart, you must use


Sometimes we need to aggregate routes in a layer to make the data easier to understand, that's why we use Resource type objects. Just create a class that inherits from Resource and implement the ModularRoute List. See an example of a complete CRUD:

class UserResource extends Resource {  @override  List<Route> get routes => [        Route.get('/', () => getAllUsers),        Route.get('/:id', getUser),        //passed json body in request'/', addUser),        Route.put('/:id', updateUser),        Route.delete('/:id', deleteUser),      ];
  FutureOr<Response> getAllUsers() => Response.ok('All users');  FutureOr<Response> getUser(ModularArguments args) => Response.ok('user id ${args.params['id']}');  FutureOr<Response> addUser(ModularArguments args) => Response.ok('New user added: ${}');  FutureOr<Response> updateUser(ModularArguments args) => Response.ok('Updated user id ${args.params['id']}');  FutureOr<Response> deleteUser(ModularArguments args) => Response.ok('Deleted user id ${args.params['id']}');}

Now, just add UserResource to AppModule using the Route.resource constructor:

import 'package:shelf/shelf.dart';import 'package:shelf_modular/shelf_modular.dart';
import 'user_resource.dart';
class AppModule extends Module {  @override  List<ModularRoute> get routes => [      Route.resource('/users', resource: UserResource()),    ];}

To see if everything is working, just test it in a browser:


Paying attention to the following URL, we notice that the route name /users is concatenated with the resource routes, being: /users + /.