All Projects → yiisoft → router

yiisoft / router

Licence: BSD-3-Clause License
Router is a request matcher and URL generator

Programming Languages

PHP
23972 projects - #3 most used programming language

Projects that are alternatives of or similar to router

VueStudy
Vue.js学习系列示例代码及教程
Stars: ✭ 80 (+110.53%)
Mutual labels:  router
var-dumper
Helper for dumping variable for debug purposes
Stars: ✭ 13 (-65.79%)
Mutual labels:  yii3
NoCRouter
RTL Network-on-Chip Router Design in SystemVerilog by Andrea Galimberti, Filippo Testa and Alberto Zeni
Stars: ✭ 39 (+2.63%)
Mutual labels:  router
gatsby-plugin-dynamic-routes
Creating dynamic routes based on your environment and/or renaming existing routes
Stars: ✭ 14 (-63.16%)
Mutual labels:  router
oas2
OpenAPI 2.0 (aka Swagger) utils for Golang.
Stars: ✭ 19 (-50%)
Mutual labels:  router
yii-console
Yii console components
Stars: ✭ 48 (+26.32%)
Mutual labels:  yii3
froute
Type safe and flexible router for React
Stars: ✭ 31 (-18.42%)
Mutual labels:  router
http-connection-lifecycle
Complete and detailed explanation of HTTP connection lifecycle
Stars: ✭ 43 (+13.16%)
Mutual labels:  router
routedux
A router that maps urls to redux actions and vice-versa
Stars: ✭ 19 (-50%)
Mutual labels:  router
session
A session service, PSR-15 session middleware, and a flash message service which helps use one-time messages.
Stars: ✭ 14 (-63.16%)
Mutual labels:  yii3
ROS Scripts
Scripts for RouterOS (MikroTik devices)
Stars: ✭ 81 (+113.16%)
Mutual labels:  router
backbone.base-router
A better starting point for building a new Backbone Router.
Stars: ✭ 49 (+28.95%)
Mutual labels:  router
db-sqlite
SQLite support for Yii
Stars: ✭ 15 (-60.53%)
Mutual labels:  yii3
trail
Routing library for the Scala platform
Stars: ✭ 76 (+100%)
Mutual labels:  router
mutex
Mutex lock implementation
Stars: ✭ 28 (-26.32%)
Mutual labels:  yii3
dodgr
Distances on Directed Graphs in R
Stars: ✭ 106 (+178.95%)
Mutual labels:  router
crizmas-mvc
raulsebastianmihaila.github.io/crizmas-mvc-docs/
Stars: ✭ 12 (-68.42%)
Mutual labels:  router
browser
Routing and Navigation for browser apps
Stars: ✭ 31 (-18.42%)
Mutual labels:  router
pi-ap
Raspberry Pi Access Point: This repo automates the configuration of hostapd, dnsmasq, dhcpcd & wpa_supplicant to transform a Pi into a wireless AP. Requirements: a Pi, an Ethernet cable and a DHCP-enabled port on a router with a 'net connection or a switch connected to this router.
Stars: ✭ 69 (+81.58%)
Mutual labels:  router
app-api
API application project template
Stars: ✭ 44 (+15.79%)
Mutual labels:  yii3

Yii Router


Latest Stable Version Total Downloads Build status Scrutinizer Code Quality Code Coverage Mutation testing badge static analysis type-coverage

The package provides PSR-7 compatible request routing and a PSR-15 middleware ready to be used in an application. Instead of implementing routing from ground up, the package provides an interface for configuring routes and could be used with an adapter package. Currently, the only adapter available is FastRoute.

Features

  • URL matching and URL generation supporting HTTP methods, hosts, and defaults.
  • Good IDE support for defining routes.
  • Route groups with infinite nesting.
  • Middleware support for both individual routes and groups.
  • Ready to use middleware for route matching.
  • Convenient CurrentRoute service that holds information about last matched route.
  • Out of the box CORS middleware support.

Requirements

  • PHP 7.4 or higher.

Installation

The package could be installed with composer:

composer require yiisoft/router --prefer-dist

Additionally, you will need an adapter such as FastRoute.

Defining routes and URL matching

Common usage of the router looks like the following:

use Yiisoft\Router\CurrentRoute;
use Yiisoft\Router\Group;
use Yiisoft\Router\Route;
use Yiisoft\Router\RouteCollection;
use Yiisoft\Router\RouteCollectorInterface;
use Yiisoft\Router\UrlMatcherInterface;
use Yiisoft\Router\Fastroute\UrlMatcher;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;

// Define routes
$routes = [
    Route::get('/')
        ->action(static function (ServerRequestInterface $request, RequestHandlerInterface $next) use ($responseFactory) {
            $response = $responseFactory->createResponse();
            $response->getBody()->write('You are at homepage.');
            return $response;
        }),
    Route::get('/test/{id:\w+}')
        ->action(static function (CurrentRoute $currentRoute, RequestHandlerInterface $next) use ($responseFactory) {
            $id = $currentRoute->getArgument('id');
    
            $response = $responseFactory->createResponse();
            $response->getBody()->write('You are at test with argument ' . $id);
            return $response;
        })
];

// Add routes defined to route collector
$collector = $container->get(RouteCollectorInterface::class);
$collector->addGroup(Group::create(null)->routes($routes));

// Initialize URL matcher
/** @var UrlMatcherInterface $urlMatcher */
$urlMatcher = new UrlMatcher(new RouteCollection($collector));

// Do the match against $request which is PSR-7 ServerRequestInterface. 
$result = $urlMatcher->match($request);

if (!$result->isSuccess()) {
     // 404
}

// $result->arguments() contains arguments from the match.

// Run middleware assigned to a route found.
$response = $result->process($request, $notFoundHandler);

Note: Despite UrlGeneratorInterface and UrlMatcherInterface being common for all adapters available, certain features and, especially, pattern syntax may differ. To check usage and configuration details, please refer to specific adapter documentation. All examples in this document are for FastRoute adapter.

Middleware usage

In order to simplify usage in PSR-middleware based application, there is a ready to use middleware provided:

$router = $container->get(Yiisoft\Router\UrlMatcherInterface::class);
$responseFactory = $container->get(\Psr\Http\Message\ResponseFactoryInterface::class);

$routerMiddleware = new Yiisoft\Router\Middleware\Router($router, $responseFactory, $container);

// Add middleware to your middleware handler of choice.

In case of a route match router middleware executes handler middleware attached to the route. If there is no match, next application middleware processes the request.

Routes

Route could match for one or more HTTP methods: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS. There are corresponding static methods for creating a route for a certain method. If a route is to handle multiple methods at once, it could be created using methods().

use Yiisoft\Router\Route;

Route::delete('/post/{id}')
    ->name('post-delete')
    ->action([PostController::class, 'actionDelete']);
    
Route::methods([Method::GET, Method::POST], '/page/add')
    ->name('page-add')
    ->action([PageController::class, 'actionAdd']);

If you want to generate a URL based on route and its parameters, give it a name with name(). Check "Creating URLs" for details.

action() in the above is a primary middleware definition that is invoked last when matching result process() method is called. How middleware are executed and what middleware formats are accepted is defined by middleware dispatcher used. See readme of yiisoft/middleware-dispatcher for middleware examples.

If a route should be applied only to a certain host, it could be defined like the following:

use Yiisoft\Router\Route;

Route::get('/special')
    ->name('special')
    ->action(SpecialAction::class)
    ->host('https://www.yiiframework.com');

Defaults for parameters could be provided via defaults() method:

use Yiisoft\Router\Route;

Route::get('/api[/v{version}]')
    ->name('api-index')
    ->action(ApiAction::class)
    ->defaults(['version' => 1]);

In the above we specify that if "version" is not obtained from URL during matching then it will be 1.

Besides action, additional middleware to execute before the action itself could be defined:

use Yiisoft\Router\Route;

Route::methods([Method::GET, Method::POST], '/page/add')
    ->middleware(Authentication::class)
    ->middleware(ExtraHeaders::class)
    ->action([PostController::class, 'add'])
    ->name('blog/add');

It is typically used for a certain actions that could be reused for multiple routes such as authentication.

If there is a need to either add middleware to be executed first or remove existing middleware from a route, prependMiddleware() and disableMiddleware() could be used.

If you combine routes from multiple sources and want last route to have priority over existing ones, mark it as "override":

use Yiisoft\Router\Route;

Route::get('/special')
    ->name('special')
    ->action(SpecialAction::class)
    ->override();

Route groups

Routes could be grouped. That is useful for API endpoints and similar cases:

use \Yiisoft\Router\Route;
use \Yiisoft\Router\Group;
use \Yiisoft\Router\RouteCollectorInterface;

// for obtaining router see adapter package of choice readme
$collector = $container->get(RouteCollectorInterface::class);
    
$collector->addGroup(
    Group::create('/api')
        ->middleware(ApiAuthentication::class)
        ->host('https://example.com')
        ->routes([
            Route::get('/comments'),
            Group::create('/posts')->routes([
                Route::get('/list'),
            ]),
        ])
);

A group could have a prefix, such as /api in the above. The prefix is applied for each group's route both when matching and when generating URLs.

Similar to individual routes, a group could have a set of middleware managed using middleware(), prependMiddleware(), and disableMiddleware(). These middleware are executed prior to matched route's own middleware and action.

If host is specified, all routes in the group would match only if the host match.

Automatic OPTIONS response and CORS

By default, router responds automatically to OPTIONS requests based on the routes defined:

HTTP/1.1 204 No Content
Allow: GET, HEAD

Generally that is fine unless you need CORS headers. In this case, you can add a middleware for handling it such as tuupola/cors-middleware:

use Yiisoft\Router\Group;
use \Tuupola\Middleware\CorsMiddleware;

return [
    Group::create('/api')
        ->withCors(CorsMiddleware::class)
        ->routes([
          // ...
        ]
    );
];

Creating URLs

URLs could be created using UrlGeneratorInterface::generate(). Let's assume a route is defined like the following:

use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Psr\Http\Message\ResponseFactoryInterface;
use Yiisoft\Yii\Http\Handler\NotFoundHandler;
use Yiisoft\Yii\Runner\Http\SapiEmitter;
use Yiisoft\Yii\Runner\Http\ServerRequestFactory;
use Yiisoft\Router\CurrentRoute;
use Yiisoft\Router\Route;
use Yiisoft\Router\RouteCollection;
use Yiisoft\Router\RouteCollectorInterface;
use Yiisoft\Router\Fastroute\UrlMatcher;


$request = $container->get(ServerRequestFactory::class)->createFromGlobals();
$responseFactory = $container->get(ResponseFactoryInterface::class);
$notFoundHandler = new NotFoundHandler($responseFactory);
$collector = $container->get(RouteCollectorInterface::class);
$collector->addRoute(
   Route::get('/test/{id:\w+}')
       ->action(static function (CurrentRoute $currentRoute, RequestHandlerInterface $next) use ($responseFactory) {
           $id = $currentRoute->getArgument('id');
           $response = $responseFactory->createResponse();
           $response->getBody()->write('You are at test with argument ' . $id);

           return $response;
       })
       ->name('test')
);
$router = new UrlMatcher(new RouteCollection($collector));
$route = $router->match($request);
$response = $route->process($request, $notFoundHandler);
$emitter = new SapiEmitter();
$emitter->emit($response, $request->getMethod() === Method::HEAD);

Then that is how URL could be obtained for it:

use Yiisoft\Router\UrlGeneratorInterface;

function getUrl(UrlGeneratorInterface $urlGenerator, $parameters = [])
{
    return $urlGenerator->generate('test', $parameters);
}

Absolute URL cold be generated using UrlGeneratorInterface::generateAbsolute():

use Yiisoft\Router\UrlGeneratorInterface;

function getUrl(UrlGeneratorInterface $urlGenerator, $parameters = [])
{
    return $urlGenerator->generateAbsolute('test', $parameters);
}

Also, there is a handy UrlGeneratorInterface::generateFromCurrent() method. It allows generating a URL that is a modified version of the current URL:

use Yiisoft\Router\UrlGeneratorInterface;

function getUrl(UrlGeneratorInterface $urlGenerator, $id)
{
    return $urlGenerator->generateFromCurrent(['id' => 42]);
}

In the above, ID will be replaced with 42 and the rest of the parameters will stay the same. That is useful for modifying URLs for filtering and/or sorting.

Obtaining current route information

For such a route:

use \Yiisoft\Router\Route;

$routes = [
    Route::post('/post/{id:\d+}')
        ->action([PostController::class, 'actionEdit']),
];

The information could be obtained as follows:

use Psr\Http\Message\ResponseInterface
use Psr\Http\Message\UriInterface;
use Yiisoft\Router\CurrentRoute;
use Yiisoft\Router\Route;

final class PostController
{   
    public function actionEdit(CurrentRoute $currentRoute): ResponseInterface
    {
        $postId = $currentRoute->getArgument('id');
        if ($postId === null) {
            throw new \InvalidArgumentException('Post ID is not specified.');
        }
        
        // ...
    
    }
}

In addition to commonly used getArgument() method, the following methods are available:

  • getArguments() - To obtain all arguments at once.
  • getName() - To get route name.
  • getHost() - To get route host.
  • getPattern() - To get route pattern.
  • getMethods() - To get route methods.
  • getUri() - To get current URI.

Testing

Unit testing

The package is tested with PHPUnit. To run tests:

./vendor/bin/phpunit

Mutation testing

The package tests are checked with Infection mutation framework. To run it:

./vendor/bin/infection

Static analysis

The code is statically analyzed with Psalm. To run static analysis:

./vendor/bin/psalm

License

The Yii Dependency Injection is free software. It is released under the terms of the BSD License. Please see LICENSE for more information.

Maintained by Yii Software.

Support the project

Open Collective

Follow updates

Official website Twitter Telegram Facebook Slack

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].