A Native JavaScript Route / Router Proposal

The new set of standard classes, such as URLPattern, Response, Request, and URL, has made me ponder what native Route/Router classes would look like. I’ve experimented with various server frameworks like Express, Oak, and Fresh, and have been contempla…

The new set of standard classes, such as URLPattern, Response, Request, and URL, has made me ponder what native Route/Router classes would look like. I’ve experimented with various server frameworks like Express, Oak, and Fresh, and have been contemplating what a server would look like from the perspective of WinterCG or Mozilla. Here’s a simple Route and Routes class that only matches on method and URL.

type Handler = (req: Request) => Promise<Response> | Response

export class Route {
  urlPattern: URLPattern
  constructor (
    public method: string,
    public pathname: string,
    public handler: Handler
  ) {
    this.urlPattern = new URLPattern({ pathname })
  }
  static get (pathname: string, handler: Handler) {
    return new Route("GET", pathname, handler)
  }
}

export class Routes {
  routes: Route[]
  constructor (...routes: Route[]) {
    this.routes = routes
  }
  async match (req: Request): Promise<Response> {
    const matches = this.routes.filter(route => {
      return route.urlPattern.test(req.url) && route.method === req.method
    })
    if (matches.length > 1) { 
      return new Response('internal error, more then one route with the same pathname')
    } else if (matches.length === 0) {
      return new Response('internal error, not found')
    } else {
      const response = await matches[0].handler(req)

      return response
    }
  }
}

This would allow you to do something like:

import { serve } from "https://deno.land/std@0.173.0/http/server.ts";

const routes = new Routes(
  Route.get('/elephant', () => Response.json('elephant')),
  Route.get('/monkey', () => Response.json('monkey')),
  Route.get('/racoon', () => Response.json('racoon')),
  Route.get('/bunny', () => Response.json('bunny')),
)

// To listen on port 4242.
serve((request) => {
  return routes.match(request)
}, { port: 4242 });

This has one issue: what if you want to match on other parts of the Request? This can become complicated quickly. Along with the standard URL and method, there are the header, query, body, and should a matcher match on the extracted, parsed body? If so, should the body also be validated within the Request object? To access the body, it is behind a promise. To match the body, you would need to know the type of body (e.g. form, XML, JSON) and then use a tool like zod to validate it. It’s not outlined here but I had created the idea of WrapedRequest that would cache the body within the instance of the WrapedRequest so that the promise is resolved once and passed to every Router for matching.

A more complex Route class could have all the matching criteria listed out as an array of options and requirements.

new RouteMatcher(
  method.get,
  oneOf(urlPattern('/elephant'), urlPattern('/elephant/:name')),
  oneOf([queryParam('name'), urlPattern('/elephant/:name'), header('x-name')]),
)

I like the concept of a simple Route/Router that can match against various criteria, and I wonder if others are also contemplating this idea. It certainly simplifies things to only match against the method and URL path.

I have been pondering the potential for a native Route/Router class that can match against a variety of criteria. I have been experimenting with different server frameworks and considering the design of a server from various perspectives. I propose that a simple Route and Routes class that can match on method and URL is a good starting point, but there is room for expansion to match on other criteria as well. I am curious to hear if others share this perspective and would like to open a discussion on this topic.


Print Share Comment Cite Upload Translate
APA
Thomas Reggi | Sciencx (2024-03-29T11:26:30+00:00) » A Native JavaScript Route / Router Proposal. Retrieved from https://www.scien.cx/2023/01/23/a-native-javascript-route-router-proposal/.
MLA
" » A Native JavaScript Route / Router Proposal." Thomas Reggi | Sciencx - Monday January 23, 2023, https://www.scien.cx/2023/01/23/a-native-javascript-route-router-proposal/
HARVARD
Thomas Reggi | Sciencx Monday January 23, 2023 » A Native JavaScript Route / Router Proposal., viewed 2024-03-29T11:26:30+00:00,<https://www.scien.cx/2023/01/23/a-native-javascript-route-router-proposal/>
VANCOUVER
Thomas Reggi | Sciencx - » A Native JavaScript Route / Router Proposal. [Internet]. [Accessed 2024-03-29T11:26:30+00:00]. Available from: https://www.scien.cx/2023/01/23/a-native-javascript-route-router-proposal/
CHICAGO
" » A Native JavaScript Route / Router Proposal." Thomas Reggi | Sciencx - Accessed 2024-03-29T11:26:30+00:00. https://www.scien.cx/2023/01/23/a-native-javascript-route-router-proposal/
IEEE
" » A Native JavaScript Route / Router Proposal." Thomas Reggi | Sciencx [Online]. Available: https://www.scien.cx/2023/01/23/a-native-javascript-route-router-proposal/. [Accessed: 2024-03-29T11:26:30+00:00]
rf:citation
» A Native JavaScript Route / Router Proposal | Thomas Reggi | Sciencx | https://www.scien.cx/2023/01/23/a-native-javascript-route-router-proposal/ | 2024-03-29T11:26:30+00:00
https://github.com/addpipe/simple-recorderjs-demo