a tiny and isomorphic URL router for JavaScript

Related tags

Routing director
Overview

Logo

Synopsis

Director is a router. Routing is the process of determining what code to run when a URL is requested.

Motivation

A routing library that works in both the browser and node.js environments with as few differences as possible. Simplifies the development of Single Page Apps and Node.js applications. Dependency free (doesn't require jQuery or Express, etc).

Status

Build Status

Features

Usage

Building client-side script

Run the provided CLI script.

./bin/build

Client-side Routing

It simply watches the hash of the URL to determine what to do, for example:

http://foo.com/#/bar

Client-side routing (aka hash-routing) allows you to specify some information about the state of the application using the URL. So that when the user visits a specific URL, the application can be transformed accordingly.

Hash route

Here is a simple example:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>A Gentle Introduction</title>

    <script
      src="https://rawgit.com/flatiron/director/master/build/director.min.js">
    </script>

    <script>
      var author = function () { console.log("author"); };
      var books = function () { console.log("books"); };
      var viewBook = function (bookId) {
        console.log("viewBook: bookId is populated: " + bookId);
      };

      var routes = {
        '/author': author,
        '/books': [books, function() {
          console.log("An inline route handler.");
        }],
        '/books/view/:bookId': viewBook
      };

      var router = Router(routes);

      router.init();
    </script>
  </head>

  <body>
    <ul>
      <li><a href="#/author">#/author</a></li>
      <li><a href="#/books">#/books</a></li>
      <li><a href="#/books/view/1">#/books/view/1</a></li>
    </ul>
  </body>
</html>

Director works great with your favorite DOM library, such as jQuery.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>A Gentle Introduction 2</title>

    <script
      src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js">
    </script>

    <script
      src="https://rawgit.com/flatiron/director/master/build/director.min.js">
    </script>

    <script>
    $('document').ready(function() {
      //
      // create some functions to be executed when
      // the correct route is issued by the user.
      //
      var showAuthorInfo = function () { console.log("showAuthorInfo"); };
      var listBooks = function () { console.log("listBooks"); };

      var allroutes = function() {
        var route = window.location.hash.slice(2);
        var sections = $('section');
        var section;

        section = sections.filter('[data-route=' + route + ']');

        if (section.length) {
          sections.hide(250);
          section.show(250);
        }
      };

      //
      // define the routing table.
      //
      var routes = {
        '/author': showAuthorInfo,
        '/books': listBooks
      };

      //
      // instantiate the router.
      //
      var router = Router(routes);

      //
      // a global configuration setting.
      //
      router.configure({
        on: allroutes
      });

      router.init();
    });
    </script>
  </head>

  <body>
    <section data-route="author">Author Name</section>
    <section data-route="books">Book1, Book2, Book3</section>
    <ul>
      <li><a href="#/author">#/author</a></li>
      <li><a href="#/books">#/books</a></li>
    </ul>
  </body>
</html>

You can find a browser-specific build of director here which has all of the server code stripped away.

Server-Side HTTP Routing

Director handles routing for HTTP requests similar to journey or express:

  //
  // require the native http module, as well as director.
  //
  var http = require('http'),
      director = require('director');

  //
  // create some logic to be routed to.
  //
  function helloWorld() {
    this.res.writeHead(200, { 'Content-Type': 'text/plain' })
    this.res.end('hello world');
  }

  //
  // define a routing table.
  //
  var router = new director.http.Router({
    '/hello': {
      get: helloWorld
    }
  });

  //
  // setup a server and when there is a request, dispatch the
  // route that was requested in the request object.
  //
  var server = http.createServer(function (req, res) {
    router.dispatch(req, res, function (err) {
      if (err) {
        res.writeHead(404);
        res.end();
      }
    });
  });

  //
  // You can also do ad-hoc routing, similar to `journey` or `express`.
  // This can be done with a string or a regexp.
  //
  router.get('/bonjour', helloWorld);
  router.get(/hola/, helloWorld);

  //
  // set the server to listen on port `8080`.
  //
  server.listen(8080);

See Also:

Server-Side CLI Routing

Director supports Command Line Interface routing. Routes for cli options are based on command line input (i.e. process.argv) instead of a URL.

  var director = require('director');

  var router = new director.cli.Router();

  router.on('create', function () {
    console.log('create something');
  });

  router.on(/destroy/, function () {
    console.log('destroy something');
  });

  // You will need to dispatch the cli arguments yourself
  router.dispatch('on', process.argv.slice(2).join(' '));

Using the cli router, you can dispatch commands by passing them as a string. For example, if this example is in a file called foo.js:

$ node foo.js create
create something
$ node foo.js destroy
destroy something

API Documentation

Constructor

  var router = Router(routes);

Routing Table

An object literal that contains nested route definitions. A potentially nested set of key/value pairs. The keys in the object literal represent each potential part of the URL. The values in the object literal contain references to the functions that should be associated with them. bark and meow are two functions that you have defined in your code.

  //
  // Assign routes to an object literal.
  //
  var routes = {
    //
    // a route which assigns the function `bark`.
    //
    '/dog': bark,
    //
    // a route which assigns the functions `meow` and `scratch`.
    //
    '/cat': [meow, scratch]
  };

  //
  // Instantiate the router.
  //
  var router = Router(routes);

Adhoc Routing

When developing large client-side or server-side applications it is not always possible to define routes in one location. Usually individual decoupled components register their own routes with the application router. We refer to this as Adhoc Routing. Lets take a look at the API director exposes for adhoc routing:

Client-side Routing

  var router = new Router().init();

  router.on('/some/resource', function () {
    //
    // Do something on `/#/some/resource`
    //
  });

HTTP Routing

  var router = new director.http.Router();

  router.get(/\/some\/resource/, function () {
    //
    // Do something on an GET to `/some/resource`
    //
  });

Scoped Routing

In large web appliations, both Client-side and Server-side, routes are often scoped within a few individual resources. Director exposes a simple way to do this for Adhoc Routing scenarios:

  var router = new director.http.Router();

  //
  // Create routes inside the `/users` scope.
  //
  router.path(/\/users\/(\w+)/, function () {
    //
    // The `this` context of the function passed to `.path()`
    // is the Router itself.
    //

    this.post(function (id) {
      //
      // Create the user with the specified `id`.
      //
    });

    this.get(function (id) {
      //
      // Retreive the user with the specified `id`.
      //
    });

    this.get(/\/friends/, function (id) {
      //
      // Get the friends for the user with the specified `id`.
      //
    });
  });

Routing Events

In director, a "routing event" is a named property in the Routing Table which can be assigned to a function or an Array of functions to be called when a route is matched in a call to router.dispatch().

  • on: A function or Array of functions to execute when the route is matched.
  • before: A function or Array of functions to execute before calling the on method(s).

Client-side only

  • after: A function or Array of functions to execute when leaving a particular route.
  • once: A function or Array of functions to execute only once for a particular route.

Configuration

Given the flexible nature of director there are several options available for both the Client-side and Server-side. These options can be set using the .configure() method:

  var router = new director.Router(routes).configure(options);

The options are:

  • recurse: Controls route recursion. Use forward, backward, or false. Default is false Client-side, and backward Server-side.
  • strict: If set to false, then trailing slashes (or other delimiters) are allowed in routes. Default is true.
  • async: Controls async routing. Use true or false. Default is false.
  • delimiter: Character separator between route fragments. Default is /.
  • notfound: A function to call if no route is found on a call to router.dispatch().
  • on: A function (or list of functions) to call on every call to router.dispatch() when a route is found.
  • before: A function (or list of functions) to call before every call to router.dispatch() when a route is found.

Client-side only

  • resource: An object to which string-based routes will be bound. This can be especially useful for late-binding to route functions (such as async client-side requires).
  • after: A function (or list of functions) to call when a given route is no longer the active route.
  • html5history: If set to true and client supports pushState(), then uses HTML5 History API instead of hash fragments. See History API for more information.
  • run_handler_in_init: If html5history is enabled, the route handler by default is executed upon Router.init() since with real URIs the router can not know if it should call a route handler or not. Setting this to false disables the route handler initial execution.
  • convert_hash_in_init: If html5history is enabled, the window.location hash by default is converted to a route upon Router.init() since with canonical URIs the router can not know if it should convert the hash to a route or not. Setting this to false disables the hash conversion on router initialisation.

URL Matching

  var router = Router({
    //
    // given the route '/dog/yella'.
    //
    '/dog': {
      '/:color': {
        //
        // this function will return the value 'yella'.
        //
        on: function (color) { console.log(color) }
      }
    }
  });

Routes can sometimes become very complex, simple/:tokens don't always suffice. Director supports regular expressions inside the route names. The values captured from the regular expressions are passed to your listener function.

  var router = Router({
    //
    // given the route '/hello/world'.
    //
    '/hello': {
      '/(\\w+)': {
        //
        // this function will return the value 'world'.
        //
        on: function (who) { console.log(who) }
      }
    }
  });
  var router = Router({
    //
    // given the route '/hello/world/johny/appleseed'.
    //
    '/hello': {
      '/world/?([^\/]*)\/([^\/]*)/?': function (a, b) {
        console.log(a, b);
      }
    }
  });

URL Parameters

When you are using the same route fragments it is more descriptive to define these fragments by name and then use them in your Routing Table or Adhoc Routes. Consider a simple example where a userId is used repeatedly.

  //
  // Create a router. This could also be director.cli.Router() or
  // director.http.Router().
  //
  var router = new director.Router();

  //
  // A route could be defined using the `userId` explicitly.
  //
  router.on(/([\w-_]+)/, function (userId) { });

  //
  // Define a shorthand for this fragment called `userId`.
  //
  router.param('userId', /([\\w\\-]+)/);

  //
  // Now multiple routes can be defined with the same
  // regular expression.
  //
  router.on('/anything/:userId', function (userId) { });
  router.on('/something-else/:userId', function (userId) { });

Wildcard routes

It is possible to define wildcard routes, so that /foo and /foo/a/b/c routes to the same handler, and gets passed "" and "a/b/c" respectively.

  router.on("/foo/?((\w|.)*)"), function (path) { });

Route Recursion

Can be assigned the value of forward or backward. The recurse option will determine the order in which to fire the listeners that are associated with your routes. If this option is NOT specified or set to null, then only the listeners associated with an exact match will be fired.

No recursion, with the URL /dog/angry

  var routes = {
    '/dog': {
      '/angry': {
        //
        // Only this method will be fired.
        //
        on: growl
      },
      on: bark
    }
  };

  var router = Router(routes);

Recursion set to backward, with the URL /dog/angry

  var routes = {
    '/dog': {
      '/angry': {
        //
        // This method will be fired first.
        //
        on: growl
      },
      //
      // This method will be fired second.
      //
      on: bark
    }
  };

  var router = Router(routes).configure({ recurse: 'backward' });

Recursion set to forward, with the URL /dog/angry

  var routes = {
    '/dog': {
      '/angry': {
        //
        // This method will be fired second.
        //
        on: growl
      },
      //
      // This method will be fired first.
      //
      on: bark
    }
  };

  var router = Router(routes).configure({ recurse: 'forward' });

Breaking out of recursion, with the URL /dog/angry

  var routes = {
    '/dog': {
      '/angry': {
        //
        // This method will be fired first.
        //
        on: function() { return false; }
      },
      //
      // This method will not be fired.
      //
      on: bark
    }
  };

  //
  // This feature works in reverse with recursion set to true.
  //
  var router = Router(routes).configure({ recurse: 'backward' });

Async Routing

Before diving into how Director exposes async routing, you should understand Route Recursion. At it's core route recursion is about evaluating a series of functions gathered when traversing the Routing Table.

Normally this series of functions is evaluated synchronously. In async routing, these functions are evaluated asynchronously. Async routing can be extremely useful both on the client-side and the server-side:

  • Client-side: To ensure an animation or other async operations (such as HTTP requests for authentication) have completed before continuing evaluation of a route.
  • Server-side: To ensure arbitrary async operations (such as performing authentication) have completed before continuing the evaluation of a route.

The method signatures for route functions in synchronous and asynchronous evaluation are different: async route functions take an additional next() callback.

Synchronous route functions

  var router = new director.Router();

  router.on('/:foo/:bar/:bazz', function (foo, bar, bazz) {
    //
    // Do something asynchronous with `foo`, `bar`, and `bazz`.
    //
  });

Asynchronous route functions

  var router = new director.http.Router().configure({ async: true });

  router.on('/:foo/:bar/:bazz', function (foo, bar, bazz, next) {
    //
    // Go do something async, and determine that routing should stop
    //
    next(false);
  });

Resources

Available on the Client-side only. An object literal containing functions. If a host object is specified, your route definitions can provide string literals that represent the function names inside the host object. A host object can provide the means for better encapsulation and design.

  var router = Router({

    '/hello': {
      '/usa': 'americas',
      '/china': 'asia'
    }

  }).configure({ resource: container }).init();

  var container = {
    americas: function() { return true; },
    china: function() { return true; }
  };

History API

Available on the Client-side only. Director supports using HTML5 History API instead of hash fragments for navigation. To use the API, pass {html5history: true} to configure(). Use of the API is enabled only if the client supports pushState().

Using the API gives you cleaner URIs but they come with a cost. Unlike with hash fragments your route URIs must exist. When the client enters a page, say http://foo.com/bar/baz, the web server must respond with something meaningful. Usually this means that your web server checks the URI points to something that, in a sense, exists, and then serves the client the JavaScript application.

If you're after a single-page application you can not use plain old <a href="/bar/baz"> tags for navigation anymore. When such link is clicked, web browsers try to ask for the resource from server which is not of course desired for a single-page application. Instead you need to use e.g. click handlers and call the setRoute() method yourself.

Attach Properties To this

Available in the http router only. Generally, the this object bound to route handlers, will contain the request in this.req and the response in this.res. One may attach additional properties to this with the router.attach method:

  var director = require('director');

  var router = new director.http.Router().configure(options);

  //
  // Attach properties to `this`
  //
  router.attach(function () {
    this.data = [1,2,3];
  });

  //
  // Access properties attached to `this` in your routes!
  //
  router.get('/hello', function () {
    this.res.writeHead(200, { 'content-type': 'text/plain' });

    //
    // Response will be `[1,2,3]`!
    //
    this.res.end(this.data);
  });

This API may be used to attach convenience methods to the this context of route handlers.

HTTP Streaming and Body Parsing

When you are performing HTTP routing there are two common scenarios:

  • Buffer the request body and parse it according to the Content-Type header (usually application/json or application/x-www-form-urlencoded).
  • Stream the request body by manually calling .pipe or listening to the data and end events.

By default director.http.Router() will attempt to parse either the .chunks or .body properties set on the request parameter passed to router.dispatch(request, response, callback). The router instance will also wait for the end event before firing any routes.

Default Behavior

  var director = require('director');

  var router = new director.http.Router();

  router.get('/', function () {
    //
    // This will not work, because all of the data
    // events and the end event have already fired.
    //
    this.req.on('data', function (chunk) {
      console.log(chunk)
    });
  });

In flatiron, director is used in conjunction with union which uses a BufferedStream proxy to the raw http.Request instance. union will set the req.chunks property for you and director will automatically parse the body. If you wish to perform this buffering yourself directly with director you can use a simple request handler in your http server:

  var http = require('http'),
      director = require('director');

  var router = new director.http.Router();

  var server = http.createServer(function (req, res) {
    req.chunks = [];
    req.on('data', function (chunk) {
      req.chunks.push(chunk.toString());
    });

    router.dispatch(req, res, function (err) {
      if (err) {
        res.writeHead(404);
        res.end();
      }

      console.log('Served ' + req.url);
    });
  });

  router.post('/', function () {
    this.res.writeHead(200, { 'Content-Type': 'application/json' })
    this.res.end(JSON.stringify(this.req.body));
  });

Streaming Support

If you wish to get access to the request stream before the end event is fired, you can pass the { stream: true } options to the route.

  var director = require('director');

  var router = new director.http.Router();

  router.get('/', { stream: true }, function () {
    //
    // This will work because the route handler is invoked
    // immediately without waiting for the `end` event.
    //
    this.req.on('data', function (chunk) {
      console.log(chunk);
    });
  });

Instance methods

configure(options)

  • options {Object}: Options to configure this instance with.

Configures the Router instance with the specified options. See Configuration for more documentation.

param(token, matcher)

  • token {string}: Named parameter token to set to the specified matcher
  • matcher {string|Regexp}: Matcher for the specified token.

Adds a route fragment for the given string token to the specified regex matcher to this Router instance. See URL Parameters for more documentation.

on(method, path, route)

  • method {string}: Method to insert within the Routing Table (e.g. on, get, etc.).
  • path {string}: Path within the Routing Table to set the route to.
  • route {function|Array}: Route handler to invoke for the method and path.

Adds the route handler for the specified method and path within the Routing Table.

path(path, routesFn)

  • path {string|Regexp}: Scope within the Routing Table to invoke the routesFn within.
  • routesFn {function}: Adhoc Routing function with calls to this.on(), this.get() etc.

Invokes the routesFn within the scope of the specified path for this Router instance.

dispatch(method, path[, callback])

  • method {string}: Method to invoke handlers for within the Routing Table
  • path {string}: Path within the Routing Table to match
  • callback {function}: Invoked once all route handlers have been called.

Dispatches the route handlers matched within the Routing Table for this instance for the specified method and path.

mount(routes, path)

  • routes {object}: Partial routing table to insert into this instance.
  • path {string|Regexp}: Path within the Routing Table to insert the routes into.

Inserts the partial Routing Table, routes, into the Routing Table for this Router instance at the specified path.

Instance methods (Client-side only)

init([redirect])

  • redirect {String}: This value will be used if '/#/' is not found in the URL. (e.g., init('/') will resolve to '/#/', init('foo') will resolve to '/#foo').

Initialize the router, start listening for changes to the URL.

getRoute([index])

  • index {Number}: The hash value is divided by forward slashes, each section then has an index, if this is provided, only that section of the route will be returned.

Returns the entire route or just a section of it.

setRoute(route)

  • route {String}: Supply a route value, such as home/stats.

Set the current route.

setRoute(start, length)

  • start {Number} - The position at which to start removing items.
  • length {Number} - The number of items to remove from the route.

Remove a segment from the current route.

setRoute(index, value)

  • index {Number} - The hash value is divided by forward slashes, each section then has an index.
  • value {String} - The new value to assign the the position indicated by the first parameter.

Set a segment of the current route.

Frequently Asked Questions

What About SEO?

Is using a Client-side router a problem for SEO? Yes. If advertising is a requirement, you are probably building a "Web Page" and not a "Web Application". Director on the client is meant for script-heavy Web Applications.

LICENSE: MIT
Author: Charlie Robbins
Contributors: Paolo Fragomeni
Comments
  • [api] Bind extra objects to thisArg in http

    [api] Bind extra objects to thisArg in http

    Refer #80

    @indexzero, @AvianFlu

    @jesusabdullah When we pass some objects in options.copy this copies all of them to this arg and apply the router function. Thus this.render will be available in the presenter.

    opened by pksunkara 26
  • Handling POST data

    Handling POST data

    Hi,

    Maybe i am missing the point as to how the router should be used but could point me in the right direction?

    What would be the best way to handle retrieving POST data from a form using Director?

    I gather the code below doesn't work because: "The this context of the function passed to .path() is the Router itself."

    I am using a basic form with method="post" and action="/save/"

    router.path(/save/, function () {
    
      this.post(function () {
    
                var self = this;
                var POST;
    
                console.log('1: i got here');
    
                self.res.writeHead(200, {'Content-type': 'text/html'});
    
                self.req.on('data', function (chunk){
    
                    console.log('2: i got here');
    
                    POST = chunk;
    
                }).on('end', function () {
    
                    console.log('3: i got here');
    
                    self.res.end(POST.toString());
    
                });
    
      });
    
    });
    

    The console prints '1: i got here', then the browser hangs waiting for an end response and nothing more is printed to the console.

    I'd like to use the routing functionality rather than simply placing this code within router.dispatch function.

    Any tips / pointers would be greatly appreciated.

    opened by icodejs 25
  • Make work with Browserify

    Make work with Browserify

    Closes #126. Depends on hij1nx/codesurgeon#13 (cc @hij1nx). Browserify just consumes the browser builds.

    This will add yet another place to update the version number (besides the browser tests) when doing releases, which is unfortunate, but I guess a necessary consequence of having version numbers in the output filenames.

    opened by domenic 18
  • Multiple hash parameters

    Multiple hash parameters

    Is there a way to handle multiple hash parameters?

    eg. ...index.html#/roadmap/7/2010

    I tried to define it this way: '/roadmap': {    '/(\d+)': {        on: displayRoadmap,        '/(\d+)': {            on: displayRoadmap        }    } }

    Hoping that it would call my function with one or two parameters based on matches: function displayRoadmap(id, year) {    ... }

    Thanks, tvalletta

    opened by tvalletta 17
  • Error when router.on() (Client-side routing)

    Error when router.on() (Client-side routing)

    using: director-1.0.7.min.js

    In chrome v16:

    var router = new Router().init();
    router.on('/:some', function () {...}); //=> TypeError: Cannot call method 'concat' of undefined
    

    In FF v9

    var router = new Router().init();
    router.on('/:some', function () {...}); //=> TypeError: this.scope is undefined
    

    In IE v9 does not work.

    client-side 
    opened by zxcabs 15
  • Client side HTML5 History API support

    Client side HTML5 History API support

    Enable using HTML5 History API and the clean URLs it brings instead of the hash fragment URIs on browsers that support it. In practice a new configure option html5history was added and the required changes implemented to browser.js.

    These changes have been manually tested with:

    • Chrome 16.0.912.75 (Windows)
    • Chromium 15.0.874.106 (Linux)
    • Firefox 9.0.1 (Linux & Windows)
    • Safari 5 (Windows)
      • Navigation from the UI works with Safari as well, but browser back button skips pages. This does happen with e.g. Spine.js as well, and also on http://html5demos.com/history so I would assume it's just a browser "feature".
    • Internet Explorer 9.0.8.8112.16421 (64-bit)
    • rekonq 0.8.0 (location bar URI does not change but navigation works)

    No tests were added due to not being able to test with just a HTML page and QUnit. Implementing tests would require adding a server implementation that serves the test page and related JS components.

    Documentation is updated as well. Unfortunately the diff contains a lot of irrelevant changes as my editor stripped trailing whitespaces. #20

    client-side 
    opened by vesse 13
  • Initial route not firing

    Initial route not firing

    It seems if the initial page load (in browser) already contains the local route then the route doesn't fire.

    routes =
      '/test': -> debugger
    
    router = new Router(routes)
    router.init()
    

    The only way I've found to get the initial route to trigger is with this little hack:

    initialRoute = window.location.hash.replace(/^#/, '')
    router.setRoute('/')
    router.setRoute(initialRoute)
    

    Anyone else experiencing this?

    opened by rymohr 12
  • Stack overflow / event firing order

    Stack overflow / event firing order

    My mini-router here: https://gist.github.com/1248332

    Having 2 issues:

    1. my global 'after' event seems to be firing before 'on'
    • this was happening with the sample code from the SugarSkull dl too
    • what exactly does "after this route" mean? i.e. does this mean when another hashchange happens when you are already on the specified route?
    1. Getting a stack overflow error with regify on line 38 of SS.js when I try to use the resource param and define a methods object
    • this was happening for me on both Chrome and FF

    Maybe I'm just defining something wrong?

    ps. can you also specify what SS.min.js is? doesn't seem to just be a minified version of SS.js, or am I wrong?

    opened by jandet-zz 12
  • .on method

    .on method

    I used this method before in sugarskull, but seems to be missing

    var flatiron  = require('flatiron')
      , app       = flatiron.app
      ;
    
    app.use(flatiron.plugins.http);
    
    app.router.on('/bla', function () {
      this.res.json({"error": "not_found"}, 404);
    });
    
    app.start(3001, function () { 
      console.log({"nodejitsu": "ok", "port": 3001});
    });
    
    $ curl localhost:3000/bla
    undefined 
    
    > process.versions
    { node: '0.6.7',
      v8: '3.6.6.15',
      ares: '1.7.5-DEV',
      uv: '0.6',
      openssl: '0.9.8r' }
    
    opened by dscape 9
  • example code doesn't work.

    example code doesn't work.

    encountered many problems, trying what was in the readme.

    Router({})
    
    TypeError: Object #<Object> has no method 'configure'
        at /home/dominic/source/dev/experiement/node_modules/sugarskull/lib/sugarskull/router.js:124:8
        at /home/dominic/source/dev/experiement/node_modules/sugarskull/lib/sugarskull/http/index.js:14:21
        at Object.<anonymous> (/home/dominic/source/dev/experiement/ss.js:4:9)
        at Module._compile (module.js:411:26)
        at Object..js (module.js:417:10)
        at Module.load (module.js:343:31)
        at Function._load (module.js:302:12)
        at Array.<anonymous> (module.js:430:10)
        at EventEmitter._tickCallback (node.js:126:26)
    
    
    new Router({}).init()
    
    
    TypeError: Object [object Object] has no method 'init'
        at Object.<anonymous> (/home/dominic/source/dev/experiement/ss.js:9:4)
        at Module._compile (module.js:411:26)
        at Object..js (module.js:417:10)
        at Module.load (module.js:343:31)
        at Function._load (module.js:302:12)
        at Array.<anonymous> (module.js:430:10)
        at EventEmitter._tickCallback (node.js:126:26)
    
    
    var Router = require('sugarskull').http.Router
      , http = require('http')
    
    function respond () {
      console.error('it worked')
      this.res.writeHeader(200); this.res.end('aoneuhaoenuhoneiurkpborkbropkbr')   
    }
    
    var r = new Router({
      on: respond,
      '/\//': respond,
      '/': respond,
    
    })
    
    http.createServer(function (req, res) {
      r.dispatch(req, res, function (err) { throw err })
    }).listen(8080)
    
    
                                            ^
    Error: Could not find path: /
        at [object Object].dispatch (/home/dominic/source/dev/experiement/node_modules/sugarskull/lib/sugarskull/http/index.js:60:16)
        at Server.<anonymous> (/home/dominic/source/dev/experiement/ss.js:21:5)
        at Server.emit (events.js:67:17)
        at HTTPParser.onIncoming (http.js:1134:12)
        at HTTPParser.onHeadersComplete (http.js:108:31)
        at Socket.ondata (http.js:1029:22)
        at Socket._onReadable (net.js:677:27)
        at IOWatcher.onReadable [as callback] (net.js:177:10)
    
    

    this needs working examples!

    opened by dominictarr 9
  • Trailing slashes not possible in director routes?

    Trailing slashes not possible in director routes?

    In theory, these two URLs are equally valid, and will generally mean the same thing:

    1. http://localhost:7000/api/
    2. http://localhost:7000/api

    However, it seems that number 1 is not currently possible with Director.

    I have this setup in my Flatiron app:

    // In app.js
    var flatiron = require('flatiron'),
        app = flatiron.app;
    
    app.use(flatiron.plugins.http);
    
    app.router.path('/api', require('./api').router);
    
    
    // In api/index.js
    var router = function () {
      this.get('/', function () {
        this.res.writeHead(200, { 'Content-Type': 'text/plain' });
        this.res.end('This is the entry point for the Ardon API.');
      });
    };
    
    module.exports = {
      router: router
    };
    

    I've tried different variations of that with slash or not slash in the app.router.path() and this.get() invocations, but the result is invariably the same. http://localhost:7000/api works as it should, http://localhost:7000/api/ returns the text “undefined” with a 404 not found header.

    opened by mikl 8
  • Bump request from 2.49.0 to 2.88.0

    Bump request from 2.49.0 to 2.88.0

    Bumps request from 2.49.0 to 2.88.0.

    Changelog

    Sourced from request's changelog.

    v2.88.0 (2018/08/10)

    v2.87.0 (2018/05/21)

    v2.86.0 (2018/05/15)

    v2.85.0 (2018/03/12)

    v2.84.0 (2018/03/12)

    v2.83.0 (2017/09/27)

    v2.82.0 (2017/09/19)

    v2.81.0 (2017/03/09)

    v2.80.0 (2017/03/04)

    ... (truncated)
    Commits
    • 6420240 2.88.0
    • bd22e21 fix: massive dependency upgrade, fixes all production vulnerabilities
    • 925849a Merge pull request #2996 from kwonoj/fix-uuid
    • 7b68551 fix(uuid): import versioned uuid
    • 5797963 Merge pull request #2994 from dlecocq/oauth-sign-0.9.0
    • 628ff5e Update to oauth-sign 0.9.0
    • 10987ef Merge pull request #2993 from simov/fix-header-tests
    • cd848af These are not going to fail if there is a server listening on those ports
    • a92e138 #515, #2894 Strip port suffix from Host header if the protocol is known. (#2904)
    • 45ffc4b Improve AWS SigV4 support. (#2791)
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot ignore this [patch|minor|major] version will close this PR and stop Dependabot creating any more for this minor/major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • about 'forward'

    about 'forward'

    var routes = { '/api': { '/:id': { '/:id': { on: f3 }, on: f2 }, on: f1 } };

    var router = Router(routes).configure({ recurse: 'forward' });

    I want it to be f1-->f2-->f3 but f1-->f3-->f2

    opened by ruanzy 0
  • Not sure what I'm doing wrong. Node version: 8.1.3.

    Not sure what I'm doing wrong. Node version: 8.1.3.

    1.) I downloaded your project to C:\TutorialCode

    2.) I changed my current working directory to: C:\TutorialCode\director\test\browser\backend\

    3.) Then, I tried running node backend from the command window on my Windows 7 machine

    image

    opened by bkwdesign 0
Owner
a decoupled application framework
a decoupled application framework
Micro client-side router inspired by the Express router

Tiny Express-inspired client-side router. page('/', index) page('/user/:user', show) page('/user/:user/edit', edit) page('/user/:user/album', album) p

Sloth 7.6k Dec 28, 2022
A navigation aid (aka, router) for the browser in 850 bytes~!

A navigation aid (aka, router) for the browser in 865 bytes~! Install $ npm install --save navaid Usage const navaid = require('navaid'); // Setup r

Luke Edwards 732 Dec 27, 2022
An Express.js-Style router for the front-end

An Express.js-Style router for the front-end. Code the front-end like the back-end. Same language same framework. frontexpress demo import frontexpres

Camel Aissani 262 Jul 11, 2022
JavaScript Routes

Introduction Crossroads.js is a routing library inspired by URL Route/Dispatch utilities present on frameworks like Rails, Pyramid, Django, CakePHP, C

Miller Medeiros 1.4k Oct 22, 2022
RESTful degradable JavaScript routing using pushState

Davis.js Description Davis.js is a small JavaScript library using HTML5 history.pushState that allows simple Sinatra style routing for your JavaScript

Oliver Nightingale 532 Sep 24, 2022
Single Page Application micro framework. Views, routes and controllers in 60 lines of code

SPApp Single Page Application Micro Framework Supports views, controllers and routing in 60 lines of code! Introduction If you heard anything about MV

Andrew 262 Nov 23, 2022
Backend API Rest application for ShortLink, a URL shortening service where you enter a valid URL and get back an encoded URL

ShortLink - The Shortest URL (API) Sobre o Projeto | Como Usar | Importante! Sobre o projeto The Shortest URL é um projeto back-end de ShortLink, um s

Bruno Weber 2 Mar 22, 2022
Router JS 💽 Simple Router building in JavaScript

Router JS ?? Simple Router building in JavaScript

David Montaño Tamayo 1 Feb 12, 2022
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
A tiny isomorphic fast function for generating a cryptographically random hex string.

ZeptoID A tiny isomorphic fast function for generating a cryptographically random hex string. Accoding to this calculator one would have to generate i

Fabio Spampinato 9 Oct 24, 2022
A chainable router designed for Next.js api. inspired and regex based from itty-router

Next.js Api Router A chainable router designed for Next.js api. inspired and regex based from itty-router Features Tiny (~8xx bytes compressed) with z

Aris Riswanto 1 Jan 21, 2022
Micro client-side router inspired by the Express router

Tiny Express-inspired client-side router. page('/', index) page('/user/:user', show) page('/user/:user/edit', edit) page('/user/:user/album', album) p

Sloth 7.6k Dec 28, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
🛣️ A tiny and fast http request router designed for use with deno and deno deploy

Rutt Rutt is a tiny http router designed for use with deno and deno deploy. It is written in about 200 lines of code and is pretty fast, using an exte

Denosaurs 26 Dec 10, 2022
Piccloud is a full-stack (Angular & Spring Boot) online image clipboard that lets you share images over the internet by generating a unique URL. Others can access the image via this URL.

Piccloud Piccloud is a full-stack application built with Angular & Spring Boot. It is an online image clipboard that lets you share images over the in

Olayinka Atobiloye 3 Dec 15, 2022
An isomorphic and configurable javascript utility for objects deep cloning that supports circular references.

omniclone An isomorphic and configurable javascript function for object deep cloning. omniclone(source [, config, [, visitor]]); Example: const obj =

Andrea Simone Costa 184 May 5, 2022
CASL is an isomorphic authorization JavaScript library which restricts what resources a given user is allowed to access

CASL (pronounced /ˈkæsəl/, like castle) is an isomorphic authorization JavaScript library which restricts what resources a given user is allowed to ac

Sergii Stotskyi 4.5k Dec 31, 2022
A tiny (108 bytes), secure, URL-friendly, unique string ID generator for JavaScript

Nano ID English | Русский | 简体中文 | Bahasa Indonesia A tiny, secure, URL-friendly, unique string ID generator for JavaScript. “An amazing level of sens

Andrey Sitnik 19.6k Jan 8, 2023
:seedling: Next-Gen AI-Assisted Isomorphic Application Engine for Embedded, Console, Mobile, Server and Desktop

lychee.js Mono Repository Important Notes to follow through Installation Quirks: The lycheejs-engine Repository needs to be installed to the path /opt

Cookie Engineer 791 Dec 31, 2022