How to Fix WiFi Extender Not Connecting to Internet

If your wifi extender not connect to Internet router, then you need to reset your extender. The location of the reset button in the extender may vary depending on the brand. The reset button will be present at the back of your extender and press it for 10 seconds using a needle. This will reset all the current settings and allows you to modify your extender to your wish.

Check to see if another similar network is available in your area using other devices such as phones, tablets, and laptops. To change the settings of your extender and router, you must first determine the IP address of your Wi-Fi router. Reboot your router and extender, and then rescan. Change the router and extender's passwords and usernames, and keep this information for future connections. 

Issue’s Netgear WiFi extender not connecting to internet

If your Netgear WiFi extender not connecting to internet, then one of the following is the reason behind this:

  1. The device is not properly configured for Netgear extender to use
  2. The software or hardware of the WiFi range extender is faulty. Due to this, the Netgear extender not connecting to the internet on Windows 7/8/10, Linux, Mac, or other operating systems.
  3. Cable connections are loose.
  4. Interference in the path of extenders & signals is another reason.
  5. The extender is placed in a dead zone.
  6. Poor or no connection status of your network adapter.
  7. The extender is showing an orange LED light.
  8. Outdated Netgear extender firmware.

Here is hope that you now know the factor causing WiFi connectivity problems. However, if all things are on good terms from your end, execute the steps outlined underneath to fix the issue.

Fix: Netgear WiFi Extender Not Connecting to Internet-

With no more ado, let’s start troubleshooting the problem-

  1. Place your WiFi extender away from interference-creating devices such as microwaves, Bluetooth devices, cordless phones, metal objects, mirrors, glasses, fish tanks, etc.
  2. Check the LED lights on your extender as well as the router. On the off chance that the power light is showing in red color, it signifies that your WiFi extender is not connecting to the router.
  3. A blinking orange LED light implies that the extender is connected to the router but there is no internet/WAN.
  4. Found no issue with the LED lights on the extender and router? Go for loose connections or plugins checking.
  5. Reboot your PC, modem, computer, laptop, extender, and router, and verify if it fixes the issue or not.
  6. If the error is still annoying you, log in to 
  7. Lastly, go for the Netgear extender reset. Just press the reset button on your device and restore all the default factory settings.

Still, Facing the Issue?

We all understand how frustrating it is – when your Netgear extender refuses to connect to the internet. However, it is all dependent on the situation that leads to this issue. Therefore, considering this, For any query, you can visit our website and also call our expert team they will guide you.  www.wirelessextendersetup.org   

wifi extender not connecting to internet netgear wifi range extender not connecting to internet netgear nighthawk wifi extender not connecting to internet
#wifi #internet #reset #usa #technology #extender #router #fixing 

Sheldon  Grant

Sheldon Grant

1669093687

How to Implement React Router in This Tutorial

Learn how to implement React Router in this tutorial.

React Router is a third party library created to solve the problem of routing in React app. It wraps around the browser history API and does the job of keeping your React application UI in sync with the browser’s URL.

There are two packages of React Router: react-router-dom for React and react-router-native for React Native. Since you’re learning about making web application, you only have to install react-router-dom:

npm install react-router-dom

There are 3 basic React Router components commonly used in minimal navigation, they are BrowserRouter, Route and Link. Let’s explore about BrowserRouter and Route first:

import { BrowserRouter as Router, Route } from 'react-router-dom'

class RouterNavigationSample extends React.Component {
  render() {
    return (
      <Router>
      <>
        <NavigationComponent />
        <Route exact path="/" component={Home} />
        <Route path="/about" component={About} />
      </>
      </Router>
    )
  }
}

The BrowserRouter, which is imported as Router, acts as the parent component that wraps all of your React component. It will intercept Browser request URL and match its path with the corresponding Route component. So if the browser URL is localhost:3000/about, the Router will take that information and than look for a Route component that has the path attribute of /about.

You will determine what will be rendered by adding the component attribute to Route.

In the sample above, an exact attribute is added to the default Route path (/), because without it, any route with / will also render the Home component, causing inconsistencies in the navigation.

The third component Link is used for navigation, replacing the regular <a> tag of HTML. This is because a regular HTML anchor tag will do a full refresh of the browser on click, which is not suited for React application. A React app only needs to update the URL, browser history and component rendered without any browser refresh:

import { Link } from "react-router-dom";

class NavigationComponent extends React.Component {
  render() {
    return (
      <>
        <ul>
          <li>
            <Link to="/">Home</Link>
          </li>
          <li>
            <Link to="/about">About page</Link>
          </li>
        </ul>
        <hr />
      </>
    );
  }
}

You can try a working demo here.

Note how you can use the previous and next button of the browser’s navigation bar, and the url is updated with subsequent navigation, without the browser loading. This is the power of React Router in action.

Making dynamic routing

You’ve seen how to create simple navigation using React Router, yet most web application require more advanced function than that. You probably need a dynamic routing, where you can put something like /user/:id, in which React needs to render something based on the value of :id.

Old links can also be dead and need to be redirected to new link.

Also, if the browser URL doesn’t match any existing route, you need to display a 404 page.

That’s why you need to learn about 2 more components, Switch and Redirect. Switch is a unique component that will render the first matching Route, then stop. To illustrate this example:

import { Route } from 'react-router'

<Route path="/about" component={About}/>
<Route path="/:user" component={User}/>
<Route component={NoMatch}/>

In the above code, a browser URL of /about will match all three routes, causing it all to be rendered and stacked below each other. Now by using the Switch component, React Router will render the About component route and then stop.

import {Switch, Route} from 'react-router';

<Switch>
  <Route path='/about' component={About} />
  <Route path='/:user' component={User} />
  <Route component={NoMatch} />
</Switch>;

The order of the Route component inside Switch is important, so make sure you declare all static route first before declaring routes with url parameter and 404 route.

Now for Redirect, the component is pretty simple. You only need to add from attribute that states the old URL and to attribute specifying the new URL to link to.

import {Redirect} from 'react-router';

<Redirect from='/old-match' to='/will-match' />;

Nested route

In order to create nested route, you need to declare another Route inside the parent component. For example, let’s say you have /users route that render to Users component.

Let’s do a little exercise. First, create an array of objects that store user data, the following will do:

const users = [
  {
    id: '1',
    name: 'Nathan',
    role: 'Web Developer',
  },
  {
    id: '2',
    name: 'Johnson',
    role: 'React Developer',
  },
  {
    id: '3',
    name: 'Alex',
    role: 'Ruby Developer',
  },
];

Now create a simple routing in the application:

class RouterNavigationSample extends React.Component {
  render() {
    return (
      <Router>
        <>
          <NavigationComponent />
          <Route exact path='/' component={Home} />
          <Route path='/about' component={About} />
          <Route path='/users' component={Users} />
        </>
      </Router>
    );
  }
}

The NavigationComponent is where you write the Link component for navigating the application:

class NavigationComponent extends React.Component {
  render() {
    return (
      <>
        <ul>
          <li>
            <Link to='/'>Home</Link>
          </li>
          <li>
            <Link to='/about'>About page</Link>
          </li>
          <li>
            <Link to='/users'>Users page</Link>
          </li>
        </ul>
        <hr />
      </>
    );
  }
}

It’s time to create components to render on specific routes. Home and About component will render a single div, while Users will have another Link and Route component.

Inside the Users component, you will render a list of users, with a nested route to individual user by its ID, like /users/:id:

const Home = () => {
  return <div>This is the home page</div>;
};

const About = () => {
  return <div>This is the about page</div>;
};

const Users = () => {
  return (
    <>
      <ul>
        {users.map(({name, id}) => (
          <li key={id}>
            <Link to={`/users/${id}`}>{name}</Link>
          </li>
        ))}
      </ul>
      <Route path='/users/:id' component={User} />
      <hr />
    </>
  );
};

There’s nothing new with this code. So you can write the User component now:

const User = ({match}) => {
  const user = users.find((user) => user.id === match.params.id);

  return (
    <div>
      Hello! I'm {user.name} and I'm a {user.role}
    </div>
  );
};

Now here is something new I haven’t told you about. Every time a component is rendered in a specific route, the component receive route props from React Router. There are 3 route props being passed down into component: match, location, history.

You can look at the props by opening the React Developer Tools and highlight the matching component route:

Route propsRoute props

(If you’re opening from Codesandbox, you can open the demo in a new separate window to enable React DevTool)

Notice how you add /:id URL parameter in the Users component nested route. This id is passed down to the User component through the match.params.id object property. If you passed the URL parameter as /:userId, it will be passed down as match.params.userId.

Now that you know about route props, let’s refactor Users component a bit:

const Users = ({ match }) => {
  return (
    <>
      <ul>
        {users.map(({ name, id }) => (
          <li key={id}>
            <Link to={`${match.url}/${id}`}>{name}</Link>
          </li>
        ))}
      </ul>
      <Route path={`${match.url}/:id`} component={User} />
      <hr />
    </>
  );
}

As always, here is a working demo.

Passing props to Route component

You might think that passing props into Route component is the same as passing into regular component:

<Route path="/about" component={About} user='Jelly'/>

Unfortunately, React Router doesn’t forward the props entered into Route component into the component props, so you have to use another method.

Fortunately, React Router provides a render attribute that accepts a function to be called when the URL locations matches. This props also receives the same route props as the component props:

<Route
  path="/about"
  render={props => <About {...props} admin="Bean" />}
/>

// the component
const About = props => {
  return <div>This is the about page {props.admin}</div>;
};

First, you take the given props from React Router and pass it into the component, so that the component can use match, location or history props if necessary. Then you add your own extra props into it. The example above use arbitrary admin props as example.

You can see the full code here.

Now you’ve learned about React Router, try to implement it for your React application!

Original article source at: https://sebhastian.com/

#react #router 

How to Implement React Router in This Tutorial
Lawrence  Lesch

Lawrence Lesch

1667834040

uWebSockets.js: μWebSockets for Node.js Back-ends

uWebSockets.js

Simple, secure1 & standards compliant2 web server for the most demanding3 of applications. Read more...

⚡ Simple performance

µWebSockets.js is an HTTP/WebSocket server for Node.js that runs 8.5x that of Fastify and at least 10x that of Socket.IO. It comes with both router and pub/sub support and is suited for extraordinary performance needs. Browse the documentation and see the main repo. There are tons of examples but here's the gist of it all:

/* Non-SSL is simply App() */
require('uWebSockets.js').SSLApp({

  /* There are more SSL options, cut for brevity */
  key_file_name: 'misc/key.pem',
  cert_file_name: 'misc/cert.pem',
  
}).ws('/*', {

  /* There are many common helper features */
  idleTimeout: 32,
  maxBackpressure: 1024,
  maxPayloadLength: 512,
  compression: DEDICATED_COMPRESSOR_3KB,

  /* For brevity we skip the other events (upgrade, open, ping, pong, close) */
  message: (ws, message, isBinary) => {
    /* You can do app.publish('sensors/home/temperature', '22C') kind of pub/sub as well */
    
    /* Here we echo the message back, using compression if available */
    let ok = ws.send(message, isBinary, true);
  }
  
}).get('/*', (res, req) => {

  /* It does Http as well */
  res.writeStatus('200 OK').writeHeader('IsExample', 'Yes').end('Hello there!');
  
}).listen(9001, (listenSocket) => {

  if (listenSocket) {
    console.log('Listening to port 9001');
  }
  
});

💪 Unfair advantage

Being written in native code directly targeting the Linux kernel makes it way faster than any JavaScript implementation.

Low latencies are key to customer satisfaction and your competitive edge. Run low latency services at a lower cost.

⚔️ Battle proven

We've been fully standards compliant with a perfect Autobahn|Testsuite score since 20162. µWebSockets powers many of the biggest crypto exchanges in the world, handling trade volumes of multiple billions of USD every day. If you trade crypto, chances are you do so via µWebSockets.

📦 Easily installed

We recommend, for simplicity installing with yarn add uWebSockets.js@uNetworking/uWebSockets.js#v20.10.0 or any such release.

Being an open source project, you are of course perfectly free to choose other ways of installation as you might prefer.

💼 Commercially supported

uNetworking AB is a Swedish consulting & contracting company dealing with anything related to µWebSockets; development, support and customer success.

Don't hesitate sending a mail if you're building something large, in need of advice or having other business inquiries in mind. We'll figure out what's best for both parties and make sure you're not stepping into one of the many common pitfalls.

Special thanks to BitMEX, Bitfinex, Google, Coinbase, Bitwyre and deepstreamHub for allowing the project itself to thrive on GitHub since 2016 - this project would not be possible without these beautiful companies.

⚙️ Gear up

If performance is of utter importance, you don't necessarily have to use JavaScript/Node.js but could write apps in C++ using µWebSockets directly. It works exactly the same way, and will offer the best performance for those highly demanding applications where scripting won't do.

🤝 Permissively licensed

Intellectual property, all rights reserved.

Where such explicit notice is given, source code is licensed Apache License 2.0 which is a permissive OSI-approved license with very few limitations. Modified "forks" should be of nothing but licensed source code, and be made available under another product name. If you're uncertain about any of this, please ask before assuming.

Download Details:

Author: uNetworking
Source Code: https://github.com/uNetworking/uWebSockets.js 
License: Apache-2.0 license

#typescript #javascript #nodejs #http #router 

uWebSockets.js: μWebSockets for Node.js Back-ends

Routing: The Routing Component Maps an HTTP Request

Routing Component

The Routing component maps an HTTP request to a set of configuration variables.

Getting Started

$ composer require symfony/routing
use App\Controller\BlogController;
use Symfony\Component\Routing\Generator\UrlGenerator;
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;

$route = new Route('/blog/{slug}', ['_controller' => BlogController::class]);
$routes = new RouteCollection();
$routes->add('blog_show', $route);

$context = new RequestContext();

// Routing can match routes with incoming requests
$matcher = new UrlMatcher($routes, $context);
$parameters = $matcher->match('/blog/lorem-ipsum');
// $parameters = [
//     '_controller' => 'App\Controller\BlogController',
//     'slug' => 'lorem-ipsum',
//     '_route' => 'blog_show'
// ]

// Routing can also generate URLs for a given route
$generator = new UrlGenerator($routes, $context);
$url = $generator->generate('blog_show', [
    'slug' => 'my-blog-post',
]);
// $url = '/blog/my-blog-post'

Resources

Download Details:

Author: symfony
Source Code: https://github.com/symfony/routing 
License: MIT license

#php #router #symfony 

Routing: The Routing Component Maps an HTTP Request
Hunter  Krajcik

Hunter Krajcik

1665160515

Stack_router: A Stack-based Routing Library using an indexedStack

Stack router

Stack routers use an IndexedStack to route between different widgets. They come with their own scaffolds, app bars and snack bars similarly to the ones provided by the core Flutter UI library.

Basic demo gif.

Usage

import 'package:stack_router/stack_router.dart';

class ExampleStackRoutes {
  static const String firstRoute = 'firstRoute';
  static const String secondRoute = 'secondRoute';
}

class Home extends StatelessWidget {
  const Home({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Material(
      child: StackRouter(
        initialRoute: ExampleStackRoutes.firstRoute,
        builder: (router) {
          return [
            StackRoute(
              route: ExampleStackRoutes.firstRoute,
              child: Center(
                child: ElevatedButton(
                  onPressed: () {
                    router.pushRoute(ExampleStackRoutes.secondRoute);
                  },
                  child: const Text(
                    "Go to second route",
                    style: TextStyle(color: Colors.white),
                  ),
                ),
              ),
            ),
            StackRoute(
              route: ExampleStackRoutes.secondRoute,
              child: StackRouterScaffold(
                appBar: const StackRouterAppBar(
                  title: Text("I'm a Title", style: TextStyle(fontSize: 24)),
                ),
                child: Container(
                  color: Colors.blue,
                  alignment: Alignment.center,
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      const Text(
                        "I'm the second route",
                        style: TextStyle(
                          color: Colors.white,
                        ),
                      ),
                      const Padding(padding: EdgeInsets.only(top: 16)),
                      ElevatedButton(
                        style: ButtonStyle(
                          backgroundColor:
                              MaterialStateProperty.all(Colors.white),
                        ),
                        onPressed: () {
                          router.showSnackBar(
                            snackBar: const StackRouterSnackBar(
                              title: Text(
                                "I'm a snackbar!",
                                style: TextStyle(color: Colors.white),
                              ),
                            ),
                          );
                        },
                        child: const Text(
                          "Show snack bar",
                          style: TextStyle(color: Colors.black),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ),
          ];
        },
      ),
    );
  }
}

In this example, the first route consists of a button that navigates to the second route using the router.pushRoute API when it is pressed.

The basic router APIs for navigating between routes are:

  • pushRoute(String route) - Push the given route onto the top of the navigation stack
  • popRoute([String? route]) - Pop the given route (defaults to the current route) from the navigation stack.

StackRouterActions

Similarly to Flutter Material's ScaffoldMessenger, any child under a StackRouterScaffold can manipulate the stack router using the StackRouterActions made available by an InheritedWidget.

This makes it easy to show snack bars and change routes from your current route.

class SecondRoute extends StatelessWidget {
  @override
  build(context) {
    return StackRouterScaffold(
      child: Center(
        child: ElevatedButton(
          style: ButtonStyle(
            backgroundColor:
                MaterialStateProperty.all(Colors.white),
          ),
          onPressed: () {
            StackRouterActions.of(context).showSnackBar(
              snackBar: const StackRouterSnackBar(
                title: Text(
                  "I'm a snackbar!",
                  style: TextStyle(color: Colors.white),
                ),
              ),
              actions: [
                TextButton(
                  child: Text('Go back'),
                  onPressed: () {
                    StackRouterActions.of(context).popRoute();
                  }
                )
              ]
            );
          },
          child: const Text(
            "Show snack bar",
            style: TextStyle(color: Colors.black),
          ),
        ),
      ),
    );
  }
}

Snack bars

Snack bars are queued per route and can can be shown or hidden with the router snack bar APIs:

  • showSnackBar({ required StackRouterSnackBar snackBar, String? route }) - Display a snack bar on the provided route (default is current route).
  • hideSnackBar({ String? route }) - Clear the current snack bar on the provided route (default is current route).
  • clearSnackBars({ String? route }) - Clear all snack bars from the given route (default is the current route).

In the following example, two snack bars are queued up on the current route when the button is pressed:

class SecondRoute extends StatelessWidget {
  @override
  build(context) {
    return StackRouterScaffold(
      child: Center(
        child: ElevatedButton(
          style: ButtonStyle(
            backgroundColor:
                MaterialStateProperty.all(Colors.white),
          ),
          onPressed: () {
            StackRouterActions.of(context).showSnackBar(
              snackBar: const StackRouterSnackBar(
                title: Text(
                  "I'm a snackbar!",
                  style: TextStyle(color: Colors.white),
                ),
              ),
            );
            StackRouterActions.of(context).showSnackBar(
              snackBar: const StackRouterSnackBar(
                title: Text(
                  "I'm another snackbar!",
                  style: TextStyle(color: Colors.white),
                ),
              ),
            );
          },
          child: const Text(
            "Show snack bar",
            style: TextStyle(color: Colors.black),
          ),
        ),
      ),
    );
  }
}

Snack bar demo gif.

You can also show snackbars on a different route than the current one:

class SecondRoute extends StatelessWidget {
  @override
  build(context) {
    return StackRouterScaffold(
      child: Center(
        child: ElevatedButton(
          style: ButtonStyle(
            backgroundColor:
                MaterialStateProperty.all(Colors.white),
          ),
          onPressed: () {
            StackRouterActions.of(context).showSnackBar(
              snackBar: const StackRouterSnackBar(
                title: Text(
                  "I'm a snackbar!",
                  style: TextStyle(color: Colors.white),
                ),
              ),
            );
            StackRouterActions.of(context).showSnackBar(
              snackBar: const StackRouterSnackBar(
                route: ExampleStackRoutes.firstRoute,
                title: Text(
                  "I'm a snackbar for another route!",
                  style: TextStyle(color: Colors.white),
                ),
              ),
            );
          },
          child: const Text(
            "Show snack bar",
            style: TextStyle(color: Colors.black),
          ),
        ),
      ),
    );
  }
}

Snack bar demo gif.

Persisted Routes

Stack routers pass the widgets specified in the routes list to an IndexedStack widget that chooses which route to display. Because routes are managed by an IndexedStack, it has some interesting properties like the ability to warm up and persist routes:

StackRoute(
  route: ExampleStackRoutes.secondRoute,
  persist: true,
  child: Center(
    child: const Text(
      "Second route",
      style: TextStyle(color: Colors.white),
    ),
  ),
);

By default, a route in the stack router is not built until it has been pushed on. All routes that have been pushed on are maintained in the StackRouter history and are persisted so that when you push on a second route and pop back to the first, it is still the same widget instance and has maintained all the temporal state like any form data or changes the user may have made to the route before navigating away.

If you want to warm up a particular route even before it has been navigated to, you can specify persist: true on the route so that it will optimistically build when the StackRouter is first instantiated. This is useful for routes in a flow that are likely to be navigated to and are slower to build because of network data requirements or deep build trees.

Building modal flows

Stack routers can be useful for building modal flows and wizards like those that are commonly seen on platforms like desktop web. To build modal flows with StackRouter, check out modal_stack_router.

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add stack_router

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  stack_router: ^1.3.3

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:stack_router/stack_router.dart';

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:stack_router/stack_router.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Stack Router Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(),
    );
  }
}

class ExampleStackRoutes {
  static const String firstRoute = 'firstRoute';
  static const String secondRoute = 'secondRoute';
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Material(
      child: StackRouter(
        initialRoute: ExampleStackRoutes.firstRoute,
        builder: (router) {
          return [
            StackRoute(
              route: ExampleStackRoutes.firstRoute,
              child: Center(
                child: ElevatedButton(
                  onPressed: () {
                    router.pushRoute(ExampleStackRoutes.secondRoute);
                  },
                  child: const Text(
                    "Go to second route",
                    style: TextStyle(color: Colors.white),
                  ),
                ),
              ),
            ),
            StackRoute(
              route: ExampleStackRoutes.secondRoute,
              child: StackRouterScaffold(
                appBar: const StackRouterAppBar(
                  title: Text("I'm a Title", style: TextStyle(fontSize: 24)),
                ),
                child: Container(
                  color: Colors.blue,
                  alignment: Alignment.center,
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      const Text(
                        "I'm the second route",
                        style: TextStyle(
                          color: Colors.white,
                        ),
                      ),
                      const Padding(padding: EdgeInsets.only(top: 16)),
                      ElevatedButton(
                        style: ButtonStyle(
                          backgroundColor:
                              MaterialStateProperty.all(Colors.white),
                        ),
                        onPressed: () {
                          router.showSnackBar(
                            snackBar: const StackRouterSnackBar(
                              title: Text(
                                "I'm a snackbar!",
                                style: TextStyle(color: Colors.white),
                              ),
                            ),
                          );
                        },
                        child: const Text(
                          "Show snack bar",
                          style: TextStyle(color: Colors.black),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ),
          ];
        },
      ),
    );
  }
}

Download Details:

Author: DanReynolds
Source Code: https://github.com/danReynolds/stack_router 
License: MIT license

#flutter #dart #stack #router 

Stack_router: A Stack-based Routing Library using an indexedStack

10 Popular Golang Libraries for Routers

In today's post we will learn about 10 Popular Golang Libraries for Routers.

What is a router?

A router is a device that connects two or more packet-switched networks or subnetworks. It serves two primary functions: managing traffic between these networks by forwarding data packets to their intended IP addresses, and allowing multiple devices to use the same Internet connection.

There are several types of routers, but most routers pass data between LANs (local area networks) and WANs (wide area networks). A LAN is a group of connected devices restricted to a specific geographic area. A LAN usually requires a single router.

A WAN, by contrast, is a large network spread out over a vast geographic area. Large organizations and companies that operate in multiple locations across the country, for instance, will need separate LANs for each location, which then connect to the other LANs to form a WAN. Because a WAN is distributed over a large area, it often necessitates multiple routers and switches*.

*A network switch forwards data packets between groups of devices in the same network, whereas a router forwards data between different networks.

Table of contents:

  • Alien - Lightweight and fast http router from outer space.
  • Bellt - A simple Go HTTP router.
  • Bone - Lightning Fast HTTP Multiplexer.
  • Bxog - Simple and fast HTTP router for Go. It works with routes of varying difficulty, length and nesting. And he knows how to create a URL from the received parameters.
  • Chi - Small, fast and expressive HTTP router built on net/context.
  • Fasthttprouter - High performance router forked from httprouter. The first router fit for fasthttp.
  • FastRouter - a fast, flexible HTTP router written in Go.
  • Goblin - A golang http router based on trie tree.
  • Gocraft/web - Mux and middleware package in Go.
  • Goji - Goji is a minimalistic and flexible HTTP request multiplexer with support for net/context.

1 - Alien:

Lightweight and fast http router from outer space.

Features

  • fast ( see the benchmarks, or run them yourself)
  • lightweight ( just a single file read all of it in less than a minute)
  • safe( designed with concurrency in mind)
  • middleware support.
  • routes groups
  • no external dependency( only the standard library )

Installation

go get github.com/gernest/alien

Usage

normal static routes

package main

import (
	"log"
	"net/http"

	"github.com/gernest/alien"
)

func main() {
	m := alien.New()
	m.Get("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("hello world"))
	})
	log.Fatal(http.ListenAndServe(":8090", m))
}

visiting your localhost at path / will print hello world

named params

package main

import (
	"log"
	"net/http"

	"github.com/gernest/alien"
)

func main() {
	m := alien.New()
	m.Get("/hello/:name", func(w http.ResponseWriter, r *http.Request) {
		p := alien.GetParams(r)
		w.Write([]byte(p.Get("name")))
	})
	log.Fatal(http.ListenAndServe(":8090", m))
}

visiting your localhost at path /hello/tanzania will print tanzania

View on Github

2 - Bellt:

A simple Go HTTP router.

Bellt Package implements a request router with the aim of managing controller actions based on fixed and parameterized routes.

The project so far has the following functionalities:

  • Standard definition of route "/health", in order to prepare the service developed with bellt to act as microservice.
  • Providing the creation of parameterized routes, simple or segmented (groups).
  • All requests can be made through fixed patterns, querystrings and parameters.
  • Obtaining the requisition parameters in the controller functions.

Install

To get Bellt

> Go CLI

go get -u github.com/GuilhermeCaruso/bellt

> Go DEP

dep ensure -add github.com/GuilhermeCaruso/bellt

> Govendor

govendor fetch github.com/GuilhermeCaruso/bellt

Guide

Router

To initialize our router

var router = bellt.NewRouter()
package main

import (
	"fmt"
	"log"
	"net/http"

	"github.com/GuilhermeCaruso/bellt"
)

func main() {
	router := bellt.NewRouter()

	log.Fatal(http.ListenAndServe(":8080", nil))
}

HandleFunc

HandleFunc function responsible for initializing a common route or built through the Router. All non-grouped routes must be initialized by this method.

/*
	[path] - Endpoint string
	[handlerFunc] - Function that will be called on the request
	[methods] - Slice for endpoint methods ("GET", "POST", "PUT", "DELETE")
*/

router.HandleFunc(path, handlerFunc, methods)
    
package main

import (
	"fmt"
	"log"
	"net/http"

	"github.com/GuilhermeCaruso/bellt"
)

func main() {
	router := bellt.NewRouter()

	router.HandleFunc("/bellt", belltHandler, "GET")

	log.Fatal(http.ListenAndServe(":8080", nil))
}

func belltHandle(w http.ResponseWriter, r *http.Request){
	w.WriteHeader(http.StatusOK)
	w.Write([]byte("Simple Golang HTTP router")
}

View on Github

3 - Bone:

Lightning Fast HTTP Multiplexer.

What is bone ?

Bone is a lightweight and lightning fast HTTP Multiplexer for Golang. It support :

  • URL Parameters
  • REGEX Parameters
  • Wildcard routes
  • Router Prefix
  • Route params validators
  • Sub Router, mux.SubRoute(), support most standard router (bone, gorilla/mux, httpRouter etc...)
  • Http method declaration
  • Support for http.Handler and http.HandlerFunc
  • Custom NotFound handler
  • Respect the Go standard http.Handler interface

Speed

- BenchmarkBoneMux        10000000               118 ns/op
- BenchmarkZeusMux          100000               144 ns/op
- BenchmarkHttpRouterMux  10000000               134 ns/op
- BenchmarkNetHttpMux      3000000               580 ns/op
- BenchmarkGorillaMux       300000              3333 ns/op
- BenchmarkGorillaPatMux   1000000              1889 ns/op

These tests are just for fun, all these routers are great and efficient. Bone isn't the fastest router for every job.

Example

package main

import(
  "net/http"

  "github.com/go-zoo/bone"
)

func main () {
  mux := bone.New()

  mux.RegisterValidatorFunc("isNum", func(s string) bool {
    if _, err := strconv.Atoi(s); err == nil {
      return true
    }
    return false
  })

  // mux.Get, Post, etc ... takes http.Handler
  // validator for route parameter
  mux.Get("/home/:id|isNum", http.HandlerFunc(HomeHandler))
  // multiple parameter
  mux.Get("/profil/:id/:var", http.HandlerFunc(ProfilHandler))
  mux.Post("/data", http.HandlerFunc(DataHandler))

  // Support REGEX Route params
  mux.Get("/index/#id^[0-9]$", http.HandlerFunc(IndexHandler))

  // Handle take http.Handler
  mux.Handle("/", http.HandlerFunc(RootHandler))

  // GetFunc, PostFunc etc ... takes http.HandlerFunc
  mux.GetFunc("/test", Handler)

  http.ListenAndServe(":8080", mux)
}

func Handler(rw http.ResponseWriter, req *http.Request) {
  // Get the value of the "id" parameters.
  val := bone.GetValue(req, "id")

  rw.Write([]byte(val))
}

View on Github

4 - Bxog:

Simple and fast HTTP router for Go. It works with routes of varying difficulty, length and nesting. And he knows how to create a URL from the received parameters.

Usage

An example of using the multiplexer:

package main

import (
	"io"
	"net/http"

	bx "github.com/claygod/Bxog"
)

// Handlers
func IHandler(w http.ResponseWriter, req *http.Request, r *bx.Router) {
	io.WriteString(w, "Welcome to Bxog!")
}
func THandler(w http.ResponseWriter, req *http.Request, r *bx.Router) {
	params := r.Params(req, "/abc/:par")
	io.WriteString(w, "Params:\n")
	io.WriteString(w, " 'par' -> "+params["par"]+"\n")
}
func PHandler(w http.ResponseWriter, req *http.Request, r *bx.Router) {
	// Getting parameters from URL
	params := r.Params(req, "country")
	io.WriteString(w, "Country:\n")
	io.WriteString(w, " 'name' -> "+params["name"]+"\n")
	io.WriteString(w, " 'capital' -> "+params["city"]+"\n")
	io.WriteString(w, " 'valuta' -> "+params["money"]+"\n")
	// Creating an URL string
	io.WriteString(w, "Creating an URL from the current route (This is an example of creating an another URL):\n")
	io.WriteString(w, r.Create("country", map[string]string{"name": "Russia", "city": "Moscow", "money": "rouble"}))
}

// Main
func main() {
	m := bx.New()
	m.Add("/", IHandler)
	m.Add("/abc/:par", THandler)
	m.Add("/country/:name/capital/:city/valuta/:money", PHandler).
		Id("country"). // For a convinience you can indicate a short ID
		Method("GET")  // It is not necessary to indicate the GET method here as the GET method is used by default but this way is used to set an allowed method
	m.Test()
	m.Start(":9999")
}

Click URLs:

Settings

Necessary changes in the configuration of the multiplexer can be made in the configuration file config.go

View on Github

5 - Chi:

Small, fast and expressive HTTP router built on net/context.

chi is a lightweight, idiomatic and composable router for building Go HTTP services. It's especially good at helping you write large REST API services that are kept maintainable as your project grows and changes. chi is built on the new context package introduced in Go 1.7 to handle signaling, cancelation and request-scoped values across a handler chain.

The focus of the project has been to seek out an elegant and comfortable design for writing REST API servers, written during the development of the Pressly API service that powers our public API service, which in turn powers all of our client-side applications.

The key considerations of chi's design are: project structure, maintainability, standard http handlers (stdlib-only), developer productivity, and deconstructing a large system into many small parts. The core router github.com/go-chi/chi is quite small (less than 1000 LOC), but we've also included some useful/optional subpackages: middleware, render and docgen. We hope you enjoy it too!

Install

go get -u github.com/go-chi/chi/v5

Examples

See _examples/ for a variety of examples.

As easy as:

package main

import (
	"net/http"

	"github.com/go-chi/chi/v5"
	"github.com/go-chi/chi/v5/middleware"
)

func main() {
	r := chi.NewRouter()
	r.Use(middleware.Logger)
	r.Get("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("welcome"))
	})
	http.ListenAndServe(":3000", r)
}

REST Preview:

Here is a little preview of how routing looks like with chi. Also take a look at the generated routing docs in JSON (routes.json) and in Markdown (routes.md).

I highly recommend reading the source of the examples listed above, they will show you all the features of chi and serve as a good form of documentation.

import (
  //...
  "context"
  "github.com/go-chi/chi/v5"
  "github.com/go-chi/chi/v5/middleware"
)

func main() {
  r := chi.NewRouter()

  // A good base middleware stack
  r.Use(middleware.RequestID)
  r.Use(middleware.RealIP)
  r.Use(middleware.Logger)
  r.Use(middleware.Recoverer)

  // Set a timeout value on the request context (ctx), that will signal
  // through ctx.Done() that the request has timed out and further
  // processing should be stopped.
  r.Use(middleware.Timeout(60 * time.Second))

  r.Get("/", func(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("hi"))
  })

  // RESTy routes for "articles" resource
  r.Route("/articles", func(r chi.Router) {
    r.With(paginate).Get("/", listArticles)                           // GET /articles
    r.With(paginate).Get("/{month}-{day}-{year}", listArticlesByDate) // GET /articles/01-16-2017

    r.Post("/", createArticle)                                        // POST /articles
    r.Get("/search", searchArticles)                                  // GET /articles/search

    // Regexp url parameters:
    r.Get("/{articleSlug:[a-z-]+}", getArticleBySlug)                // GET /articles/home-is-toronto

    // Subrouters:
    r.Route("/{articleID}", func(r chi.Router) {
      r.Use(ArticleCtx)
      r.Get("/", getArticle)                                          // GET /articles/123
      r.Put("/", updateArticle)                                       // PUT /articles/123
      r.Delete("/", deleteArticle)                                    // DELETE /articles/123
    })
  })

  // Mount the admin sub-router
  r.Mount("/admin", adminRouter())

  http.ListenAndServe(":3333", r)
}

func ArticleCtx(next http.Handler) http.Handler {
  return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    articleID := chi.URLParam(r, "articleID")
    article, err := dbGetArticle(articleID)
    if err != nil {
      http.Error(w, http.StatusText(404), 404)
      return
    }
    ctx := context.WithValue(r.Context(), "article", article)
    next.ServeHTTP(w, r.WithContext(ctx))
  })
}

func getArticle(w http.ResponseWriter, r *http.Request) {
  ctx := r.Context()
  article, ok := ctx.Value("article").(*Article)
  if !ok {
    http.Error(w, http.StatusText(422), 422)
    return
  }
  w.Write([]byte(fmt.Sprintf("title:%s", article.Title)))
}

// A completely separate router for administrator routes
func adminRouter() http.Handler {
  r := chi.NewRouter()
  r.Use(AdminOnly)
  r.Get("/", adminIndex)
  r.Get("/accounts", adminListAccounts)
  return r
}

func AdminOnly(next http.Handler) http.Handler {
  return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    ctx := r.Context()
    perm, ok := ctx.Value("acl.permission").(YourPermissionType)
    if !ok || !perm.IsAdmin() {
      http.Error(w, http.StatusText(403), 403)
      return
    }
    next.ServeHTTP(w, r)
  })
}

View on Github

6 - Fasthttprouter:

High performance router forked from httprouter. The first router fit for fasthttp.

FastHttpRouter is forked from httprouter which is a lightweight high performance HTTP request router (also called multiplexer or just mux for short) for fasthttp.

This router is optimized for high performance and a small memory footprint. It scales well even with very long paths and a large number of routes. A compressing dynamic trie (radix tree) structure is used for efficient matching.

License Related

  • The author of httprouter @julienschmidt did almost all the hard work of this router.
  • I respect the laws of open source. So LICENSE of httprouter is alway stay here: HttpRouterLicense.
  • What I do is just fit for fasthttp. I have no hope to build a huge but toxic go web framwork like iris.
  • I fork this repo is just because there is no router for fasthttp at that time. And fasthttprouter is the FIRST router for fasthttp.
  • fasthttprouter has been used in my online production and processes 17 million requests per day. It is fast and stable, so I decide to release a stable version.

Releases

  • [2016.10.24] v0.1.0 The first release version of fasthttprouter.

Usage

This is just a quick introduction, view the GoDoc for details:

Let's start with a trivial example:

package main

import (
	"fmt"
	"log"

	"github.com/buaazp/fasthttprouter"
	"github.com/valyala/fasthttp"
)

func Index(ctx *fasthttp.RequestCtx) {
	fmt.Fprint(ctx, "Welcome!\n")
}

func Hello(ctx *fasthttp.RequestCtx) {
	fmt.Fprintf(ctx, "hello, %s!\n", ctx.UserValue("name"))
}

func main() {
	router := fasthttprouter.New()
	router.GET("/", Index)
	router.GET("/hello/:name", Hello)

	log.Fatal(fasthttp.ListenAndServe(":8080", router.Handler))
}

Named parameters

As you can see, :name is a named parameter. The values are accessible via RequestCtx.UserValues. You can get the value of a parameter by using the ctx.UserValue("name").

Named parameters only match a single path segment:

Pattern: /user/:user

 /user/gordon              match
 /user/you                 match
 /user/gordon/profile      no match
 /user/                    no match

Note: Since this router has only explicit matches, you can not register static routes and parameters for the same path segment. For example you can not register the patterns /user/new and /user/:user for the same request method at the same time. The routing of different request methods is independent from each other.

Catch-All parameters

The second type are catch-all parameters and have the form *name. Like the name suggests, they match everything. Therefore they must always be at the end of the pattern:

Pattern: /src/*filepath

 /src/                     match
 /src/somefile.go          match
 /src/subdir/somefile.go   match

View on Github

7 - FastRouter:

A fast, flexible HTTP router written in Go.

FastRouter is a fast, flexible HTTP router written in Go.

FastRouter contains some customizable options, such as TrailingSlashesPolicy, PanicHandler, OptionsHandler, MethodNotAllowedHandler, NotFoundHandler and so on.

FastRouter also provides some useful features, such as grouping and middleware.

Features

Fast: See Go Web Framework Benchmark

Flexible: FastRouter provides some customizable options for you:

  • TrailingSlashesPolicy:
    • IgnoreTrailingSlashes: ignore trailing slashes.
    • AppendTrailingSlashes: append trailing slashes and redirect if request path is not end with '/'.
    • RemoveTrailingSlashes: remove trailing slashes and redirect if request path is end with '/'.
    • StrictTrailingSlashes: remove or append trailing slashes according to corresponding pattern.
  • PanicHandler
  • OptionsHandler
  • MethodNotAllowedHandler
  • NotFoundHandler

Compatible: FastRouter is an implementation of http.Handler, so it is compatible with third-party packages.

Middleware: Middleware is a chaining tool for chaining http.Handler, see Middleware.

Grouping: Grouping is an useful feature of FastRouter, it allows to nest and specify middleware of group, see Grouping.

Documentation

See Documentation for details.

View on Github

8 - Goblin:

A golang http router based on trie tree.

Features

  • Support Go1.19 >= 1.15
  • Easy to use
  • Lightweight
  • Fully compatible with net/http
  • No external dependencies
  • Support custom error handler
  • Support method-based routing
  • Support variables in URL paths
  • Support regexp route patterns
  • Support middlewares

Install

go get -u github.com/bmf-san/goblin

Usage

Method-based routing

Goblin supports method-based routing.

GET/POST/PUT/PATCH/DELETE/OPTIONS

You can define routing as follows.

r := goblin.NewRouter()

r.Methods(http.MethodGet).Handler(`/`, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "/")
})

r.Methods(http.MethodGet, http.MethodPost).Handler(`/methods`, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    if r.Method == http.MethodGet {
        fmt.Fprintf(w, "GET")
    }
    if r.Method == http.MethodPost {
        fmt.Fprintf(w, "POST")
    }
})

http.ListenAndServe(":9999", r)

Variables in URL paths

goblin supports variabled in URL paths.

r := goblin.NewRouter()

r.Methods(http.MethodGet).Handler(`/foo/:id`, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    id := goblin.GetParam(r.Context(), "id")
    fmt.Fprintf(w, "/foo/%v", id)
}))

r.Methods(http.MethodGet).Handler(`/foo/:name`, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    name := goblin.GetParam(r.Context(), "name")
    fmt.Fprintf(w, "/foo/%v", name)
}))

http.ListenAndServe(":9999", r)

If you use the named parameters without regular expression as in the above case, it is internally interpreted as a wildcard ((.+)) regular expression.

So :id is substantially defined as :id[(.+)] internaly.

Regexp route patterns

goblin support regexp route patterns.

:paramName[pattern]

r.Methods(http.MethodGet).Handler(`/foo/:id[^\d+$]`, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    id := goblin.GetParam(r.Context(), "id")
    fmt.Fprintf(w, "/foo/%v", id)
}))

View on Github

9 - Gocraft/web:

Mux and middleware package in Go.

gocraft/web is a Go mux and middleware package. We deal with casting and reflection so YOUR code can be statically typed. And we're fast.

Getting Started

From your GOPATH:

go get github.com/gocraft/web

Add a file server.go - for instance, src/myapp/server.go

package main

import (
	"github.com/gocraft/web"
	"fmt"
	"net/http"
	"strings"
)

type Context struct {
	HelloCount int
}

func (c *Context) SetHelloCount(rw web.ResponseWriter, req *web.Request, next web.NextMiddlewareFunc) {
	c.HelloCount = 3
	next(rw, req)
}

func (c *Context) SayHello(rw web.ResponseWriter, req *web.Request) {
	fmt.Fprint(rw, strings.Repeat("Hello ", c.HelloCount), "World!")
}

func main() {
	router := web.New(Context{}).                   // Create your router
		Middleware(web.LoggerMiddleware).           // Use some included middleware
		Middleware(web.ShowErrorsMiddleware).       // ...
		Middleware((*Context).SetHelloCount).       // Your own middleware!
		Get("/", (*Context).SayHello)               // Add a route
	http.ListenAndServe("localhost:3000", router)   // Start the server!
}

Run the server. It will be available on localhost:3000:

go run src/myapp/server.go

View on Github

10 - Goji:

Goji is a minimalistic and flexible HTTP request multiplexer with support for net/context.

Goji is a HTTP request multiplexer, similar to net/http.ServeMux. It compares incoming requests to a list of registered Patterns, and dispatches to the http.Handler that corresponds to the first matching Pattern. Goji also supports Middleware (composable shared functionality applied to every request) and uses the standard context package to store request-scoped values.

Quick Start

package main

import (
        "fmt"
        "net/http"

        "goji.io"
        "goji.io/pat"
)

func hello(w http.ResponseWriter, r *http.Request) {
        name := pat.Param(r, "name")
        fmt.Fprintf(w, "Hello, %s!", name)
}

func main() {
        mux := goji.NewMux()
        mux.HandleFunc(pat.Get("/hello/:name"), hello)

        http.ListenAndServe("localhost:8000", mux)
}

Please refer to Goji's GoDoc Documentation for a full API reference.

Stability

Goji's API was recently updated to use the new net/http and context integration, and is therefore some of its interfaces are in a state of flux. We don't expect any further changes to the API, and expect to be able to announce API stability soon. Goji is suitable for use in production.

Prior to Go 1.7, Goji promised API stability with a different API to the one that is offered today. The author broke this promise, and does not take this breach of trust lightly. While stability is obviously extremely important, the author and community have decided to follow the broader Go community in standardizing on the standard library copy of the context package.

Users of the old API can find that familiar API on the net-context branch. The author promises to maintain both the net-context branch and master for the forseeable future.

View on Github

Thank you for following this article.

Related videos:

Golang Web Routing and Golang Restful Web Design

#go #golang #router 

10 Popular Golang Libraries for Routers
Gordon  Taylor

Gordon Taylor

1661911380

The Suspense-friendly Minimalistic Sister Of React Router 4

Router Suspense

A suspense-friendly minimalistic sister of React Router.

npm i router-suspense

As of now, this is a very basic router that works in async-land.

Playing with Suspense

This router will work in React 15+. However, If you want to play around with suspense features, you'll need to enable suspense somehow. That means either building React yourself. Or, using this handy dandy starter we made.

https://github.com/palmerhq/react-suspense-starter

API

The API is basically the core of React Router 4.

<Router>

Exactly the same as RR4's <BrowserRouter>

  • children: React.ReactNode
import React from 'react';
import { unstable_createRoot as createRoot } from 'react-dom';
import { Router } from 'router-suspense';
import App from './App';

const root = createRoot(document.getElementById('app'));

const render = Comp => {
  root.render(
   <Router>
     <Comp />
   </Router>
  );
};

render(App);

<Route>

Render prop component to conditionally render based on the URL. If present, it uses ReactDOM.unstable_deferredUpdates to wait for any suspense jazz to happen on the next route before making the transition.

Route Props

  • render: ((props) => React.ReactNode): Passes history, location, match as a render prop. Only renders when path matches the current location.
  • path: string Path to match. Same as RR4.
  • exact: boolean = false Same as RR4.
import React from 'react'
import { Route, Link } from 'router-suspense'

export const Nav = () => (
  <nav>
    <Link to="/">Home</Link>
    <Link to="/dashboard">Dashboard</Link>
  </nav>
)

export const App = () => (
  <div>
    <nav>
     <Link to="/">Home</Link>
     <Link to="/dashboard">Dashboard</Link>
     <Link to="/user/123">User</Link>
    </nav>
    <Route path="/" exact render={() => <div>Home</div>} />
    <Route path="/dashboard" exact render={() => <div>Dashboard</div>} />
    <Route path="/user/:id" exact render={({ match }) => <div>User {match.params.id} </div>} />
  </div>
)

<Link>

Link works like React Router 4's. You give it a path, it renders an <a>, but does a client-side transition by calling history.push(path) under the hood.

  • to: string The relative path to link to
import React from 'react'
import { Link } from 'router-suspense'

export const Nav = () => (
  <nav>
    <Link to="/">Home</Link>
    <Link to="/dashboard">Dashboard</Link>
  </nav>
)

withRouter(Comp: Component)

A higher-order component that hooks into Router context. Same as RR4.

import React from 'react'
import { Link } from 'router-suspense'

const BackButton = ({ history }) => (
  <div>
    <button onClick={() => history.goBack()}>Back</button>
  </div>
)

export default withRouter(BackButton)

Inspiration

A lot of this code is taken straight from React Router and React Training's MiniRouter lecture.


Download Details:

Author: Palmerhq
Source Code: https://github.com/palmerhq/router-suspense 
License: MIT license

#javascript #router #react 

The Suspense-friendly Minimalistic Sister Of React Router 4
Lawrence  Lesch

Lawrence Lesch

1660993740

Koa-router: Router Middleware for Koa

koa-router    

Router middleware for koa

  • Express-style routing using app.get, app.put, app.post, etc.
  • Named URL parameters.
  • Named routes with URL generation.
  • Responds to OPTIONS requests with allowed methods.
  • Support for 405 Method Not Allowed and 501 Not Implemented.
  • Multiple route middleware.
  • Multiple routers.
  • Nestable routers.
  • ES7 async/await support.

Migrating to 7 / Koa 2

  • The API has changed to match the new promise-based middleware signature of koa 2. See the koa 2.x readme for more information.
  • Middleware is now always run in the order declared by .use() (or .get(), etc.), which matches Express 4 API.

Installation

Install using npm:

npm install koa-router

API Reference

Router ⏏

Kind: Exported class
 

new Router([opts])

Create a new router.

ParamTypeDescription
[opts]Object 
[opts.prefix]Stringprefix router paths

Example
Basic usage:

var Koa = require('koa');
var Router = require('koa-router');

var app = new Koa();
var router = new Router();

router.get('/', (ctx, next) => {
  // ctx.router available
});

app
  .use(router.routes())
  .use(router.allowedMethods());

 

router.get|put|post|patch|delete|del ⇒ Router

Create router.verb() methods, where verb is one of the HTTP verbs such as router.get() or router.post().

Match URL patterns to callback functions or controller actions using router.verb(), where verb is one of the HTTP verbs such as router.get() or router.post().

Additionaly, router.all() can be used to match against all methods.

router
  .get('/', (ctx, next) => {
    ctx.body = 'Hello World!';
  })
  .post('/users', (ctx, next) => {
    // ...
  })
  .put('/users/:id', (ctx, next) => {
    // ...
  })
  .del('/users/:id', (ctx, next) => {
    // ...
  })
  .all('/users/:id', (ctx, next) => {
    // ...
  });

When a route is matched, its path is available at ctx._matchedRoute and if named, the name is available at ctx._matchedRouteName

Route paths will be translated to regular expressions using path-to-regexp.

Query strings will not be considered when matching requests.

Named routes

Routes can optionally have names. This allows generation of URLs and easy renaming of URLs during development.

router.get('user', '/users/:id', (ctx, next) => {
 // ...
});

router.url('user', 3);
// => "/users/3"

Multiple middleware

Multiple middleware may be given:

router.get(
  '/users/:id',
  (ctx, next) => {
    return User.findOne(ctx.params.id).then(function(user) {
      ctx.user = user;
      next();
    });
  },
  ctx => {
    console.log(ctx.user);
    // => { id: 17, name: "Alex" }
  }
);

Nested routers

Nesting routers is supported:

var forums = new Router();
var posts = new Router();

posts.get('/', (ctx, next) => {...});
posts.get('/:pid', (ctx, next) => {...});
forums.use('/forums/:fid/posts', posts.routes(), posts.allowedMethods());

// responds to "/forums/123/posts" and "/forums/123/posts/123"
app.use(forums.routes());

Router prefixes

Route paths can be prefixed at the router level:

var router = new Router({
  prefix: '/users'
});

router.get('/', ...); // responds to "/users"
router.get('/:id', ...); // responds to "/users/:id"

URL parameters

Named route parameters are captured and added to ctx.params.

router.get('/:category/:title', (ctx, next) => {
  console.log(ctx.params);
  // => { category: 'programming', title: 'how-to-node' }
});

The path-to-regexp module is used to convert paths to regular expressions.

Kind: instance property of Router

ParamTypeDescription
pathString 
[middleware]functionroute middleware(s)
callbackfunctionroute callback

 

router.routes ⇒ function

Returns router middleware which dispatches a route matching the request.

Kind: instance property of Router
 

router.use([path], middleware) ⇒ Router

Use given middleware.

Middleware run in the order they are defined by .use(). They are invoked sequentially, requests start at the first middleware and work their way "down" the middleware stack.

Kind: instance method of Router

ParamType
[path]String
middlewarefunction
[...]function

Example

// session middleware will run before authorize
router
  .use(session())
  .use(authorize());

// use middleware only with given path
router.use('/users', userAuth());

// or with an array of paths
router.use(['/users', '/admin'], userAuth());

app.use(router.routes());

 

router.prefix(prefix) ⇒ Router

Set the path prefix for a Router instance that was already initialized.

Kind: instance method of Router

ParamType
prefixString

Example

router.prefix('/things/:thing_id')

 

router.allowedMethods([options]) ⇒ function

Returns separate middleware for responding to OPTIONS requests with an Allow header containing the allowed methods, as well as responding with 405 Method Not Allowed and 501 Not Implemented as appropriate.

Kind: instance method of Router

ParamTypeDescription
[options]Object 
[options.throw]Booleanthrow error instead of setting status and header
[options.notImplemented]functionthrow the returned value in place of the default NotImplemented error
[options.methodNotAllowed]functionthrow the returned value in place of the default MethodNotAllowed error

Example

var Koa = require('koa');
var Router = require('koa-router');

var app = new Koa();
var router = new Router();

app.use(router.routes());
app.use(router.allowedMethods());

Example with Boom

var Koa = require('koa');
var Router = require('koa-router');
var Boom = require('boom');

var app = new Koa();
var router = new Router();

app.use(router.routes());
app.use(router.allowedMethods({
  throw: true,
  notImplemented: () => new Boom.notImplemented(),
  methodNotAllowed: () => new Boom.methodNotAllowed()
}));

 

router.redirect(source, destination, [code]) ⇒ Router

Redirect source to destination URL with optional 30x status code.

Both source and destination can be route names.

router.redirect('/login', 'sign-in');

This is equivalent to:

router.all('/login', ctx => {
  ctx.redirect('/sign-in');
  ctx.status = 301;
});

Kind: instance method of Router

ParamTypeDescription
sourceStringURL or route name.
destinationStringURL or route name.
[code]NumberHTTP status code (default: 301).

 

router.route(name) ⇒ Layer | false

Lookup route with given name.

Kind: instance method of Router

ParamType
nameString

 

router.url(name, params, [options]) ⇒ String | Error

Generate URL for route. Takes a route name and map of named params.

Kind: instance method of Router

ParamTypeDescription
nameStringroute name
paramsObjecturl parameters
[options]Objectoptions parameter
[options.query]Object | Stringquery options

Example

router.get('user', '/users/:id', (ctx, next) => {
  // ...
});

router.url('user', 3);
// => "/users/3"

router.url('user', { id: 3 });
// => "/users/3"

router.use((ctx, next) => {
  // redirect to named route
  ctx.redirect(ctx.router.url('sign-in'));
})

router.url('user', { id: 3 }, { query: { limit: 1 } });
// => "/users/3?limit=1"

router.url('user', { id: 3 }, { query: "limit=1" });
// => "/users/3?limit=1"

 

router.param(param, middleware) ⇒ Router

Run middleware for named route parameters. Useful for auto-loading or validation.

Kind: instance method of Router

ParamType
paramString
middlewarefunction

Example

router
  .param('user', (id, ctx, next) => {
    ctx.user = users[id];
    if (!ctx.user) return ctx.status = 404;
    return next();
  })
  .get('/users/:user', ctx => {
    ctx.body = ctx.user;
  })
  .get('/users/:user/friends', ctx => {
    return ctx.user.getFriends().then(function(friends) {
      ctx.body = friends;
    });
  })
  // /users/3 => {"id": 3, "name": "Alex"}
  // /users/3/friends => [{"id": 4, "name": "TJ"}]

 

Router.url(path, params [, options]) ⇒ String

Generate URL from url pattern and given params.

Kind: static method of Router

ParamTypeDescription
pathStringurl pattern
paramsObjecturl parameters
[options]Objectoptions parameter
[options.query]Object | Stringquery options

Example

var url = Router.url('/users/:id', {id: 1});
// => "/users/1"

const url = Router.url('/users/:id', {id: 1}, {query: { active: true }});
// => "/users/1?active=true"

Contributing

Please submit all issues and pull requests to the alexmingoia/koa-router repository!

Tests

Run tests using npm test.

Support

If you have any problem or suggestion please open an issue here.

Download Details:

Author: ZijianHe
Source Code: https://github.com/ZijianHe/koa-router 
License: MIT license

#javascript #router #middleware 

Koa-router: Router Middleware for Koa
Gordon  Taylor

Gordon Taylor

1660721220

Find-my-way: A Crazy Fast HTTP Router

find-my-way  

A crazy fast HTTP router, internally uses an highly performant Radix Tree (aka compact Prefix Tree), supports route params, wildcards, and it's framework independent.

If you want to see a benchmark comparison with the most commonly used routers, see here.
Do you need a real-world example that uses this router? Check out Fastify or Restify.

Install

npm i find-my-way --save

Usage

const http = require('http')
const router = require('find-my-way')()

router.on('GET', '/', (req, res, params) => {
  res.end('{"message":"hello world"}')
})

const server = http.createServer((req, res) => {
  router.lookup(req, res)
})

server.listen(3000, err => {
  if (err) throw err
  console.log('Server listening on: http://localhost:3000')
})

 

API

 

FindMyWay([options])

Instance a new router.
You can pass a default route with the option defaultRoute.

const router = require('find-my-way')({
  defaultRoute: (req, res) => {
    res.statusCode = 404
    res.end()
  }
})

In case of a badly formatted url (eg: /hello/%world), by default find-my-way will invoke the defaultRoute, unless you specify the onBadUrl option:

const router = require('find-my-way')({
  onBadUrl: (path, req, res) => {
    res.statusCode = 400
    res.end(`Bad path: ${path}`)
  }
})

Trailing slashes can be ignored by supplying the ignoreTrailingSlash option:

const router = require('find-my-way')({
  ignoreTrailingSlash: true
})
function handler (req, res, params) {
  res.end('foo')
}
// maps "/foo/" and "/foo" to `handler`
router.on('GET', '/foo/', handler)

Duplicate slashes can be ignored by supplying the ignoreDuplicateSlashes option:

const router = require('find-my-way')({
  ignoreDuplicateSlashes: true
})
function handler (req, res, params) {
  res.end('foo')
}
// maps "/foo", "//foo", "///foo", etc to `handler`
router.on('GET', '////foo', handler)

Note that when ignoreTrailingSlash and ignoreDuplicateSlashes are both set to true, duplicate slashes will first be removed and then trailing slashes will, meaning //a//b//c// will be converted to /a/b/c.

You can set a custom length for parameters in parametric (standard, regex and multi) routes by using maxParamLength option, the default value is 100 characters.
If the maximum length limit is reached, the default route will be invoked.

const router = require('find-my-way')({
  maxParamLength: 500
})

If you are using a regex based route, find-my-way will throw an error if detects potentially catastrophic exponential-time regular expressions (internally uses safe-regex2).
If you want to disable this behavior, pass the option allowUnsafeRegex.

const router = require('find-my-way')({
  allowUnsafeRegex: true
})

According to RFC3986, find-my-way is case sensitive by default. You can disable this by setting the caseSensitive option to false: in that case, all paths will be matched as lowercase, but the route parameters or wildcards will maintain their original letter casing. You can turn off case sensitivity with:

const router = require('find-my-way')({
  caseSensitive: false
})

The default query string parser that find-my-way uses is the Node.js's core querystring module. You can change this default setting by passing the option querystringParser and use a custom one, such as qs.

const qs = require('qs')
const router = require('find-my-way')({
  querystringParser: str => qs.parse(str)
})

router.on('GET', '/', (req, res, params, store, searchParams) => {
  assert.equal(searchParams, { foo: 'bar', baz: 'faz' })
})

router.lookup({ method: 'GET', url: '/?foo=bar&baz=faz' }, null)

You can assign a buildPrettyMeta function to sanitize a route's store object to use with the prettyPrint functions. This function should accept a single object and return an object.


const privateKey = new Symbol('private key')
const store = { token: '12345', [privateKey]: 'private value' }

const router = require('find-my-way')({
  buildPrettyMeta: route => {
    const cleanMeta = Object.assign({}, route.store)

    // remove private properties
    Object.keys(cleanMeta).forEach(k => {
      if (typeof k === 'symbol') delete cleanMeta[k]
    })

    return cleanMeta // this will show up in the pretty print output!
  }
})

store[privateKey] = 'private value'
router.on('GET', '/hello_world', (req, res) => {}, store)

router.prettyPrint()

//└── / (-)
//    └── hello_world (GET)
//        • (token) "12345"

Constraints

find-my-way supports restricting handlers to only match certain requests for the same path. This can be used to support different versions of the same route that conform to a semver based versioning strategy, or restricting some routes to only be available on hosts. find-my-way has the semver based versioning strategy and a regex based hostname constraint strategy built in.

To constrain a route to only match sometimes, pass constraints to the route options when registering the route:

findMyWay.on('GET', '/', { constraints: { version: '1.0.2' } }, (req, res) => {
  // will only run when the request's Accept-Version header asks for a version semver compatible with 1.0.2, like 1.x, or 1.0.x.
})

findMyWay.on('GET', '/', { constraints: { host: 'example.com' } }, (req, res) => {
  // will only run when the request's Host header is `example.com`
})

Constraints can be combined, and route handlers will only match if all of the constraints for the handler match the request. find-my-way does a boolean AND with each route constraint, not an OR.

find-my-way will try to match the most constrained handlers first before handler with fewer or no constraints.

 

Custom Constraint Strategies

Custom constraining strategies can be added and are matched against incoming requests while trying to maintain find-my-way's high performance. To register a new type of constraint, you must add a new constraint strategy that knows how to match values to handlers, and that knows how to get the constraint value from a request. Register strategies when constructing a router or use the addConstraintStrategy method.

Add a custom constrain strategy when constructing a router:

const customResponseTypeStrategy = {
  // strategy name for referencing in the route handler `constraints` options
  name: 'accept',
  // storage factory for storing routes in the find-my-way route tree
  storage: function () {
    let handlers = {}
    return {
      get: (type) => { return handlers[type] || null },
      set: (type, store) => { handlers[type] = store }
    }
  },
  // function to get the value of the constraint from each incoming request
  deriveConstraint: (req, ctx) => {
    return req.headers['accept']
  },
  // optional flag marking if handlers without constraints can match requests that have a value for this constraint
  mustMatchWhenDerived: true
}

const router = FindMyWay({ constraints: { accept: customResponseTypeStrategy } });

Add a custom constraint strategy using the addConstraintStrategy method:

const customResponseTypeStrategy = {
  // strategy name for referencing in the route handler `constraints` options
  name: 'accept',
  // storage factory for storing routes in the find-my-way route tree
  storage: function () {
    let handlers = {}
    return {
      get: (type) => { return handlers[type] || null },
      set: (type, store) => { handlers[type] = store }
    }
  },
  // function to get the value of the constraint from each incoming request
  deriveConstraint: (req, ctx) => {
    return req.headers['accept']
  },
  // optional flag marking if handlers without constraints can match requests that have a value for this constraint
  mustMatchWhenDerived: true
}

const router = FindMyWay();
router.addConstraintStrategy(customResponseTypeStrategy);

Once a custom constraint strategy is registered, routes can be added that are constrained using it:

findMyWay.on('GET', '/', { constraints: { accept: 'application/fancy+json' } }, (req, res) => {
  // will only run when the request's Accept header asks for 'application/fancy+json'
})

findMyWay.on('GET', '/', { constraints: { accept: 'application/fancy+xml' } }, (req, res) => {
  // will only run when the request's Accept header asks for 'application/fancy+xml'
})

Constraint strategies should be careful to make the deriveConstraint function performant as it is run for every request matched by the router. See the lib/strategies directory for examples of the built in constraint strategies.

By default, find-my-way uses a built in strategies for the version constraint that uses semantic version based matching logic, which is detailed below. It is possible to define an alternative strategy:

const customVersioning = {
  // replace the built in version strategy
  name: 'version',
  // provide a storage factory to store handlers in a simple way
  storage: function () {
    let versions = {}
    return {
      get: (version) => { return versions[version] || null },
      set: (version, store) => { versions[version] = store }
    }
  },
  deriveConstraint: (req, ctx) => {
    return req.headers['accept']
  },
  mustMatchWhenDerived: true // if the request is asking for a version, don't match un-version-constrained handlers
}

const router = FindMyWay({ constraints: { version: customVersioning } });

The custom strategy object should contain next properties:

  • storage - a factory function to store lists of handlers for each possible constraint value. The storage object can use domain-specific storage mechanisms to store handlers in a way that makes sense for the constraint at hand. See lib/strategies for examples, like the version constraint strategy that matches using semantic versions, or the host strategy that allows both exact and regex host constraints.
  • deriveConstraint - the function to determine the value of this constraint given a request

The signature of the functions and objects must match the one from the example above.

Please, be aware, if you use your own constraining strategy - you use it on your own risk. This can lead both to the performance degradation and bugs which are not related to find-my-way itself!

 

on(method, path, [opts], handler, [store])

Register a new route.

router.on('GET', '/example', (req, res, params, store, searchParams) => {
  // your code
})

Last argument, store is used to pass an object that you can access later inside the handler function. If needed, store can be updated.

router.on('GET', '/example', (req, res, params, store) => {
  assert.equal(store, { message: 'hello world' })
}, { message: 'hello world' })

Versioned routes

If needed, you can provide a version route constraint, which will allow you to declare multiple versions of the same route that are used selectively when requests ask for different version using the Accept-Version header. This is useful if you want to support several different behaviours for a given route and different clients select among them.

If you never configure a versioned route, the 'Accept-Version' header will be ignored. Remember to set a Vary header in your responses with the value you are using for defining the versioning (e.g.: 'Accept-Version'), to prevent cache poisoning attacks. You can also configure this as part your Proxy/CDN.

default

The default versioning strategy follows the semver specification. When using lookup, find-my-way will automatically detect the Accept-Version header and route the request accordingly. Internally find-my-way uses the semver-store to get the correct version of the route; advanced ranges and pre-releases currently are not supported.

Be aware that using this feature will cause a degradation of the overall performances of the router.

router.on('GET', '/example', { constraints: { version: '1.2.0' }}, (req, res, params) => {
  res.end('Hello from 1.2.0!')
})

router.on('GET', '/example', { constraints: { version: '2.4.0' }}, (req, res, params) => {
  res.end('Hello from 2.4.0!')
})

// The 'Accept-Version' header could be '1.2.0' as well as '*', '2.x' or '2.4.x'

If you declare multiple versions with the same major or minor find-my-way will always choose the highest compatible with the Accept-Version header value.

custom

It's also possible to define a custom versioning strategy during the find-my-way initialization. In this case the logic of matching the request to the specific handler depends on the versioning strategy you use.

on(methods[], path, [opts], handler, [store])

Register a new route for each method specified in the methods array. It comes handy when you need to declare multiple routes with the same handler but different methods.

router.on(['GET', 'POST'], '/example', (req, res, params) => {
  // your code
})

 

Supported path formats

To register a parametric path, use the colon before the parameter name. For wildcard use the star. Remember that static routes are always inserted before parametric and wildcard.

// parametric
router.on('GET', '/example/:userId', (req, res, params) => {}))
router.on('GET', '/example/:userId/:secretToken', (req, res, params) => {}))

// wildcard
router.on('GET', '/example/*', (req, res, params) => {}))

Regular expression routes are supported as well, but pay attention, RegExp are very expensive in term of performance!
If you want to declare a regular expression route, you must put the regular expression inside round parenthesis after the parameter name.

// parametric with regexp
router.on('GET', '/example/:file(^\\d+).png', () => {}))

It's possible to define more than one parameter within the same couple of slash ("/"). Such as:

router.on('GET', '/example/near/:lat-:lng/radius/:r', (req, res, params) => {}))

Remember in this case to use the dash ("-") as parameters separator.

Finally it's possible to have multiple parameters with RegExp.

router.on('GET', '/example/at/:hour(^\\d{2})h:minute(^\\d{2})m', (req, res, params) => {}))

In this case as parameter separator it's possible to use whatever character is not matched by the regular expression.

The last parameter can be made optional if you add a question mark ("?") at the end of the parameters name.

router.on('GET', '/example/posts/:id?', (req, res, params) => {}))

In this case you can request /example/posts as well as /example/posts/1. The optional param will be undefined if not specified.

Having a route with multiple parameters may affect negatively the performance, so prefer single parameter approach whenever possible, especially on routes which are on the hot path of your application.

Note that you must encode the parameters containing reserved characters.

 

Match order

The routing algorithm matches one chunk at a time (where the chunk is a string between two slashes), this means that it cannot know if a route is static or dynamic until it finishes to match the URL.

The chunks are matched in the following order:

  1. static
  2. parametric
  3. wildcards
  4. parametric(regex)
  5. multi parametric(regex)

So if you declare the following routes

  • /:userId/foo/bar
  • /33/:a(^.*$)/:b

and the URL of the incoming request is /33/foo/bar, the second route will be matched because the first chunk (33) matches the static chunk. If the URL would have been /32/foo/bar, the first route would have been matched. Once a url has been matched, find-my-way will figure out which handler registered for that path matches the request if there are any constraints. find-my-way will check the most constrained handlers first, which means the handlers with the most keys in the constraints object.

If you just want a path containing a colon without declaring a parameter, use a double colon. For example, /name::customVerb will be interpreted as /name:customVerb

Supported methods

The router is able to route all HTTP methods defined by http core module.

off(method, path)

Deregister a route.

router.off('GET', '/example')
// => { handler: Function, params: Object, store: Object}
// => null

off(methods[], path)

Deregister a route for each method specified in the methods array. It comes handy when you need to deregister multiple routes with the same path but different methods.

router.off(['GET', 'POST'], '/example')
// => [{ handler: Function, params: Object, store: Object}]
// => null

off(methods, path, [constraints])

Deregister a route for each constraints key is matched, containing keys like the host for the request, the version for the route to be matched, or other custom constraint values. See the constraints section to know more.

router.off('GET', '/example', { host: 'fastify.io' })
// => [{ handler: Function, params: Object, store: Object}]
// => null

reset()

Empty router.

router.reset()

Caveats

  • It's not possible to register two routes which differs only for their parameters, because internally they would be seen as the same route. In a such case you'll get an early error during the route registration phase. An example is worth thousand words: ```js const findMyWay = FindMyWay({ defaultRoute: (req, res) => {} })

findMyWay.on('GET', '/user/:userId(^\d+)', (req, res, params) => {})

findMyWay.on('GET', '/user/:username(^[a-z]+)', (req, res, params) => {}) // Method 'GET' already declared for route ':'


<a name="shorthand-methods"></a>
##### Shorthand methods
If you want an even nicer api, you can also use the shorthand methods to declare your routes.

For each HTTP supported method, there's the shorthand method. For example:
```js
router.get(path, handler [, store])
router.delete(path, handler [, store])
router.head(path, handler [, store])
router.patch(path, handler [, store])
router.post(path, handler [, store])
router.put(path, handler [, store])
router.options(path, handler [, store])
// ...

If you need a route that supports all methods you can use the all api.

router.all(path, handler [, store])

lookup(request, response, [context])

Start a new search, request and response are the server req/res objects.
If a route is found it will automatically call the handler, otherwise the default route will be called.
The url is sanitized internally, all the parameters and wildcards are decoded automatically.

router.lookup(req, res)

lookup accepts an optional context which will be the value of this when executing a handler

router.on('GET', '*', function(req, res) {
  res.end(this.greeting);
})
router.lookup(req, res, { greeting: 'Hello, World!' })

find(method, path, [constraints])

Return (if present) the route registered in method:path.
The path must be sanitized, all the parameters and wildcards are decoded automatically.
An object with routing constraints should usually be passed as constraints, containing keys like the host for the request, the version for the route to be matched, or other custom constraint values. If the router is using the default versioning strategy, the version value should be conform to the semver specification. If you want to use the existing constraint strategies to derive the constraint values from an incoming request, use lookup instead of find. If no value is passed for constraints, the router won't match any constrained routes. If using constrained routes, passing undefined for the constraints leads to undefined behavior and should be avoided.

router.find('GET', '/example', { host: 'fastify.io' })
// => { handler: Function, params: Object, store: Object}
// => null

router.find('GET', '/example', { host: 'fastify.io', version: '1.x' })
// => { handler: Function, params: Object, store: Object}
// => null

prettyPrint([{ commonPrefix: false, includeMeta: true || [] }])

Prints the representation of the internal radix tree, useful for debugging.

findMyWay.on('GET', '/test', () => {})
findMyWay.on('GET', '/test/hello', () => {})
findMyWay.on('GET', '/testing', () => {})
findMyWay.on('GET', '/testing/:param', () => {})
findMyWay.on('PUT', '/update', () => {})

console.log(findMyWay.prettyPrint())
// └── /
//     ├── test (GET)
//     │   ├── /hello (GET)
//     │   └── ing (GET)
//     │       └── /:param (GET)
//     └── update (PUT)

prettyPrint accepts an optional setting to use the internal routes array to render the tree.

console.log(findMyWay.prettyPrint({ commonPrefix: false }))
// └── / (-)
//     ├── test (GET)
//     │   └── /hello (GET)
//     ├── testing (GET)
//     │   └── /:param (GET)
//     └── update (PUT)

To include a display of the store data passed to individual routes, the option includeMeta may be passed. If set to true all items will be displayed, this can also be set to an array specifying which keys (if present) should be displayed. This information can be further sanitized by specifying a buildPrettyMeta function which consumes and returns an object.

findMyWay.on('GET', '/test', () => {}, { onRequest: () => {}, authIDs => [1,2,3] })
findMyWay.on('GET', '/test/hello', () => {}, { token: 'df123-4567' })
findMyWay.on('GET', '/testing', () => {})
findMyWay.on('GET', '/testing/:param', () => {})
findMyWay.on('PUT', '/update', () => {})

console.log(findMyWay.prettyPrint({ commonPrefix: false, includeMeta: ['onRequest'] }))
// └── /
//     ├── test (GET)
//     │   • (onRequest) "anonymous()"
//     │   ├── /hello (GET)
//     │   └── ing (GET)
//     │       └── /:param (GET)
//     └── update (PUT)

console.log(findMyWay.prettyPrint({ commonPrefix: true, includeMeta: true }))
// └── / (-)
//     ├── test (GET)
//     │   • (onRequest) "anonymous()"
//     │   • (authIDs) [1,2,3]
//     │   └── /hello (GET)
//     │       • (token) "df123-4567"
//     ├── testing (GET)
//     │   └── /:param (GET)
//     └── update (PUT)

routes

Return the all routes registered at moment, useful for debugging.

const findMyWay = require('find-my-way')()

findMyWay.on('GET', '/test', () => {})
findMyWay.on('GET', '/test/hello', () => {})

console.log(findMyWay.routes)
// Will print
// [
//   {
//     method: 'GET',
//     path: '/test',
//     opts: {},
//     handler: [Function],
//     store: undefined
//   },
//   {
//     method: 'GET',
//     path: '/test/hello',
//     opts: {},
//     handler: [Function],
//     store: undefined
//   }
// ]

Acknowledgements

It is inspired by the echo router, some parts have been extracted from trekjs router.

Past sponsor

Download Details:

Author: Delvedor
Source Code: https://github.com/delvedor/find-my-way 
License: MIT license

#javascript #http #router 

Find-my-way: A Crazy Fast HTTP Router
Reid  Rohan

Reid Rohan

1660618260

Trouter: A Fast, Small-but-mighty, Familiar Fish...errr, Router

trouter

🐟 A fast, small-but-mighty, familiar fish router

Install

$ npm install --save trouter

Usage

import Trouter from 'trouter';

const router = new Trouter();

// Define all routes
router
  .get('/users', _ => {
    console.log('> Getting all users');
  })
  .add('POST', '/users', _ => {
    console.log('~> Adding a user');
  })
  .get('/users/:id', val => {
    console.log('~> Getting user with ID:', val);
  });

// Find a route definition
let obj = router.find('GET', '/users/123');
//=> obj.params ~> { id:123 }
//=> obj.handlers ~> Array<Function>

// Execute the handlers, passing value
obj.handlers.forEach(fn => {
  fn(obj.params.id);
});
//=> ~> Getting user with ID: 123

// Returns empty keys when no match
router.find('DELETE', '/foo');
//=> { params:{}, handlers:[] }

API

Trouter()

Initializes a new Trouter instance.

trouter.add(method, pattern, ...handlers)

Returns: self

Stores a method + pattern pairing internally, along with its handler(s).

method

Type: String

Any uppercased, valid HTTP/1.1 verb — choose from one of the following:

GET  HEAD  PATCH  OPTIONS  CONNECT  DELETE  TRACE  POST  PUT

pattern

Type: String or RegExp

Trouter supports simple route patterns which are fast and well readable but limited. If you need more complex patterns, you can pass an instance of RegExp with parameters specified as named capture groups.

Important: RegExp named capture groups are supported in Node.js 10.x and above!

The supported route pattern types are:

  • static (/users)
  • named parameters (/users/:id)
  • nested parameters (/users/:id/books/:title)
  • optional parameters (/users/:id?/books/:title?)
  • suffixed parameters (/movies/:title.mp4, movies/:title.(mp4|mov))
  • any match / wildcards (/users/*)

...handlers

Type: Function

The function(s) that should be tied to this pattern.

Because this is a rest parameter, whatever you pass will always be cast to an Array.

Important: Trouter does not care what your function signature looks like!
You are not bound to the (req, res) standard, or even passing a Function at all!

trouter.use(pattern, ...handlers)

Returns: self

This is an alias for trouter.add('', pattern, ...handlers), matching all HTTP methods.

However, unlike trouter.all, the pattern you defined IS NOT RESTRICTIVE, which means that the route will match any & all URLs that start (but not end) with a matching segment.

router.use('/foo', 'USE /foo');
router.use('/foo/:name', 'USE /foo/:name');
router.post('/foo/:name', 'POST /foo/:name');
router.head('/foo/:name/hello', 'HEAD /foo/:name/hello');

router.find('GET', '/foo').handlers;
//=> ['USE /foo']

router.find('POST', '/foo/bar').handlers;
//=> ['USE /foo', 'USE /foo/:name', 'POST /foo/:name']

router.find('HEAD', '/foo/bar/hello').handlers;
//=> ['USE /foo', 'USE /foo/:name', 'HEAD /foo/:name/hello']

Compare this snippet with the one below to see differences between trouter.all and this method.

trouter.all(pattern, ...handlers)

Returns: self

This is an alias for trouter.add('', pattern, ...handlers), matching all HTTP methods.

However, unlike trouter.use, the pattern you defined IS RESTRICTIVE and behaves like any other trouter.METHOD route. This means that the URL must match the defined pattern exactly – or have the appropriate optional and/or wildcard segments to accommodate the desired flexibility.

router.all('/foo', 'ALL /foo');
router.all('/foo/:name', 'ALL /foo/:name');
router.post('/foo/:name', 'POST /foo/:name');
router.head('/foo/:name/hello', 'HEAD /foo/:name/hello');

router.find('GET', '/foo').handlers;
//=> ['ALL /foo']

router.find('POST', '/foo/bar').handlers;
//=> ['ALL /foo/:name', 'POST /foo/:name']

router.find('HEAD', '/foo/bar/hello').handlers;
//=> ['HEAD /foo/:name/hello']

Compare this snippet with the one above to see differences between trouter.use and this method.

trouter.METHOD(pattern, ...handlers)

This is an alias for trouter.add(METHOD, pattern, ...handlers), where METHOD is any lowercased HTTP verb.

const noop = _ => {}:
const app = new Trouter();

app.get('/users/:id', noop);
app.post('/users', noop);
app.patch('/users/:id', noop);

// less common methods too
app.trace('/foo', noop);
app.connect('/bar', noop);

trouter.find(method, url)

Returns: Object

Searches within current instance for all method + pattern pairs that satisfy the current method + url.

Important: Parameters and handlers are assembled/gathered in the order that they were defined!

This method will always return an Object with params and handlers keys.

  • params — Object whose keys are the named parameters of your route pattern.
  • handlers — Array containing the ...handlers provided to .add() or .METHOD()

Note: The handlers and params keys will be empty if no matches were found.

method

Type: String

Any valid HTTP method name, uppercased.

Note: When searching for HEAD routes, GET routes will also be inspected.

url

Type: String

The URL used to match against pattern definitions. This is typically req.url.

Benchmarks

Run on Node v10.13.0

GET /                           x 10,349,863 ops/sec ±2.15% (93 runs sampled)
POST /users                     x 13,895,099 ops/sec ±0.40% (94 runs sampled)
GET /users/:id                  x  6,288,457 ops/sec ±0.25% (93 runs sampled)
PUT /users/:id/books/:title?    x  6,176,501 ops/sec ±0.22% (96 runs sampled)
DELETE /users/:id/books/:title  x  5,581,288 ops/sec ±2.04% (96 runs sampled)
HEAD /hello (all)               x  9,700,097 ops/sec ±0.47% (90 runs sampled)

Download Details:

Author: lukeed
Source Code: https://github.com/lukeed/trouter 
License: MIT license

#javascript #router 

Trouter: A Fast, Small-but-mighty, Familiar Fish...errr, Router

Oily.js: A Blazingly Fast Bun.js Filesystem Router

Oily

A blazingly fast Bun.js filesystem router, with
an unpleasantly smooth experience!


Installation

Once you've got Bun.js installed, The installation is super simple, just run the following commands.

# Install Bun.js, If you haven't yet.curl https://bun.sh/install | bash# Use Bun's package manager to install, or you# can use any package manager that supports Bun.js.bun add oily

Usage

// file: ./src/index.ts
import { Oily } from "oily";

await Oily.serve({
  middleware: [
    async (request, next) => {
      // do something before.
      const response = await next();
      // do something after.

      return response;
    }
  ]
});

// now listening on port 3000.

Routes are found, by default, within the ./http/routes directory, next to the entrypoint.

// file: ./src/http/routes/foo.ts
import { Oily } from "oily";

export default Oily.route({
  methods: {
    get: {
      async handle() {
        return Response.json({
          foo: true
        });
      }
    }
  }
});

Author: Ariesclark
Source Code: https://github.com/ariesclark/oily.js 
License: MIT license

#typescript #http #router #filesystem 

Oily.js: A Blazingly Fast Bun.js Filesystem Router

Siopao: A Minimal Routing Library Designed to Sit on Top

siopao

A minimal routing library designed to sit on top of Bun's fast HTTP server. Based on Radix Tree.

Sio=Hot Pao=Bun

Installation

bun add siopao

Usage

import Siopao from 'siopao'

const app = new Siopao()

app.get('/ping', () => new Response('pong'))

// Named route
app.get('/path/:name', (request) => {
  return Response.json({
    name: request.params.name
  })
})

// Wildcard route
app.use('/path/foo/**', (request) => {
  return new Response('Wildcard route')
})

// Named Wildcard route
app.use('/path/foo/**:name', (request) => {
  return new Response('Named Wildcard route')
})

app.serve({ port: 3000 }, () => {
  console.log('Listening on port 3000...')
})

If you have custom logic to add inside Bun's fetch option, you can use the fetch method instead:

const app = new Siopao()

app.get('/ping', () => new Response('pong'))

Bun.serve({
  port: 3000,
  fetch: (request) => {
    // Custom logic here

    return app.fetch(request)
  }
})

For a more complete web framework for the Bun runtime, see Bao.js.

Author: Wobsoriano
Source Code: https://github.com/wobsoriano/siopao 
License: MIT license

#typescript #http #router 

Siopao: A Minimal Routing Library Designed to Sit on Top

Hono: Ultrafast web framework for Cloudflare Workers, Deno, and Bun

Hono - [炎] means flame🔥 in Japanese - is a small, simple, and ultrafast web framework for Cloudflare Workers, Deno, Bun, and others.

import { Hono } from 'hono'
const app = new Hono()

app.get('/', (c) => c.text('Hono!!'))

export default app

Features

  • Ultrafast - the router does not use linear loops.
  • Zero-dependencies - using only Service Worker and Web Standard API.
  • Middleware - built-in middleware, custom middleware, and third-party middleware.
  • TypeScript - first-class TypeScript support.
  • Multi-platform - works on Cloudflare Workers, Fastly Compute@Edge, Deno, or Bun.

Benchmarks

Hono is fastest, compared to other routers for Cloudflare Workers.

hono - trie-router(default) x 389,510 ops/sec ±3.16% (85 runs sampled)
hono - regexp-router x 452,290 ops/sec ±2.64% (84 runs sampled)
itty-router x 206,013 ops/sec ±3.39% (90 runs sampled)
sunder x 323,131 ops/sec ±0.75% (97 runs sampled)
worktop x 191,218 ops/sec ±2.70% (91 runs sampled)
Fastest is hono - regexp-router
✨  Done in 43.56s.

Documentation

The documentation is available on honojs.dev.

Migration

Migration guide is available on docs/MIGRATION.md.

Contributing

Contributions Welcome! You can contribute in the following ways.

  • Create an Issue - Propose a new feature. Report a bug.
  • Pull Request - Fix a bug and typo. Refactor the code.
  • Create third-party middleware - Instruct below.
  • Share - Share your thoughts on the Blog, Twitter, and others.
  • Make your application - Please try to use Hono.

For more details, see docs/CONTRIBUTING.md.

Contributors

Thanks to all contributors! Especially, @metrue and @usualoma!


Documentation 👉 honojs.dev
v2.x has been released! Migration guide


Author: Honojs
Source Code: https://github.com/honojs/hono 
License: MIT license

#javascript #typescript #npm #router #cloudflare 

Hono: Ultrafast web framework for Cloudflare Workers, Deno, and Bun

A Flutter Package Which Provides A Page Route Which Reveals Its Page

A page route, which reveals its page by expanding a circular clip from an anchor widget.


If you're looking for a database solution, check out cbl, another project of mine. It brings Couchbase Lite to standalone Dart and Flutter, with support for:

  • Full-Text Search,
  • Expressive Queries,
  • Data Sync,
  • Change Notifications

and more.


Getting started

To use the CircularClipRoute, provide it the context from which the animation should expand and push it onto the navigation stack. One way to get the right context is to use a Builder, which wraps the widget from which the route should expand:

final navigationTrigger = Builder(
    builder: (context) {
      return IconButton(
          icon: Icon(Icons.favorite),
          onPressed: () {
            Navigator.push(context, CircularClipRoute<void>(
              // This context will be used to determine the location and size of
              // the expanding clip. Here this will resolve to the `IconButton`.
              expandFrom: context,
              builder: (_) => MyRoute(),
            ));
          }
      );
    }
);

Also, take a look at the API docs for customizing the animation.

Example

The example implements the demo at the top.

References

Inspired by this shot.

This drawing visualizes the geometry involved in creating the route transition:

Illustration of the geometry of the transition

The Anchored Custom Routes article explains how to implement routes, that are anchored to a widget, generally.

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add circular_clip_route

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  circular_clip_route: ^0.2.0+3

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:circular_clip_route/circular_clip_route.dart'; 

example/lib/main.dart

import 'package:flutter/material.dart';

import 'contact_list_page.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: ContactListPage(),
    );
  }
} 

Download Details:

Author: blaugold

Source Code: https://github.com/blaugold/circular_clip_route

#router #flutter 

A Flutter Package Which Provides A Page Route Which Reveals Its Page
Nat  Grady

Nat Grady

1658677680

Router Solving Electron Hell Callback Passing, Helpfull for MVC

ElectronRouter 

Router solving Electron shell callback passing, helpfull for MVC

Installation

// Install:
npm install electron-router

// Test:
npm test

Motivation

The problem

When making an electron app I usually come down to the same problem: message passing; if you want to send a message to a window you have to keep a reference to it, whatever the module you're sending the message from, which leaves two possible solutions:

  • Pass the wanted window object to every module that needs to send a message to that window.

or

  • Somehow send the message to the owner of the window reference (usually implies callback passing).

On the other hand, when you want to receive a message from the window you have to listen to ipc which is usually great, but forces you to have perfect tune of the variables that the callback is going to access; this does not present a problem by itself, but as the application grows it may become one.

One example of this is when you have a database and want to query it from the window renderer process, either the database is listening on the ipc and aware of the window (keeps a reference to it) for querying/retrieving data or both the window and the database route their data through the main script, becoming some sort of dummy proxy.

After some brainstorming, the solution I came to was designing the Router, it gives similar options to express. I've made a diagram to help visualize all this.

diagram explaining the problem

The solution

The router just triggers the functions you register on by sending events and parameters. Allowing easy message/data passing and respecting the event/callback Electron architecture.

Features

Wildcards

Every sent/listened message can use wildcards

router.on('loading::start', () => { console.log('start loading...') }
router.on('loading::continue', () => { console.log('continue loading...') }
router.on('loading::end', () => { console.log('end loading...') }

...

router.send('loading::start', ...) // logs "start loading"
router.send('loading::*', ...) // logs "start loading", "continue loading", "end loading"

Simple, plain communication

You can send messages unidirectionally from the main process to the renderer process and viceversa (analogous to electron's ipc) (Previous example)

Duplex communication with channels

router.get('config::*')
router.post('config', ( req, res ) => {
    // req.params contain sent parameters
    // res.json sends data back
})
...

router.route('get', 'config::start', ( err, result ) => {
    console.log('got config', result)
})

API

The router is just a static object, there will be one router in the main process and another one on the renderer. Just 'require' it and start listening/sending events/data. What this object does is route callbacks from one side to another passing parameters, triggered by different events. It can listen to ipc events and send window events too. HTTP Verbs are used just as different channels and for completness (equality to express). For every route/event it is possible register wildcard ('*').

You are responsible for unregistering your callbacks with removeListener(listener), or all callbacks with removeAllListeners(), take into account that this will also delete whatever routes where registered on IPC outside the router. In order to do unregister individual callbacks, listeners should not be just anonymous functions.

Instance

// Constructs the object setting its name
let Router = require('electron-router')

// Returns the static instance
let router = Router( name )

Simple communication

// Triggers/Sends a message on the given event name passing provided messages.
router.send( event, msg1, msg2... )

// Register a listener on the given event, triggering the callback when the event is sent.
// Callback receives the messages sent on the other side
router.on( event, ( msg1, msg2... ) => {})

Duplex communication

// Triggers/Sends a message to the given route on the given method (channel, HTTP Verbs)
// passing the given messages to that channel/route handler. 
// Callback is called with err/result when the handler calls res.json()
// if the handler does not call the return function, callback is invoked with Err: Timeout

router.route( method, route, msg1, msg2..., ( err, result ) => {})

// Similar to router.routes.method( route, msg1, msg2..., ( err, result ) => {})

// All handlers on all channels are called with
//     req { parameters: [], method: channel }
//     res { json: [Function] } - function to call with (err, result), triggers the route back

// Registers handler on GET channel at the given route.
router.get( route, ( req, res ) => {}) // must call res.json( err, result )

// Registers handler on POST channel at the given route.
router.post( route, ( req, res ) => {}) // must call res.json( err, result )

// Registers handler on UPDATE channel at the given route.
router.update( route, ( req, res ) => {}) // must call res.json( err, result )

// Registers handler on DELETE channel at the given route.
router.delete( route, ( req, res ) => {}) // must call res.json( err, result )

Examples

// On every module that uses the router
// Import it
let Router = require('electron-router')

// Main script

const electron = require('electron')
const BrowserWindow = electron.BrowserWindow
const app = electron.app
const Router = require('electron-router')
let router = Router('MAIN')
let mainWindow = null

...

app.on('ready', () => {

    // Create window
    ... 

  // Setup DB and modules
  ...

    // Do the rest on ready event (triggered from window, which is usaully the slowest component)
    router.on('ready', () => {
        router.on('quit', () => {
            // Close DB
            // Handle quit code
            ...
        })
    })
})

...

// Window script

const $ = require('jquery')
const Router = require('electron-router')
let router = Router('WINDOW')

// On window ready
$(() => {
  // Send ready event to all registered handlers
  router.send('ready')
  ...

  $('#updates').on('click', () => {
      router.route('POST', '/DB', $('#userData').data())
  })
})

...

// DB script

const Router = require('electron-router')
let router = Router('DB')

...

router.on('ready', () => { ... })

// Register trigger for every route on method GET
route.get('*', ( req, res ) => {
    db.find({ id: req.params }, ( err, results ) => {
        res.json( err, results )
    })
})

// Receive data on post method, route /DB
router.post('/DB', ( req, res ) => {
    console.log('Received', req.params)
    // Save data on db
    db.save( req.params, ( err, result ) => {
        // Send save result to the triggerer
        res.json( err, result )
    })
})

Contributing

Any help is welcome, just send a pull request (please document a little what you want to do), with any ideas/code

Future

In the future it could be great to support:

  • MVC frameworks integration (Backbone...) (Should not be too difficult, overwrite sync method on Collections) erbs
  • Template rendering (i.e.: res.render(data))

Notes

The diagram was made with gliffy

Author: Geblanco
Source Code: https://github.com/geblanco/electron-router 
License: MIT license

#electron #router #mvc #passing 

Router Solving Electron Hell Callback Passing, Helpfull for MVC