neft
Version:
Universal Platform
149 lines (103 loc) • 4.54 kB
text/coffeescript
# Handler
'use strict'
utils = require 'src/utils'
assert = require 'src/assert'
log = require 'src/log'
Schema = require 'src/schema'
{parse, stringify} = JSON
assert = assert.scope 'Networking.Handler'
log = log.scope 'Networking', 'Handler'
# **Class** Handler
Represents a callback function called on the request.
Each handler must determine an uri, which is compared with the got request URI.
You should use `createHandler()` to create a functional handler.
Access it with:
```javascript
var Networking = require('networking');
var Handler = Networking.Handler;
```
module.exports = (Networking) -> class Handler
## Handler::constructor(*Object* options)
constructor: (opts) ->
assert.isPlainObject opts, 'ctor options argument ...'
assert.ok utils.has(Networking.Request.METHODS, opts.method), 'ctor options.method argument ...'
assert.instanceOf opts.uri, Networking.Uri, 'ctor options.uri argument ...'
assert.instanceOf opts.schema, Schema, 'ctor options.schema argument ...' if opts.schema?
assert.isFunction opts.callback, 'ctor options.callback argument ...'
{@method, @uri, @schema, @callback} = opts
## *String* Handler::method
Describes which type of the request, this handler can handle.
method: ''
## *Networking.Uri* Handler::uri
This property is compared with the request uri.
uri: null
## *Schema* Handler::schema = null
Used to determine whether the request uri is valid and can be handled by the handler callback.
schema: null
## *Function* Handler::callback
Function used to handle the request.
It's called with three parameters: *Networking.Request*, *Networking.Response* and
a *next* function.
If the *next* function is called, the next handler is checked.
callback: null
## Handler::exec(*Networking.Request* request, *Networking.Response* response, *Function* next)
Executes the handler, that is:
- compares the uri with the request,
- validates the request uri with the schema,
- calls the handler callback.
It's internally called by the `createRequest()`.
exec: (req, res, next) ->
assert.instanceOf req, Networking.Request, '::exec request argument ...'
assert.instanceOf res, Networking.Response, '::exec response argument ...'
assert.isFunction next, '::exec next argument ...'
# compare methods
if @method isnt req.method
return next()
# test uri
unless @uri.test(req.uri.path)
return next()
params = req.params = @uri.match req.uri.path
# validate by schema
if @schema
# parse params into expected types
for key, schemaOpts of @schema.schema
if params.hasOwnProperty(key) and schemaOpts.type and schemaOpts.type isnt 'string'
params[key] = utils.tryFunction parse, null, [params[key]], params[key]
# validate schema
err = utils.catchError @schema.validate, @schema, [params]
if err instanceof Error
return next err
# on callback fail
callbackNext = (err) =>
req.handler = null
if err? and err isnt true
errMsg = err
if errMsg.stack?
if utils.isQt
errMsg = "#{err.message}\n#{err.stack}"
else
errMsg = err.stack
else if utils.isObject(errMsg)
errMsg = utils.tryFunction JSON.stringify, null, [errMsg], errMsg
if errMsg
log.error "Error in '#{@uri}': #{errMsg}"
if err instanceof RangeError or
err instanceof TypeError or
err instanceof SyntaxError or
err instanceof ReferenceError
errMsg = "Internal Error; message has been removed"
next errMsg
else
next()
req.handler = @
@callback req, res, callbackNext
null
## *String* Handler::toString()
Returns a string describing the handler.
```javascript
"get /users/{name}"
```
toString: ->
"#{@method} #{@uri}"
# Glossary
- [Networking.Handler](#class-handler)