1
0
Fork 0

Foxx: Starting with the Foxx User Documentation

This commit is contained in:
Lucas Dohmen 2013-03-25 09:50:32 +01:00
parent f483f1f137
commit 74e23f8670
3 changed files with 439 additions and 265 deletions

View File

@ -1,8 +1,64 @@
# Foxx: Build APIs and simple web applications in ArangoDB Foxx {#UserManualFoxx}
======================
Foxx: Build APIs and simple web applications in ArangoDB
========================================================
**WARNING: The following documentation file is pure fiction, **WARNING: The following documentation file is pure fiction,
it is not yet finished** it is not yet finished**
Foxx is an easy way to create APIs and simple web applications
from within **ArangoDB**.
It is inspired by Sinatra, the classy Ruby web framework. If FoxxApplication is Sinatra,
[ArangoDB Actions](http://www.arangodb.org/manuals/current/UserManualActions.html)
are the corresponding `Rack`. They provide all the HTTP goodness.
So let's get started, shall we?
## Foxx Application
@copydetails JSF_foxx_application_initializer
@copydetails JSF_foxx_application_start
### Handling Requests
@copydetails JSF_foxx_application_handleRequest
@copydetails JSF_foxx_application_head
@copydetails JSF_foxx_application_get
@copydetails JSF_foxx_application_post
@copydetails JSF_foxx_application_put
@copydetails JSF_foxx_application_patch
@copydetails JSF_foxx_application_delete
### Before and After Hooks
You can use the following two functions to do something
before or respectively after the normal routing process
is happening. You could use that for logging or to manipulate
the request or response (translate it to a certain format for
example).
@copydetails JSF_foxx_application_before
@copydetails JSF_foxx_application_after
### More functionality
@copydetails JSF_foxx_application_helper
@copydetails JSF_foxx_application_accepts
## The functions on a created FoxxApplication
When you have created your FoxxApplication you can now define routes
on it. You provide each with a function that will handle
the request. It gets two arguments (four, to be honest. But the
other two are not relevant for now):
* The request object
* The response object
You can find more about those in their individual sections.
An application build with Foxx is written in JavaScript and deployed An application build with Foxx is written in JavaScript and deployed
to ArangoDB directly. ArangoDB serves this application, you do not to ArangoDB directly. ArangoDB serves this application, you do not
need a separate application server. need a separate application server.

View File

@ -197,18 +197,18 @@ function SetRoutesFoxxApplicationSpec () {
var myFunc = function () {}, var myFunc = function () {},
routes = app.routingInfo.routes; routes = app.routingInfo.routes;
app.requires = { app.requiresLibs = {
a: 1 a: 1
}; };
app.models = { app.requiresModels = {
b: 2 b: 2
}; };
app.get('/simple/route', myFunc); app.get('/simple/route', myFunc);
app.start("myContext"); app.start("myContext");
assertEqual(app.routingInfo.routes[0].action.context, "myContext"); assertEqual(app.routingInfo.routes[0].action.context, "myContext");
assertEqual(app.routingInfo.routes[0].action.requires.a, 1); assertEqual(app.routingInfo.routes[0].action.requiresLibs.a, 1);
assertEqual(app.routingInfo.routes[0].action.models.b, 2); assertEqual(app.routingInfo.routes[0].action.requiresModels.b, 2);
} }
}; };
} }

View File

@ -1,15 +1,33 @@
/*jslint indent: 2, nomen: true, maxlen: 120, sloppy: true, vars: true */ /*jslint indent: 2, nomen: true, maxlen: 120, sloppy: true, vars: true */
/*global module, require, exports */ /*global module, require, exports */
// Foxx is an easy way to create APIs and simple web applications ////////////////////////////////////////////////////////////////////////////////
// from within **ArangoDB**. /// @brief Foxx application
// It is inspired by Sinatra, the classy Ruby web framework. If FoxxApplication is Sinatra, ///
// [ArangoDB Actions](http://www.arangodb.org/manuals/current/UserManualActions.html) /// @file
// are the corresponding `Rack`. They provide all the HTTP goodness. ///
// /// DISCLAIMER
// So let's get started, shall we? ///
/// Copyright 2013 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Lucas Dohmen
/// @author Copyright 2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
// FoxxApplication uses Underscore internally. This library is wonderful.
var FoxxApplication, var FoxxApplication,
BaseMiddleware, BaseMiddleware,
FormatMiddleware, FormatMiddleware,
@ -20,12 +38,19 @@ var FoxxApplication,
INTERNAL = require("internal"), INTERNAL = require("internal"),
internal = {}; internal = {};
// ArangoDB uses a certain structure we refer to as `UrlObject`. ////////////////////////////////////////////////////////////////////////////////
// With the following function (which is only internal, and not /// @fn JSF_foxx_createUrlObject
// exported) you can create an UrlObject with a given URL, /// @brief create a new url object
// a constraint and a method. For example: ///
// /// ArangoDB uses a certain structure we refer to as `UrlObject`.
// internal.createUrlObject('/lecker/gans', null, 'get') /// With the following function (which is only internal, and not
/// exported) you can create an UrlObject with a given URL,
/// a constraint and a method. For example:
///
/// @EXAMPLES
/// internal.createUrlObject('/lecker/gans', null, 'get')
////////////////////////////////////////////////////////////////////////////////
internal.createUrlObject = function (url, constraint, method) { internal.createUrlObject = function (url, constraint, method) {
'use strict'; 'use strict';
var urlObject = {}; var urlObject = {};
@ -44,18 +69,22 @@ internal.createUrlObject = function (url, constraint, method) {
return urlObject; return urlObject;
}; };
// ## Creating a new Application ////////////////////////////////////////////////////////////////////////////////
// And that's FoxxApplication. It's a constructor, so call it like this: /// @fn JSF_foxx_application_initializer
// /// @brief Create a new Application
// app = new FoxxApplication({ ///
// urlPrefix: "/wiese", /// And that's FoxxApplication. It's a constructor, so call it like this:
// templateCollection: "my_templates" /// It takes two optional arguments as displayed above:
// }) /// * **The URL Prefix:** All routes you define within will be prefixed with it
// /// * **The Template Collection:** More information in the template section
// It takes two optional arguments as displayed above: ///
// /// @EXAMPLES
// * **The URL Prefix:** All routes you define within will be prefixed with it /// app = new FoxxApplication({
// * **The Template Collection:** More information in the template section /// urlPrefix: "/wiese",
/// templateCollection: "my_templates"
/// });
////////////////////////////////////////////////////////////////////////////////
FoxxApplication = function (options) { FoxxApplication = function (options) {
'use strict'; 'use strict';
var urlPrefix, templateCollection, myMiddleware; var urlPrefix, templateCollection, myMiddleware;
@ -91,23 +120,17 @@ FoxxApplication = function (options) {
]; ];
}; };
// ## The functions on a created FoxxApplication
//
// When you have created your FoxxApplication you can now define routes
// on it. You provide each with a function that will handle
// the request. It gets two arguments (four, to be honest. But the
// other two are not relevant for now):
//
// * The request object
// * The response object
//
// You can find more about those in their individual sections.
_.extend(FoxxApplication.prototype, { _.extend(FoxxApplication.prototype, {
// Sometimes it is a good idea to actually start the application ////////////////////////////////////////////////////////////////////////////////
// you wrote. If this precious moment has arrived, you should /// @fn JSF_foxx_application_start
// use this function. /// @brief Start the application
// You have to provide the start function with the `applicationContext` ///
// variable. /// Sometimes it is a good idea to actually start the application
/// you wrote. If this precious moment has arrived, you should
/// use this function.
/// You have to provide the start function with the `applicationContext`
/// variable.
////////////////////////////////////////////////////////////////////////////////
start: function (context) { start: function (context) {
'use strict'; 'use strict';
var models = this.requiresModels, var models = this.requiresModels,
@ -125,18 +148,24 @@ _.extend(FoxxApplication.prototype, {
db._collection("_routing").save(this.routingInfo); db._collection("_routing").save(this.routingInfo);
}, },
// The `handleRequest` method is the raw way to create a new ////////////////////////////////////////////////////////////////////////////////
// route. You probably wont call it directly, but it is used /// @fn JSF_foxx_application_handleRequest
// in the other request methods: /// @brief Handle a request
// ///
// app.handleRequest("get", "/gaense", function (req, res) { /// The `handleRequest` method is the raw way to create a new
// //handle the request /// route. You probably wont call it directly, but it is used
// }); /// in the other request methods:
// ///
// When defining a route you can also define a so called 'parameterized' /// When defining a route you can also define a so called 'parameterized'
// route like `/gaense/:stable`. In this case you can later get the value /// route like `/gaense/:stable`. In this case you can later get the value
// the user provided for `stable` via the `params` function (see the Request /// the user provided for `stable` via the `params` function (see the Request
// object). /// object).
///
/// @EXAMPLES
/// app.handleRequest("get", "/gaense", function (req, res) {
/// //handle the request
/// });
////////////////////////////////////////////////////////////////////////////////
handleRequest: function (method, route, argument1, argument2) { handleRequest: function (method, route, argument1, argument2) {
'use strict'; 'use strict';
var newRoute = {}, options, callback; var newRoute = {}, options, callback;
@ -157,97 +186,124 @@ _.extend(FoxxApplication.prototype, {
this.routingInfo.routes.push(newRoute); this.routingInfo.routes.push(newRoute);
}, },
// ### Handle a `head` request ////////////////////////////////////////////////////////////////////////////////
// This handles requests from the HTTP verb `head`. /// @fn JSF_foxx_application_head
// As with all other requests you can give an option as the third /// @brief Handle a `head` request
// argument, or leave it blank. You have to give a function as ///
// the last argument however. It will get a request and response /// This handles requests from the HTTP verb `head`.
// object as its arguments /// As with all other requests you can give an option as the third
/// argument, or leave it blank. You have to give a function as
/// the last argument however. It will get a request and response
/// object as its arguments
////////////////////////////////////////////////////////////////////////////////
head: function (route, argument1, argument2) { head: function (route, argument1, argument2) {
'use strict'; 'use strict';
this.handleRequest("head", route, argument1, argument2); this.handleRequest("head", route, argument1, argument2);
}, },
// ### Manage a `get` request ////////////////////////////////////////////////////////////////////////////////
// This handles requests from the HTTP verb `get`. /// @fn JSF_foxx_application_get
// See above for the arguments you can give. An example: /// @brief Manage a `get` request
// ///
// app.get('/gaense/stall', function (req, res) { /// This handles requests from the HTTP verb `get`.
// // Take this request and deal with it! /// See above for the arguments you can give. An example:
// }); ///
/// @EXAMPLES
/// app.get('/gaense/stall', function (req, res) {
/// // Take this request and deal with it!
/// });
////////////////////////////////////////////////////////////////////////////////
get: function (route, argument1, argument2) { get: function (route, argument1, argument2) {
'use strict'; 'use strict';
this.handleRequest("get", route, argument1, argument2); this.handleRequest("get", route, argument1, argument2);
}, },
// ### Tackle a `post` request ////////////////////////////////////////////////////////////////////////////////
// This handles requests from the HTTP verb `post`. /// @fn JSF_foxx_application_post
// See above for the arguments you can give. An example: /// @brief Tackle a `post` request
// ///
// app.post('/gaense/stall', function (req, res) { /// This handles requests from the HTTP verb `post`.
// // Take this request and deal with it! /// See above for the arguments you can give. An example:
// }); ///
/// @EXAMPLES
/// app.post('/gaense/stall', function (req, res) {
/// // Take this request and deal with it!
/// });
////////////////////////////////////////////////////////////////////////////////
post: function (route, argument1, argument2) { post: function (route, argument1, argument2) {
'use strict'; 'use strict';
this.handleRequest("post", route, argument1, argument2); this.handleRequest("post", route, argument1, argument2);
}, },
// ### Sort out a `put` request ////////////////////////////////////////////////////////////////////////////////
// This handles requests from the HTTP verb `put`. /// @fn JSF_foxx_application_put
// See above for the arguments you can give. An example: /// @brief Sort out a `put` request
// ///
// app.put('/gaense/stall', function (req, res) { /// This handles requests from the HTTP verb `put`.
// // Take this request and deal with it! /// See above for the arguments you can give. An example:
// }); ///
/// @EXAMPLES
/// app.put('/gaense/stall', function (req, res) {
/// // Take this request and deal with it!
/// });
////////////////////////////////////////////////////////////////////////////////
put: function (route, argument1, argument2) { put: function (route, argument1, argument2) {
'use strict'; 'use strict';
this.handleRequest("put", route, argument1, argument2); this.handleRequest("put", route, argument1, argument2);
}, },
// ### Take charge of a `patch` request ////////////////////////////////////////////////////////////////////////////////
// This handles requests from the HTTP verb `patch`. /// @fn JSF_foxx_application_patch
// See above for the arguments you can give. An example: /// @brief Take charge of a `patch` request
// ///
// app.patch('/gaense/stall', function (req, res) { /// This handles requests from the HTTP verb `patch`.
// // Take this request and deal with it! /// See above for the arguments you can give. An example:
// }); ///
/// @EXAMPLES
/// app.patch('/gaense/stall', function (req, res) {
/// // Take this request and deal with it!
/// });
////////////////////////////////////////////////////////////////////////////////
patch: function (route, argument1, argument2) { patch: function (route, argument1, argument2) {
'use strict'; 'use strict';
this.handleRequest("patch", route, argument1, argument2); this.handleRequest("patch", route, argument1, argument2);
}, },
// ### Respond to a `delete` request ////////////////////////////////////////////////////////////////////////////////
// This handles requests from the HTTP verb `delete`. /// @fn JSF_foxx_application_delete
// See above for the arguments you can give. /// @brief Respond to a `delete` request
// **A word of warning:** Do not forget that `delete` is ///
// a reserved word in JavaScript so call it as follows: /// This handles requests from the HTTP verb `delete`.
// /// See above for the arguments you can give.
// app['delete']('/gaense/stall', function (req, res) { /// **A word of warning:** Do not forget that `delete` is
// // Take this request and deal with it! /// a reserved word in JavaScript so call it as follows:
// }); ///
/// @EXAMPLES
/// app['delete']('/gaense/stall', function (req, res) {
/// // Take this request and deal with it!
/// });
////////////////////////////////////////////////////////////////////////////////
'delete': function (route, argument1, argument2) { 'delete': function (route, argument1, argument2) {
'use strict'; 'use strict';
this.handleRequest("delete", route, argument1, argument2); this.handleRequest("delete", route, argument1, argument2);
}, },
// ## Before and After Hooks ////////////////////////////////////////////////////////////////////////////////
// You can use the following two functions to do something /// @fn JSF_foxx_application_before
// before or respectively after the normal routing process /// @brief Before
// is happening. You could use that for logging or to manipulate ///
// the request or response (translate it to a certain format for /// The before function takes a path on which it should watch
// example). /// and a function that it should execute before the routing
/// takes place. If you do omit the path, the function will
// ### Before /// be executed before each request, no matter the path.
// The before function takes a path on which it should watch /// Your function gets a Request and a Response object.
// and a function that it should execute before the routing /// An example:
// takes place. If you do omit the path, the function will ///
// be executed before each request, no matter the path. /// @EXAMPLES
// Your function gets a Request and a Response object. /// app.before('/high/way', function(req, res) {
// An example: /// //Do some crazy request logging
// /// });
// app.before('/high/way', function(req, res) { ////////////////////////////////////////////////////////////////////////////////
// //Do some crazy request logging
// });
before: function (path, func) { before: function (path, func) {
'use strict'; 'use strict';
if (_.isUndefined(func)) { if (_.isUndefined(func)) {
@ -263,16 +319,21 @@ _.extend(FoxxApplication.prototype, {
}); });
}, },
// ### After ////////////////////////////////////////////////////////////////////////////////
// This works pretty similar to the before function. /// @fn JSF_foxx_application_after
// But it acts after the execution of the handlers /// @brief After
// (Big surprise, I suppose). ///
// /// This works pretty similar to the before function.
// An example: /// But it acts after the execution of the handlers
// /// (Big surprise, I suppose).
// app.after('/high/way', function(req, res) { ///
// //Do some crazy response logging /// An example:
// }); ///
/// @EXAMPLES
/// app.after('/high/way', function(req, res) {
/// //Do some crazy response logging
/// });
////////////////////////////////////////////////////////////////////////////////
after: function (path, func) { after: function (path, func) {
'use strict'; 'use strict';
if (_.isUndefined(func)) { if (_.isUndefined(func)) {
@ -288,27 +349,36 @@ _.extend(FoxxApplication.prototype, {
}); });
}, },
// ## The ViewHelper concept ////////////////////////////////////////////////////////////////////////////////
// If you want to use a function inside your templates, the ViewHelpers /// @fn JSF_foxx_application_helper
// will come to rescue you. Define them on your app like this: /// @brief The ViewHelper concept
// ///
// app.helper("link_to", function (identifier) { /// If you want to use a function inside your templates, the ViewHelpers
// return urlRepository[identifier]; /// will come to rescue you. Define them on your app like this:
// }); ///
// /// @EXAMPLES
// Then you can just call this function in your template's JavaScript /// app.helper("link_to", function (identifier) {
// blocks. /// return urlRepository[identifier];
/// });
///
/// Then you can just call this function in your template's JavaScript
/// blocks.
////////////////////////////////////////////////////////////////////////////////
helper: function (name, func) { helper: function (name, func) {
'use strict'; 'use strict';
this.helperCollection[name] = func; this.helperCollection[name] = func;
}, },
// ## Shortform for using the FormatMiddleware ////////////////////////////////////////////////////////////////////////////////
// /// @fn JSF_foxx_application_accepts
// More information about the FormatMiddleware in the corresponding section. /// @brief Shortform for using the FormatMiddleware
// This is a shortcut to add the middleware to your application: ///
// /// More information about the FormatMiddleware in the corresponding section.
// app.accepts(["json"], "json"); /// This is a shortcut to add the middleware to your application:
///
/// @EXAMPLES
/// app.accepts(["json"], "json");
////////////////////////////////////////////////////////////////////////////////
accepts: function (allowedFormats, defaultFormat) { accepts: function (allowedFormats, defaultFormat) {
'use strict'; 'use strict';
@ -322,9 +392,13 @@ _.extend(FoxxApplication.prototype, {
}); });
// ## The Base Middleware ////////////////////////////////////////////////////////////////////////////////
// The `BaseMiddleware` manipulates the request and response /// @fn JSF_foxx_BaseMiddleware_initializer
// objects to give you a nicer API. /// @brief The Base Middleware
///
/// The `BaseMiddleware` manipulates the request and response
/// objects to give you a nicer API.
////////////////////////////////////////////////////////////////////////////////
BaseMiddleware = function (templateCollection, helperCollection) { BaseMiddleware = function (templateCollection, helperCollection) {
'use strict'; 'use strict';
var middleware = function (request, response, options, next) { var middleware = function (request, response, options, next) {
@ -332,29 +406,39 @@ BaseMiddleware = function (templateCollection, helperCollection) {
requestFunctions, requestFunctions,
_ = require("underscore"); _ = require("underscore");
// ### The Request Object ////////////////////////////////////////////////////////////////////////////////
// Every request object has the following attributes from the underlying Actions, /// The Request Object
// amongst others: /// Every request object has the following attributes from the underlying Actions,
// /// amongst others:
// * path: The complete path as supplied by the user ///
// /// * path: The complete path as supplied by the user
// FoxxApplication adds the following methods to this request object: ///
/// FoxxApplication adds the following methods to this request object:
////////////////////////////////////////////////////////////////////////////////
requestFunctions = { requestFunctions = {
// ### The superfluous `body` function ////////////////////////////////////////////////////////////////////////////////
// Get the body of the request /// @fn JSF_foxx_BaseMiddleware_request_body
/// @brief The superfluous `body` function
///
/// Get the body of the request
////////////////////////////////////////////////////////////////////////////////
body: function () { body: function () {
return this.requestBody; return this.requestBody;
}, },
// ### The jinxed `params` function ////////////////////////////////////////////////////////////////////////////////
// Get the parameters of the request. This process is two-fold: /// @fn JSF_foxx_BaseMiddleware_request_params
// /// @brief The jinxed `params` function
// 1. If you have defined an URL like `/test/:id` and the user ///
// requested `/test/1`, the call `params("id")` will return `1`. /// Get the parameters of the request. This process is two-fold:
// 2. If you have defined an URL like `/test` and the user gives a ///
// query component, the query parameters will also be returned. /// 1. If you have defined an URL like `/test/:id` and the user
// So for example if the user requested `/test?a=2`, the call /// requested `/test/1`, the call `params("id")` will return `1`.
// `params("a")` will return `2`. /// 2. If you have defined an URL like `/test` and the user gives a
/// query component, the query parameters will also be returned.
/// So for example if the user requested `/test?a=2`, the call
/// `params("a")` will return `2`.
////////////////////////////////////////////////////////////////////////////////
params: function (key) { params: function (key) {
var ps = {}; var ps = {};
_.extend(ps, this.urlParameters); _.extend(ps, this.urlParameters);
@ -363,36 +447,50 @@ BaseMiddleware = function (templateCollection, helperCollection) {
} }
}; };
// ### The Response Object ////////////////////////////////////////////////////////////////////////////////
// Every response object has the following attributes from the underlying Actions: /// The Response Object
// /// Every response object has the following attributes from the underlying Actions:
// * contentType ///
// * responseCode /// * contentType
// * body /// * responseCode
// * headers (an object) /// * body
// /// * headers (an object)
// FoxxApplication adds the following methods to this response object. ///
/// FoxxApplication adds the following methods to this response object.
////////////////////////////////////////////////////////////////////////////////
responseFunctions = { responseFunctions = {
// ### The straightforward `status` function ////////////////////////////////////////////////////////////////////////////////
// Set the status code of your response, for example: /// @fn JSF_foxx_BaseMiddleware_response_status
// /// @brief The straightforward `status` function
// response.status(404); ///
/// Set the status code of your response, for example:
///
/// @EXAMPLES
/// response.status(404);
////////////////////////////////////////////////////////////////////////////////
status: function (code) { status: function (code) {
this.responseCode = code; this.responseCode = code;
}, },
// ### The radical `set` function ////////////////////////////////////////////////////////////////////////////////
// Set a header attribute, for example: /// @fn JSF_foxx_BaseMiddleware_response_set
// /// @brief The radical `set` function
// response.set("Content-Length", 123); ///
// response.set("Content-Type", "text/plain"); /// Set a header attribute, for example:
// ///
// or alternatively: /// @EXAMPLES
// /// response.set("Content-Length", 123);
// response.set({ /// response.set("Content-Type", "text/plain");
// "Content-Length": "123", ///
// "Content-Type": "text/plain" /// or alternatively:
// }); ///
/// @EXAMPLES
/// response.set({
/// "Content-Length": "123",
/// "Content-Type": "text/plain"
/// });
////////////////////////////////////////////////////////////////////////////////
set: function (key, value) { set: function (key, value) {
var attributes = {}; var attributes = {};
if (_.isUndefined(value)) { if (_.isUndefined(value)) {
@ -412,46 +510,57 @@ BaseMiddleware = function (templateCollection, helperCollection) {
}, this); }, this);
}, },
// ### The magical `json` function ////////////////////////////////////////////////////////////////////////////////
// Set the content type to JSON and the body to the /// @fn JSF_foxx_BaseMiddleware_response_json
// JSON encoded object you provided. /// @brief The magical `json` function
// ///
// response.json({'born': 'December 12, 1915'}); /// Set the content type to JSON and the body to the
/// JSON encoded object you provided.
///
/// @EXAMPLES
/// response.json({'born': 'December 12, 1915'});
////////////////////////////////////////////////////////////////////////////////
json: function (obj) { json: function (obj) {
this.contentType = "application/json"; this.contentType = "application/json";
this.body = JSON.stringify(obj); this.body = JSON.stringify(obj);
}, },
// ### The mysterious `render` function ////////////////////////////////////////////////////////////////////////////////
// If you initialize your FoxxApplication with a `templateCollection`, /// @fn JSF_foxx_BaseMiddleware_response_render
// you're in luck now. /// @brief The mysterious `render` function
// It expects documents in the following form in this collection: ///
// /// If you initialize your FoxxApplication with a `templateCollection`,
// { /// you're in luck now.
// path: "high/way", /// It expects documents in the following form in this collection:
// content: "hallo <%= username %>", ///
// contentType: "text/plain", /// @EXAMPLES
// templateLanguage: "underscore" /// {
// } /// path: "high/way",
// /// content: "hallo <%= username %>",
// The `content` is the string that will be rendered by the template /// contentType: "text/plain",
// processor. The `contentType` is the type of content that results /// templateLanguage: "underscore"
// from this call. And with the `templateLanguage` you can choose /// }
// your template processor. There is only one choice now: `underscore`. ///
// /// The `content` is the string that will be rendered by the template
// If you call render, FoxxApplication will look /// processor. The `contentType` is the type of content that results
// into the this collection and search by the path attribute. /// from this call. And with the `templateLanguage` you can choose
// It will then render the template with the given data: /// your template processor. There is only one choice now: `underscore`.
// ///
// response.render("high/way", {username: 'FoxxApplication'}) /// If you call render, FoxxApplication will look
// /// into the this collection and search by the path attribute.
// Which would set the body of the response to `hello FoxxApplication` with the /// It will then render the template with the given data:
// template defined above. It will also set the `contentType` to ///
// `text/plain` in this case. /// @EXAMPLES
// /// response.render("high/way", {username: 'FoxxApplication'})
// In addition to the attributes you provided, you also have access to ///
// all your view helpers. How to define them? Read above in the /// Which would set the body of the response to `hello FoxxApplication` with the
// ViewHelper section. /// template defined above. It will also set the `contentType` to
/// `text/plain` in this case.
///
/// In addition to the attributes you provided, you also have access to
/// all your view helpers. How to define them? Read above in the
/// ViewHelper section.
////////////////////////////////////////////////////////////////////////////////
render: function (templatePath, data) { render: function (templatePath, data) {
var template; var template;
@ -474,9 +583,9 @@ BaseMiddleware = function (templateCollection, helperCollection) {
} }
}; };
// Now enhance the request and response as described above and call next at the /// Now enhance the request and response as described above and call next at the
// end of this middleware (otherwise your application would never /// end of this middleware (otherwise your application would never
// be executed. Would be a shame, really). /// be executed. Would be a shame, really).
request = _.extend(request, requestFunctions); request = _.extend(request, requestFunctions);
response = _.extend(response, responseFunctions); response = _.extend(response, responseFunctions);
next(); next();
@ -488,32 +597,37 @@ BaseMiddleware = function (templateCollection, helperCollection) {
}; };
}; };
// ## The Format Middleware ////////////////////////////////////////////////////////////////////////////////
// Unlike the `BaseMiddleware` this Middleware is only loaded if you /// @brief The Format Middleware
// want it. This Middleware gives you Rails-like format handling via ///
// the `extension` of the URL or the accept header. /// Unlike the `BaseMiddleware` this Middleware is only loaded if you
// Say you request an URL like `/people.json`: /// want it. This Middleware gives you Rails-like format handling via
// The `FormatMiddleware` will set the format of the request to JSON /// the `extension` of the URL or the accept header.
// and then delete the `.json` from the request. You can therefore write /// Say you request an URL like `/people.json`:
// handlers that do not take an `extension` into consideration and instead /// The `FormatMiddleware` will set the format of the request to JSON
// handle the format via a simple String. /// and then delete the `.json` from the request. You can therefore write
// To determine the format of the request it checks the URL and then /// handlers that do not take an `extension` into consideration and instead
// the `accept` header. If one of them gives a format or both give /// handle the format via a simple String.
// the same, the format is set. If the formats are not the same, /// To determine the format of the request it checks the URL and then
// an error is raised. /// the `accept` header. If one of them gives a format or both give
// /// the same, the format is set. If the formats are not the same,
// Use it by calling: /// an error is raised.
// ///
// FormatMiddleware = require('foxx').FormatMiddleware; /// Use it by calling:
// app.before("/*", FormatMiddleware.new(['json'])); ///
// /// @EXAMPLES
// or the shortcut: /// FormatMiddleware = require('foxx').FormatMiddleware;
// /// app.before("/*", FormatMiddleware.new(['json']));
// app.accepts(['json']); ///
// /// or the shortcut:
// In both forms you can give a default format as a second parameter, ///
// if no format could be determined. If you give no `defaultFormat` this /// @EXAMPLES
// case will be handled as an error. /// app.accepts(['json']);
///
/// In both forms you can give a default format as a second parameter,
/// if no format could be determined. If you give no `defaultFormat` this
/// case will be handled as an error.
////////////////////////////////////////////////////////////////////////////////
FormatMiddleware = function (allowedFormats, defaultFormat) { FormatMiddleware = function (allowedFormats, defaultFormat) {
'use strict'; 'use strict';
var stringRepresentation, middleware = function (request, response, options, next) { var stringRepresentation, middleware = function (request, response, options, next) {
@ -588,8 +702,8 @@ FormatMiddleware = function (allowedFormats, defaultFormat) {
}; };
}; };
// We finish off with exporting FoxxApplication and the middlewares. /// We finish off with exporting FoxxApplication and the middlewares.
// Everything else will remain our secret. /// Everything else will remain our secret.
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief loads a manifest file /// @brief loads a manifest file
@ -654,11 +768,15 @@ exports.FoxxApplication = FoxxApplication;
exports.BaseMiddleware = BaseMiddleware; exports.BaseMiddleware = BaseMiddleware;
exports.FormatMiddleware = FormatMiddleware; exports.FormatMiddleware = FormatMiddleware;
// ----------------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////////////
// --SECTION-- END-OF-FILE /// @}
// ----------------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////////////
// Local Variables: /// -----------------------------------------------------------------------------
// mode: outline-minor /// --SECTION-- END-OF-FILE
// outline-regexp: "/// @brief\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}\\|/\\*jslint" /// -----------------------------------------------------------------------------
// End:
/// Local Variables:
/// mode: outline-minor
/// outline-regexp: "/// @brief\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}\\|/\\*jslint"
/// End: