Section courante

A propos

Section administrative du site

Travailler avec un routeur

Routeur et route

Dans Fano Framework, une route est une règle d'association entre le modèle de chemin d'URL, la méthode HTTP et le code la gérant. Le routeur gère une ou plusieurs routes et fait correspondre le chemin d'URL de la demande, en extrait les données et sélectionne le code les gérant (instance de gestionnaire de demande, c'est-à-dire le contrôleur). Le routeur est toute classe implémentant l'interface IRouter.

Création d'une route pour la méthode GET

  1. Var
  2.     router:IRouter;
  3.     handler:IRequestHandler;
  4. ...
  5. router.get('/', handler);

Création d'un itinéraire pour la méthode POST

  1. router.post('/submit', handler);

Création d'un itinéraire pour la méthode PUT

  1. router.put('/submit', handler);

Création d'un itinéraire pour la méthode DELETE

  1. router.delete('/submit', handler);

Création d'un itinéraire pour la méthode PATCH

  1. router.patch('/submit', handler);

Création d'un itinéraire pour la méthode HEAD

  1. router.head('/', handler);

Création d'un itinéraire pour la méthode OPTIONS

  1. router.options('/', handler);

Créer un itinéraire pour plusieurs méthodes

  1. router.map(['GET', 'POST'], '/', handler);

Créer un itinéraire pour toutes les méthodes

  1. router.any('/', handler);

Itinéraire avec paramètres

Un itinéraire peut avoir des paramètres comme indiqué dans l'exemple suivant :

  1. router.get('/user/{username}', myUserHandler);
  2. router.get('/products/{id}/{productSlug}', productList);

Correspondance de route

Si nous avons la configuration de la route suivante :

  1. Var
  2.     router:IRouter;
  3.     myAppHandler, anotherAppHandler:IRequestHandler;
  4. ...
  5.  
  6. //Requête GET
  7. router.get('/my/app', myAppHandler);
  8.  
  9. //Requête POST
  10. router.post('/another/app', anotherAppHandler);

Si le nom d'hôte de votre application est exemple.com et que le client ouvre http://exemple.com/mon/app via un navigateur, notre application recevra la méthode GET de la requête pour les ressources /mon/app. Le routeur fera correspondre la méthode HTTP et l'URL et renverra myAppHandler en tant que code chargé de gérer cette requête.

Si le client ouvre http://exemple.com/autre/app via un navigateur, notre application recevra la méthode GET de la requête pour les ressources /autre/app. Le routeur trouvera une correspondance avec /autre/app mais comme il n'est enregistré que pour la requête POST, une exception EMethodNotAllowed sera générée avec le code d'erreur HTTP 405.

Si le client ouvre http://exemple.com/pas/existe via un navigateur, notre application recevra la méthode GET de la requête pour les ressources /pas/existe. Le routeur ne trouvera aucune correspondance. Si cela se produit, une exception ERouteHandlerNotFound sera générée avec le code d'erreur HTTP 404.

Créer des routes d'application avec le générateur de routes

Pour créer des routes d'application, vous devez créer une classe implémentant l'interface IRouteBuilder :

  1. IRouteBuilder=Interface
  2.     ['{46016416-B249-4258-B76A-7F5B55E8348D}']
  3.  
  4.     (*!----------------------------------------------
  5. * créer des routes d'application
  6. * ----------------------------------------------
  7. * @param cntr instance de conteneur de dépendances
  8. * @param rtr instance de routeur
  9. *-----------------------------------------------*)
  10.     Procedure buildRoutes(const cntr:IDependencyContainer; Const rtr:IRouter);
  11. End;

Le Fano Framework fournit une classe abstraite de base TRouteBuilder dont vous pouvez étendre et implémenter sa méthode buildRoutes() et la transmettre lors de la création d'une instance d'application comme indiqué dans le code suivant :

  1. TAppRoutes=Class(TRouteBuilder)
  2.  Public
  3.     Procedure buildRoutes(
  4.         const container : IDependencyContainer;
  5.         const router : IRouter
  6.     ); override;
  7. End;
  8. ...
  9. Procedure TAppRoutes.buildRoutes(
  10.     Const container:IDependencyContainer;
  11.     Const router:IRouter
  12. );
  13. Begin
  14.    //Inscrivez tous les itinéraires ici
  15.    router.get('/', handler);
  16. End;

Ensuite, créez son instance et transmettez-la au constructeur de l'application.

  1. appInstance:=TCgiWebApplication.create(
  2.     TAppServiceProvider.create(),
  3.     TAppRoutes.create()
  4. );

Si vous utilisez Fano CLI pour créer des applications Web, vous remarquerez peut-être que les itinéraires sont séparés en un ou plusieurs fichiers d'inclusion étant insérés dans une classe chargée de créer des itinéraires d'application, comme indiqué dans l'exemple suivant :

  1. Procedure TAppRoutes.buildRoutes(
  2.     Const container:IDependencyContainer;
  3.     Const router:IRouter
  4. );
  5. Begin
  6.     {$INCLUDE Routes/routes.inc}
  7. End;

Il s'agit simplement d'une convention utilisée par les outils CLI Fano car elle est simple à générer.

Le Fano Framework veille à ce que vous fournissiez une classe implémentant IRouteBuilder. Il ne se soucie pas de la manière dont vous l'implémentez. Vous êtes donc libre de composer la classe de création d'itinéraire comme bon vous semble.

Par exemple, vous pouvez créer une implémentation IRouteBuilder distincte pour chaque fonctionnalité pour une meilleure organisation du code, puis les composer à l'aide de la classe TCompositeRouteBuilder comme indiqué dans l'exemple ci-dessous :

  1. TUsersRoutes=Class(TRouteBuilder)
  2.  Public
  3.     Procedure buildRoutes(
  4.         Const container:IDependencyContainer;
  5.         Const router:IRouter
  6.     ); override;
  7. End;
  8. ...
  9. Procedure TUsersRoutes.buildRoutes(
  10.     Const container:IDependencyContainer;
  11.     Const router:IRouter
  12. );
  13. Begin
  14.     //Enregistrer les itinéraires associés aux utilisateurs ici
  15. End;

Pour les itinéraires de fonctionnalités de produit :

  1. TProductRoutes=Class(TRouteBuilder)
  2. public
  3.     Procedure buildRoutes(
  4.         Const container:IDependencyContainer;
  5.         Const router:IRouter
  6.     ); override;
  7. End;
  8. ...
  9. Procedure TProductRoutes.buildRoutes(
  10.     Const container:IDependencyContainer;
  11.     Const router:IRouter
  12. );
  13. Begin
  14.     //Enregistrer les produits liés aux itinéraires ici
  15. End;

Et lorsque vous créez une application, vous les composez comme suit :

  1. appInstance:=TCgiWebApplication.create(
  2.     TAppServiceProvider.create(),
  3.     TCompositeRouteBuilder.create([
  4.         TUserRoutes.create(),
  5.         TProductRoutes.create()
  6.     ]);
  7. );

Veuillez noter que TCompositeRouteBuilder est une implémentation intégrée d'IRouteBuilder composant une ou plusieurs instances d'IRouteBuilder en une seule.

Définir le nom de la route ou les intergiciels avec l'interface IRoute

Toutes les méthodes enregistrant le gestionnaire de requêtes telles que get(), post(),.., renvoient une instance de l'interface IRoute que vous pouvez utiliser pour attribuer un nom à la route ou attacher un intergiciel. Le code suivant répertorie toutes les méthodes de cette interface :

  1. Function setName(Const routeName:shortstring):IRoute;
  2. Function getName():shortstring;
  3. Function add(Const amiddleware:IMiddleware):IRoute;

Par exemple pour définir le nom de la route et attacher un middleware :

  1. var authOnlyMiddleware : IMiddleware;
  2. ...
  3. router.post('/user/submit', handler).setName('create-user').add(authOnlyMiddleware);

Obtenir le paramètre de la route

Le troisième paramètre de la méthode handleRequest() de l'interface IRequestHandler donne une instance de l'interface IRouteArgsReader pour permettre à l'application de récupérer les paramètres de la route.

Si vous avez le modèle de route /maroute/{name} et que vous accédez à la route via l'URL http://exemple.com/maroute/jean, vous pouvez obtenir la valeur du paramètre name comme suit :

  1. Function TMyController.handleRequest(
  2.     Const request:IRequest;
  3.     Const response:IResponse;
  4.     Const args:IRouteArgsReader
  5. ):IResponse;
  6. Var
  7.     arg:TPlaceholder;
  8. Begin
  9.     arg:=args.getArg('name');
  10.     //arg.name = 'name', arg.value = 'jean'
  11. End;

Si vous êtes intéressé uniquement par sa valeur, vous pouvez appeler getValue() et passer le nom de paramètre. Il renvoie la valeur sous forme de chaîne de caractères :

  1. Var name:String;
  2. ...
  3. name:=args.getValue('name'); //name = 'jean'

ou avec une syntaxe simplifiée de type tableau :

  1. name:=args['name']; //name = 'jean'

Les codes ci-dessus imprimeront une sortie identique comme suit :

  1. name:=args.getArg('name').value;

Vous pouvez obtenir tous les paramètres de route en utilisant la méthode getArgs() :

  1. Function TMyController.handleRequest(
  2.     Const request:IRequest;
  3.     Const response:IResponse;
  4.     Const args:IRouteArgsReader
  5. ):IResponse;
  6. Var placeHolders:TArrayOfPlaceholders;
  7.     arg:TPlaceholder;
  8.     i:integer;
  9. Begin
  10.     placeHolders:=args.getArgs();
  11.     For i:=0 to length(placeholders)-1 do Begin
  12.         arg:=placeholders[i];
  13.     End;
  14. End;

Créer une instance de routeur

Le Fano Framework est fourni avec une implémentation de routeur de base, la classe TRouter, implémentant l'interface IRouter :

  1. container.add('router', TSimpleRouterFactory.create());

La classe TSimpleRouterFactory crée une instance de routeur prenant en charge l'analyse des paramètres de route. Vous pouvez également utiliser la classe TRouterFactory créeant une instance de routeur ne prenant pas en charge le paramètre de route, mais étant plus rapide lors de la correspondance de l'URL de la demande :

  1. container.add('router', TRouterFactory.create());

Si vous n'avez besoin que d'un modèle de chemin d'URL statique, vous devez l'utiliser.

Si vous créez un fournisseur de services d'application hérité de TBasicAppServiceProvider, il créera un routeur par défaut à l'aide de la classe TSimpleRouterFactory étant suffisante pour la plupart des applications.

Remplacer l'instance du routeur

Si vous souhaitez remplacer le routeur par une implémentation différente, vous pouvez remplacer la méthode buildRouter() de TBasicAppServiceProvider. Par exemple :

  1. TMyAppProvider=Class(TBasicAppServiceProvider)
  2.  Private
  3.     fRouterMatcher:IRouteMatcher;
  4.  Public
  5.     Function getRouteMatcher():IRouteMatcher; override;
  6.     Function buildRouter(Const cntr:IDependencyContainer):IRouter; override;
  7. End;
  8. ...
  9. Function TMyAppProvider.buildRouter(Const cntr:IDependencyContainer):IRouter;Begin
  10.     ctnr.add('router', TRouterFactory.create());
  11.     result:=ctnr['router'] as IRouter;
  12.     fRouteMatcher:=Result as IRouteMatcher;
  13. End;
  14.  
  15. Function TMyAppProvider.getRouteMatcher():IRouteMatcher;Begin
  16.     Result:=fRouteMatcher;
  17. End;

Notez que IRouteMatcher est une interface chargée de faire correspondre l'URL de la demande et TRouter l'implémente.



Dernière mise à jour : Vendredi, le 18 octobre 2024