magikarp v1.0.1
magikarp
Magikarp is a library for building applications. Not normal applications, but path (from URL's) based applications. It doesn't see URL's as routes but as application. Every section of a patch can be an individual application. These applications can be shared and installed from npm, modulized, re-used and sliced up in any way imaginable.
Just like Magikarp, you can evolve something as small as route to a really powerful beast.
Installation
The module is released in the public npm registry and can be installed by running:
npm install --save magikarp
The --save
flag tells npm
to add the installed version of the module as
dependency in your package.json
file.
Table of Contents
Usage
In the following snippets and API examples we assume that you've already created
a new Magikarp
instance. If you have not yet, please copy the following
example:
var Magikarp = require('magikarp')
, magikarp = new Magikarp(/* null, { options } */)
When constructing a new Magikarp
instance all arguments are optional but they
might be useful for your use case. The constructor accepts 2 arguments:
- An object which would be used as the
this
value for all your routes. If nothing is supplied it will default to your constructed Magikarp instance. - Options object which allows you to configure:
pathname
The base path from which we should start looking for applications, defaults to/
.
Now that you've created your first instance we can look at the methods that we expose:
magikarp.from
Read the Applications from a directory. This directory can be one level deep and
folders that are in the given directory should have an index.js
file which
exposes an Application instance. All none .js
files in the
directory it self will be ignored automatically.
The method accepts 2 arguments:
- directory The absolute path to the directory which contains the various of applications.
- options An object which allows you to configure how the directory is read:
deep
Allow one folder within the directory.nested
Deeply spider the given directory for js files.
magikarp.from(require('path').join(__dirname, 'fixtures'));
This method returns it self so you can chain it, if that's how you roll.
magikarp.add
Add new application instance to your Magikarp. We will automatically call the
run
/optimize
method of the application and pass in the this
value that
you've set when constructing your Magikarp instance.
The method requires 1 argument:
- application The application that we should run.
magikarp.add(new Magikarp.Application('foo/bar/{baz}.js'));
As you might have guessed, this method is also chainable.
magikarp.path
Create a new application instance that will automatically be added in to magikarp so it can be requested.
var app = magikarp.path('foo');
app.get(function (req, res, next) {
res.end('hello from foo');
});
magikarp.use
Add new middleware layer to the stack. This middleware layer will be run for
every application and HTTP method. Please do note that .from
,.add
and
.path
also introduce middleware layers to the stack. So if you want to have
your middleware for every application, besure to add them before calling any of
those methods. This actually quite powerful as you can gracefully add more
layers.
See Supply.use for more detailed information on how this method works. One thing that might be worth noting is that Magikarp is actually a full Supply instance so every method that is on Supply should also work for Magikarp.
magikarp.use(require('serve-static')(__dirname + '/static/dir'));
magikarp.before
Same as the magikarp.use
method, but it adds the middleware
layers at the beginnging of the stack instead of at the end.
magikarp.before('favicon', require('serve-favicon')());
magikarp.run
This is where the magic happens and we actually start handling the HTTP request.
The method requires 3 arguments:
- req The incoming HTTP request.
- res The outgoing HTTP response.
- next Error first continuation callback for when we have no matching routes.
var http = require('http').createServer(function (req, res) {
magikarp.run(req, res, function aww(err) {
res.statusCode = err ? 500 : 404;
res.end('awww');
});
});
Application
Applications are the things that run the matching part of the path name has been accessed. In the all following examples we assume that you've already created an application, if you have not yet, please follow one of the following examples:
If you haven't required Magikarp
yet:
var app = require('magikarp').path(route);
If you've already required Magikarp
:
var app = new Magikarp.Application(route);
If you already have a Magikarp
instance:
var app = magikarp.path(route);
So there are different ways to create your first Application. The route
that
we use in the examples above should a string that matches one or multiple
sections of the path name. See routes for more detailed information
about the various of routes and patterns that you can create and use here.
API
The following methods are exposed on your Application instance:
get, post, put, delete
Add a request handler for the given method. You can also use these methods to add middleware layers before the request as they follow same identical argument pattern. The handlers require a function which accepts 3 argument:
- req Reference to the incoming HTTP request.
- res Reference to the outgoing HTTP response.
- next Error first continuation callback. If there was an error which made it impossible to process the request it can be supplied as first argument. Also if you do not wish to handle the request you can simply call the callback without any argument and we will try to find another function that can.
var app = magikarp.path('/amazing/{path}/name/');
app
.get(function (req, res, next) {
res.end('handled');
});
app
.post(require('buffer-post')())
.post(function (req, res, next) {
if (!req.body) return next();
res.write(req.param.path);
});
Please note that the functions or middleware layers you add only apply to requests that match your path and http method.
path
Create create, add, and returns a new Application instance. The instance that is created is added as "sub" application so in order to access it needs to have the same path as application it was created upon.
The method requires one argument:
- name The name, URL, or path that the application should respond to.
var app = magikarp.path('foo')
, sub = app.path('bar');
app.get(function () { .. });
app.get(function () { .. });
In the example above, the sub
application can only be accessed using the
/foo/bar/
URL as it's created from the foo
application. See
routes for more details about the paths/routes/URL syntax that we
allow.
prev, previous
If you've created a sub application using the path
method you might want to
get the reference back to the application it was created upon. The prev
or
previous
method returns this reference:
var app = magikarp.path('foo')
, sub = app.path('bar');
console.log(sub.prev() === app); // true
mount
Mount allows you to directly pass in applications as sub
application without
the need to create one first. This is super useful when you want to modulize
your code base re-use applications.
The method accepts 1 argument:
- application The application that needs to be added as sub application.
var app = new magikarp.Application('foo')
, root = magikarp.path('hello');
root.mount(app);
Please note that the mount
method returns the added application. See the
sharing section for more information about re-using and mounting
applications.
optimize
Transforms the old internals that power the API sugar to a sophisticated middleware system that automatically handles all the request and middleware processing for us. This method is automatically called when you trigger the run method for the generation of a middleware layer.
The optimize method accepts one argument:
- context The
this
value for all the http/middleware methods.
var app = magikarp.path('foo');
app.get(function () { .. });
app.get(function () { .. });
app.optimize(magikarp.provider);
It's not hurtful to call the optimize method multiple times and it can be useful
if you wish to force a custom this
value for the applications.
run
Transform the application in a middleware layer which will trigger based on the supplied route and path.
The method accepts one argument:
- context The
this
value for all the http/middleware methods.
var app = magikarp.path('foo');
app.get(function () { .. });
app.get(function () { .. });
var middleware = app.run(magikarp.provider);
Sharing
One of the amazing aspects about these applications is that they can just be exported as separate files and there for also published as npm modules. Here's a small example on how you could share a dashboard application:
var app = require('magikarp').path('/dashboard/{id}/')
, fs = require('fs');
app
.get(require('static-server')(__dirname +'/static'));
.get(function (req, res, next) {
var file = __dirname +'/+ req.param.id +'.html';
fs.exists(file, function (exists) {
if (!exists) return next();
res.statusCode = 200;
res.setHeader('Content-Type', 'text/html');
fs.createReadStream(file).pipe(res);
});
});
//
// Expose the admin interface on the `module.exports` so return valued of a
// require references the application.
//
module.exports = app;
After installing this (fake) module using npm install
you can use it directly
in your application. The only thing you need to do is mount
it:
var app = require('magikarp').path('admin', module);
app
.mount(require('magikarp-dashboard'))
.get(function (req, res, next) {
res.statusCode = 404;
res.end('I handle the apps 404s');
});
So now when you navigate to /admin/dashboard/index
it will serve the
index.html
from the magikarp-dashboard
module.
Routes
An application can be mounted on one or multiple paths. The supplied path should
be a string that can optionally be pre and suffixed with a /
. When you omit
those we will automatically add them back internally.
/appname/
would match/appname/
appname
would match/appname/
/appname
would match/appname/
/appname/foo
would match/appname/foo/
In order to capture data or "params" from paths you can use special { .. }
placeholders in the pathnames. These pathnames will be automatically replaced
with an cat all Regular Expression and introduces the supplied name within the
curly braces as key with the path value in the req.param
object.
{foo}.js
would match/hello.js
,/bar.js
etc./static/{type}/{filename}.{ext}
would match/static/css/file.js
.
The combinations are endless.
License
MIT