All Projects → nezamy → Route

nezamy / Route

Licence: mit
Route - Fast, flexible routing for PHP, enabling you to quickly and easily build RESTful web applications.

Projects that are alternatives of or similar to Route

Open Rest
Standard rest server, Base on restify and sequelize
Stars: ✭ 136 (-32%)
Mutual labels:  api, restful-api
Saas Boilerplate
SaaS boilerplate built in Laravel, Bootstrap 4 and VueJs.
Stars: ✭ 152 (-24%)
Mutual labels:  api, restful-api
Node Express Mongoose Passport Jwt Rest Api Auth
Node, express, mongoose, passport and JWT REST API authentication example
Stars: ✭ 146 (-27%)
Mutual labels:  api, restful-api
Restful Api Guidelines
A model set of guidelines for RESTful APIs and Events, created by Zalando
Stars: ✭ 1,397 (+598.5%)
Mutual labels:  api, restful-api
Proteus
Lean, mean, and incredibly fast JVM framework for web and microservice development.
Stars: ✭ 178 (-11%)
Mutual labels:  api, restful-api
Rageframe2
一个基于Yii2高级框架的快速开发应用引擎
Stars: ✭ 1,553 (+676.5%)
Mutual labels:  api, restful-api
Node Express Postgresql Sequelize
Node.js, Express.js, Sequelize.js and PostgreSQL RESTful API
Stars: ✭ 148 (-26%)
Mutual labels:  api, restful-api
Taco Api
🍉 Brazilian Table of Food Composition (TACO) - JSON API
Stars: ✭ 87 (-56.5%)
Mutual labels:  api, restful-api
Usaspending Api
Server application to serve U.S. federal spending data via a RESTful API
Stars: ✭ 166 (-17%)
Mutual labels:  api, restful-api
Restful Api With Laravel Definitive Guide
Repository with the base code for the course "RESTful API with Laravel - Definitive-Guide"
Stars: ✭ 156 (-22%)
Mutual labels:  api, restful-api
Appy Backend
A user system to bootstrap your app.
Stars: ✭ 96 (-52%)
Mutual labels:  api, restful-api
Lumen Api Starter
Lumen 8 基础上扩展出的API 启动项目,精心设计的目录结构,规范统一的响应数据格式,Repository 模式架构的最佳实践。
Stars: ✭ 197 (-1.5%)
Mutual labels:  api, restful-api
Api Restful Con Laravel Guia Definitiva
Repositorio para el código base del curso "API RESTful con Laravel - Guía Definitiva"
Stars: ✭ 95 (-52.5%)
Mutual labels:  api, restful-api
Dawn Api Demo
dawn-api-demo
Stars: ✭ 117 (-41.5%)
Mutual labels:  api, restful-api
Ppgo api demo gin
API接口应用Demo 基于Gin
Stars: ✭ 90 (-55%)
Mutual labels:  api, restful-api
Magic Api
magic-api 是一个接口快速开发框架,通过Web页面编写脚本以及配置,自动映射为HTTP接口,无需定义Controller、Service、Dao、Mapper、XML、VO等Java对象
Stars: ✭ 146 (-27%)
Mutual labels:  api, restful-api
Parvula
An extremely simple & flexible CMS generated from flat files with a complete RESTful API —
Stars: ✭ 76 (-62%)
Mutual labels:  api, restful-api
Aztro
The Astrology API 💫 Get daily horoscope!
Stars: ✭ 78 (-61%)
Mutual labels:  api, restful-api
Appkernel
API development made easy: a smart Python 3 API framework
Stars: ✭ 152 (-24%)
Mutual labels:  api, restful-api
Graphql2rest
GraphQL to REST converter: automatically generate a RESTful API from your existing GraphQL API
Stars: ✭ 181 (-9.5%)
Mutual labels:  api, restful-api

Route v2.0

Route - Fast, flexible routing for PHP, enabling you to quickly and easily build RESTful web applications.

Installation

$ composer require nezamy/route

Or if you looking for ready template for using this route Go to https://github.com/nezamy/just

Route requires PHP 7.4.0 or newer.

Changes list

  • Rewrite route based on php 7.4
  • Support Swoole extensions
  • Support locales to build multi languages website
  • Added Auth, Basic, Digest
  • Availability to customize route parser and handler
  • Smart dependency injection and service container

Usage

Only if using composer create index.php in root.

Create an index.php file with the following contents:

<?php declare(strict_types=1);

define('DS', DIRECTORY_SEPARATOR);
define('BASE_PATH', __DIR__ . DS);
//Show errors
//===================================
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);
//===================================
require BASE_PATH.'vendor/autoload.php';
$request = new Just\Http\GlobalRequest;
$response = new Just\Http\Response;
$route = new Just\Routing\Router($request, $response);
// let store them to container, to use them as a singleton
container()->set(Just\Http\Request::class, $request);
container()->set(Just\Http\Response::class, $response);
container()->set(Just\Routing\Router::class, $route);

try {
    include 'app/routes.php';
    $output = $route->run();

    foreach ($output->headers->all() as $k => $v) {
        header("$k: $v");
    }
    http_response_code($output->statusCode());
    if ($output->hasRedirect()) {
        list($url, $code) = $output->getRedirect();
        header("Location: $url", true, $code);
    }

} catch (\Error $e) {
    pre($e, 'Error', 6);
} catch (\Exception $e) {
    pre($e, 'Exception', 6);
}

echo response()->body();

app/routes.php

<?php
use Just\Route;

Route::get('/', function (){
    return 'Welcome to the home page';
});

// Maybe you want to customize 404 page
Route::setNotfound(function (){
    return 'Page Not found';
});

Use with Swoole

<?php
declare(strict_types=1);

use Swoole\Http\Server;
use Swoole\Http\Request;
use Swoole\Http\Response;

use Just\Routing\Router;

ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);

require __DIR__ . '/vendor/autoload.php';

$http = new Server("0.0.0.0", 9501);
$http->set([
    'document_root' => '/var/www/public',
    'enable_static_handler' => true,
]);
$http->on("request", function (Request $request, Response $response) {

    $request = new Just\Http\Request(
       $request->header ?? [],
       $request->server ?? [],
       $request->cookie ?? [],
       $request->get ?? [],
       $request->post ?? [],
       $request->files ?? [],
       $request->tmpfiles ?? []
    );
    $response = new Just\Http\Response;
    $route = new Just\Routing\Router($request, $response);
	container()->set(Just\Http\Request::class, $request);
	container()->set(Just\Http\Response::class, $response);
	container()->set(Router::class, $route);
    try {
        include __DIR__ .'/app/routes.php';
        $output = $route->run();
        foreach ($output->headers->all() as $k => $v) {
            $response->header($k, $v);
        }

        $response->setStatusCode($output->statusCode());

        if ($output->hasRedirect()) {
            list($url, $code) = $output->getRedirect();
            $response->redirect($url, $code);
        }
    } catch (\Error $e) {
        pre($e, 'Error', 6);
    } catch (\Exception $e) {
        pre($e, 'Exception', 6);
    }
    $response->end(response()->body(true));
});
$http->start();

How it works

Routing is done by matching a URL pattern with a callback function.

app/routes.php

Route::any('/', function() {
    return 'Hello World';
});

Route::post('/contact-us', function(\Just\Http\Request $req) {
    pre($req->body, 'Request');
});

The callback can be any object that is callable. So you can use a regular function:

function pages() {
    return 'Page Content';
}
Route::get('/', 'pages');

Or a class method:

class home
{
    public function pages() {
        return 'Home page Content';
    }
}
Route::get('/', [home::class, 'pages']);
// OR
Route::get('/', '[email protected]');

Method Routing

Route::any('/', function() {});
Route::get('/', function() {});
Route::post('/', function() {});
Route::put('/', function() {});
Route::patch('/', function() {});
Route::option('/', function() {});
Route::delete('/', function() {});

Parameters

// This example will match any page name
Route::get('/{page}', function($page) {
    return "you are in $page";
});

Route::get('/post/{id}', function($id) {
    // Will match anything like post/hello or post/5 ...
    // But not match /post/5/title
    return "post id $id";
});

// more than parameters
Route::get('/post/{id}/{title}', function($id, $title) {
    return "post id $id and title $title";
});

// you can get parameter in any order
Route::get('/post/{id}/{title}', function($title, $id) {
    return "post id $id and title $title";
});

For “unlimited” optional parameters, you can do this:

// This example will match anything after blog/ - unlimited arguments
Route::get('/blog/{any}:*', function($any) {
    pre($any);
});

Regular Expressions

You can validate the args by regular expressions.

// Validate args by regular expressions uses :(your pattern here)
Route::get('/{username}:([0-9a-z_.-]+)/post/{id}:([0-9]+)',
function($username, $id) {
    return "author $username post id $id";
});

// You can add named regex pattern in routes
Route::addPlaceholders([
    'username' => '([0-9a-z_.-]+)',
    'id' => '([0-9]+)'
]);

// Now you can use named regex
Route::get('/{username}:username/post/{id}:id', function($username, $id) {
    return "author $username post id $id";
});
//if the parameter name match the placeholder name just ignore placeholder and route will deduct that
Route::get('/{username}/post/{id}', function($username, $id) {
    return "author $username post id $id";
});

Some named regex patterns already registered in routes

[
    'int'               => '/([0-9]+)',
    'multiInt'          => '/([0-9,]+)',
    'title'             => '/([a-z_-]+)',
    'key'               => '/([a-z0-9_]+)',
    'multiKey'          => '/([a-z0-9_,]+)',
    'isoCode2'          => '/([a-z]{2})',
    'isoCode3'          => '/([a-z]{3})',
    'multiIsoCode2'     => '/([a-z,]{2,})',
    'multiIsoCode3'     => '/([a-z,]{3,})'
];

Optional parameters

You can specify named parameters that are optional for matching by adding (?)

Route::get('/post/{title}?:title/{date}?',
function($title, $date) {
    $content = '';
    if ($title) {
        $content = "<h1>$title</h1>";
    }else{
        $content =  "<h1>Posts List</h1>";
    }

    if ($date) {
        $content .= "<small>Published $date</small>";
    }
    return $content;

});

Groups

Route::group('/admin', function()
{
    // /admin/
    Route::get('/', function() {});
    // /admin/settings
    Route::get('/settings', function() {});
    // nested group
    Route::group('/users', function()
    {
        // /admin/users
        Route::get('/', function() {});
        // /admin/users/add
        Route::get('/add', function() {});
    });
    // Anything else
    Route::any('/{any}:*', function($any) {
        pre("Page ( $any ) Not Found", 6);
    });
});

Groups with parameters

Route::group('/{module}', function($lang)
{
    Route::post('/create', function() {});
    Route::put('/update', function() {});
});

Locales

// the first language is the default i.e. ar
// when you hit the site http://localhost on the first time will redirect to  http://localhost/ar
Route::locale(['ar','en'], function(){
    // will be /ar/
    Route::get('/', function($locale){
        //get current language
        pre($locale);
    });
    // /ar/contact
    Route::get('/contact', function() {});

    Route::group('/blog', function() {
        // /ar/blog/
        Route::get('/', function() {});
    });
});
// Also you can write locales like that or whatever you want
Route::locale(['ar-eg','en-us'], function(){
    // will be /ar/
    Route::get('/', function($locale){
        //get current language
        list($lang, $country) = explode('-', $locale, 2);
        pre("Lang is $lang, Country is $country");
    });
});

Auth

Basic

$auth = new \Just\Http\Auth\Basic(['users' => [
    'user1' => '123456',
    'user2' => '987654'
]]);
Route::auth($auth, function (){
    Route::get('/secret', function(\Just\Http\Request $req){
        pre("Hello {$req->user()->get('username')}, this is a secret page");
    });
});

Digest

$auth = new \Just\Http\Auth\Digest(['users' => [
    'user1' => '123456',
    'user2' => '987654'
]]);
Route::auth($auth, function (){
    Route::get('/secret', function(\Just\Http\Request $req){
        pre("Hello {$req->user()->get('username')}, this is a secret page");
    });
});

Middleware

Global

Route::use(function (\Just\Http\Request $req, $next){
    //validate something the call next to continue or return whatever if you want break 
    if($req->isMobile()){
        return 'Please open from a desktop';
    }
    
    return $next();
}, function ($next){
    // another middleware
    $next();
});

// After 
Route::use(function ($next){
    $response =  $next();
    // make some action
    return $response;
});

Middleware on groups

// if open from mobile device
Route::middleware(fn(\Just\Http\Request $req, $next) => !$req->isMobile() ? '' : $next())
    ->group('/mobile-only', function (){
        Route::get('/', function(\Just\Http\Request $req){
            pre($req->browser());
        });
    });

If you make the middleware as a class, you can pass the class with namespace. the class should be had a handle method.

class MobileOnly{
    public function handle(\Just\Http\Request $req, $next){
        return !$req->isMobile() ? '' : $next();
    }
}
Route::middleware(MobileOnly::class)
    ->group('/',function (){
        Route::get('/', function(\Just\Http\Request $req){
            pre($req->browser());
        });
    });

Middleware on route

Route::get('/', function(\Just\Http\Request $req){
    pre($req->browser());
})->middleware(MobileOnly::class);

Dependency injection

To learn about Dependency injection and service container please visit this link

Handle and Parser customization

Example of CustomRouteHandler

class CustomRouteHandler implements Just\Routing\RouteHandlerInterface
{
    public function call(callable $handler, array $args = [])
    {
        return call_user_func_array($handler, $args);
    }

    public function parse($handler): callable
    {
        if (is_string($handler) && ! function_exists($handler)) {
            $handler = explode('@', $handler, 2);
        }
        return $handler;
    }
}
\Just\Route::setHandler(new CustomRouteHandler);
class CustomRouteParser implements RouteParserInterface
{
    public function parse(string $uri): array
    {
        $matchedParameter = [];
        $matchedPattern = [];
        $result = [];
        // parse uri here and return array of 3 elements
        // /{page}
        // /{page}?

        return ['parameters' => $matchedParameter, 'patterns' => $matchedPattern, 'result' => $result];
    }
}
\Just\Route::setParser(new CustomRouteParser);
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].