Skip to content

Instantly share code, notes, and snippets.

@alandefreitas
Last active November 22, 2022 02:50
Show Gist options
  • Save alandefreitas/4557b118fd2a054126e3422ca370f7a2 to your computer and use it in GitHub Desktop.
Save alandefreitas/4557b118fd2a054126e3422ca370f7a2 to your computer and use it in GitHub Desktop.
A comparison of formats used by routers in web frameworks

Routers

Summary

Pattern Number of frameworks %
:id 23 57.5%
{id} 9 22.5%
<id> 5 12.5%
regex 2 0.50%
[id] 1 0.25%

Basic formats

Library Basic format
Expressjs /user/:id/:op?
Laravel /user/{id}/{op?}
Rails /user/:id(/:op)
Django /user/<str:id>/(?P<str>\w+)
Angular ['/user', user.id, user.op]
ASP.NET user/{id}/{op?}
Meteor /user/:id/:op?
Spring /user/:id/:op
PLAY /user/:id/:op?
Vue /user/:id/:op?
React.JS /user/:id(/:op)
Flask /user/<int:id>/<str:op>
Symfony /user/{id}/{op?}
jQuery /\/user\/([0-9]+)\/([\\w]+)/
Drupal /user/{id}/{op}
Ember /user/:id/:op
Fiber /user/:id/:op
CakePHP user/{id}/:op
Next.js user/[id]/[[...op]]
FastAPI user/{id}/{op}
Svelte /user/:id/:op
Blazor user/{id:int}/{op?}
Nuxt.js /user/:id/:op?
Phoenix /user/:id/:op
Fastify /user/:id/:op
Deno /user/:id/:op?
Preact /user/:id/:op?
LitElement /user/:id/:op?
Alpine.js /user/:id/:op?
Semantic UI /user/{id}/{op}
CherryPy user/{id}/{op}
Koa /user/:id/:op
Sails /user/:id/:op?
CodeIgniter /user/(:id)/(:op)
Deno user/{id}/{op?}
Mojolicious /user/:id/:op
Qt /user/<arg>/<arg>
Crow /user/<int>/<string>
Drogon /user/<id>/<op>
CppCMS /user/(\\d+)/(\\[a-z]+)

Notes:

  1. Many frameworks don't support optional path parameters. In that case, multiple routes should be created.
  2. CakePHP supports both {} and :

Segment Patterns

Expressjs Pattern Matches
:id match any
:id? match optional
ab?cd b is optional
ab+cd one or more b
ab*cd * matches anything
ab(cd)?e cd is optional
/a/ a is a regex
/.*fly$/ .*fly$ is a regex
Laravel Pattern Matches
{id} match any
{id?} match optional
Ruby on Rails Matches
:id match any
(/:op) match optional
Django Matches
<str:id> match any
(?P<str>\w+) match optional

Extra route constraints

Lavarel

Regex:

Route::get('/user/{name}', function ($name) {
    //
})->where('name', '[A-Za-z]+');

Registered constraints:

Route::get('/user/{id}/{name}', function ($id, $name) {
    //
})->whereNumber('id')->whereAlpha('name');

Named routes:

Route::get('/user/{id}/profile', function ($id) {
    //
})->name('profile');
// ...
$url = route('profile', ['id' => 1]);

Ruby on Rails

Regex:

get 'photos/:id', to: 'photos#show', constraints: { id: /[A-Z]\d{5}/ }

Django

Named routes:

urlpatterns = [
    path('', views.index, name='index'),
]

Angular

Regex:

{
  matcher: (url) => {
    if (url.length === 1 && url[0].path.match(/^@[\w]+$/gm)) {
      return {
        consumed: url,
        posParams: {
          username: new UrlSegment(url[0].path.slice(1), {})
        }
      };
    }

    return null;
  },
  component: ProfileComponent
}

PLAY

Regex:

GET   /items/$id<[0-9]+>    controllers.Items.show(id: Long)

Vuejs

Regex:

const routes = [
  // /:orderId -> matches only numbers
  { path: '/:orderId(\\d+)' },
  // /:productName -> matches anything else
  { path: '/:productName' },
]

Repeatable params:

const routes = [
  // /:chapters -> matches /one, /one/two, /one/two/three, etc
  { path: '/:chapters+' },
  // /:chapters -> matches /, /one, /one/two, /one/two/three, etc
  { path: '/:chapters*' },
]

Flask

Optional:

@user.route('/<user_id>', defaults={'username': None})
@user.route('/<user_id>/<username>')
def show(user_id, username):
    pass

CakePHP

CakePHP accepts both {} and :.

Regex:

// Using fluent interface
$routes->connect(
    '/articles/{id}',
    ['controller' => 'Articles', 'action' => 'view'],
)
->setPatterns(['id' => '\d+'])
->setPass(['id']);

Parameters in the same segment:

$routes->connect(
    '/blog/{id}-{slug}', // For example, /blog/3-CakePHP_Rocks
    ['controller' => 'Blogs', 'action' => 'view']
)

Fastify

Multiple params per segment:

fastify.get('/example/at/:hour(^\\d{2})h:minute(^\\d{2})m', function (request, reply) {
  // curl ${app-url}/example/at/08h24m
  // hour === "08"
  // minute === "24"
  const { hour, minute } = request.params;
  // your code here
})

CodeIgniter

Regex:

$routes->get('products/([a-z]+)/(\d+)', 'Products::show/$1/id_$2');

Qt

Param types:

QHttpServer server;
server.route("/blog/<arg>/<arg>", [] (int year, int month) {
    return blogs_by_year_and_month(year, month);
});

Implementation that matches route and callable parameters: https://github.com/qt-labs/qthttpserver/blob/983e93c3b160c62e60b1755d075e959d4685d949/src/httpserver/qhttpserver.h#L77-L87

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment