neft
Version:
Universal Platform
286 lines (198 loc) • 7.01 kB
text/coffeescript
# Response
'use strict'
utils = require 'src/utils'
assert = require 'src/assert'
log = require 'src/log'
signal = require 'src/signal'
assert = assert.scope 'Networking.Response'
log = log.scope 'Networking', 'Response'
# **Class** Response
module.exports = (Networking, Impl) -> class Response extends signal.Emitter
## *Array* Response.STATUSES
Contains abstract codes used to describe the response type.
Each status corresponds to the HTTP numeral value.
Check [http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html]() for more.
Contains:
- Response.OK,
- Response.CREATED,
- Response.ACCEPTED,
- Response.NO_CONTENT,
- Response.MOVED,
- Response.FOUND,
- Response.NOT_MODIFIED,
- Response.TEMPORARY_REDIRECT,
- Response.BAD_REQUEST,
- Response.UNAUTHORIZED,
- Response.PAYMENT_REQUIRED,
- Response.FORBIDDEN,
- Response.NOT_FOUND,
- Response.CONFLICT,
- Response.PRECONDITION_FAILED,
- Response.UNSUPPORTED_MEDIA_TYPE,
- Response.INTERNAL_SERVER_ERROR,
- Response.NOT_IMPLEMENTED,
- Response.SERVICE_UNAVAILABLE.
```javascript
console.log(Networking.Response.OK);
console.log(Networking.Response.BAD_REQUEST);
```
@STATUSES = [
# Success
(@OK = 200),
(@CREATED = 201),
(@ACCEPTED = 202),
(@NO_CONTENT = 204),
# Redirection
(@MOVED = 301),
(@FOUND = 302),
(@NOT_MODIFIED = 304),
(@TEMPORARY_REDIRECT = 307),
# Client error
(@BAD_REQUEST = 400),
(@UNAUTHORIZED = 401),
(@PAYMENT_REQUIRED = 402),
(@FORBIDDEN = 403),
(@NOT_FOUND = 404),
(@METHOD_NOT_ALLOWED = 405),
(@NOT_ACCEPTABLE = 406),
(@CONFLICT = 409),
(@PRECONDITION_FAILED = 412),
(@UNSUPPORTED_MEDIA_TYPE = 415),
# Server error
(@INTERNAL_SERVER_ERROR = 500),
(@NOT_IMPLEMENTED = 501),
(@SERVICE_UNAVAILABLE = 503)
]
@Error = require('./response/error') Networking, Response
## Response::constructor(*Object* options)
Access it with:
```javascript
var Networking = require('networking');
var Response = Networking.Response;
```
constructor: (opts) ->
assert.isPlainObject opts, 'ctor options argument ...'
assert.instanceOf opts.request, Networking.Request, 'ctor options.request argument ...'
super()
if opts.status?
assert.ok utils.has(Response.STATUSES, opts.status), 'ctor options.status argument ...'
{@status} = opts
if opts.data?
{@data} = opts
if opts.encoding?
{@encoding} = opts
@headers = opts.headers or {}
@cookies = opts.cookies or {}
utils.defineProperty @, 'request', null, opts.request
@pending = true
# signal handlers
if opts.onSend
@onSend opts.onSend
if opts.status?
@send()
## *Signal* Response::onSend()
Called when the response has been sent.
```javascript
res.onSend(function(){
console.log("Response has been sent!");
});
```
signal.Emitter.createSignal @, 'onSend'
## ReadOnly *Boolean* Response::pending
Indicates whether the response is not destroyed.
pending: false
## ReadOnly *Networking.Request* Response::request
Refers to the [Request][networking/Request].
request: null
## *Integer* Response::status = Response.OK
Keeps a normalized code determined the response type.
It refers to one of the *Response.STATUSES* values.
```javascript
res.status = Networking.Response.CREATED;
res.status = Networking.Response.PAYMENT_REQUIRED;
```
status: @OK
## *Any* Response::data
Value sent to the client.
```javascript
res.data = {items: ['superhero toy', 'book']};
res.data = new Error("Wrong order");
res.data = Document.fromJSON(...);
```
data: null
## *Object* Response::headers
headers: null
## *Object* Response::cookies
cookies: null
## *String* Response::encoding = 'utf-8'
encoding: 'utf-8'
## *Response* Response::setHeader(*String* name, *String* value)
```javascript
res.setHeader('Location', '/redirect/to/url');
```
setHeader: (name, val) ->
assert.ok @request.pending
assert.isString name, '::setHeader name argument ...'
assert.notLengthOf name, 0, '::setHeader name argument ...'
assert.isString val, '::setHeader value argument ...'
assert.notLengthOf val, 0, '::setHeader value argument ...'
Impl.setHeader @, name, val
@
## Response::send([*Integer* status, *Any* data])
This method calls the [onSend()][networking/Response::onSend()] signal.
```javascript
res.onSend(function(){
console.log("Response has been sent");
});
res.send(Networking.Response.OK, {user: 'Max', age: 43});
```
send: (status, data) ->
assert.ok @request.pending
if not data? and typeof status isnt 'number'
data = status
status = @status
if status?
assert.ok utils.has(Response.STATUSES, status)
@status = status
if data isnt undefined
@data = data
@request.destroy()
{data} = @
Impl.send @, data, =>
@pending = false
@onSend.emit()
return
## Response::redirect(*Integer* status = `Response.FOUND`, *String* uri)
The *Response.FOUND* status is typically used for the temporary redirection.
The *Response.MOVED* for is a permanent redirection.
redirect: (status, uri) ->
if uri is undefined
uri = status
status = Response.FOUND
assert.ok @request.pending
assert.ok utils.has(Response.STATUSES, status)
assert.isString uri
log "#{status} redirect to '#{uri}'"
@status = status
@setHeader 'Location', uri
@request.destroy()
Impl.redirect @, status, uri, =>
@pending = false
@onSend.emit()
## Response::raise(*Any* error)
Finishes the response with an error.
```javascript
res.raise(new Networking.Response.Error("Login first"));
res.raise(new Networking.Response.Error(Networking.Response.UNAUTHORIZED, "Login first"));
```
raise: (error) ->
if error instanceof Response.Error or isFinite(error?.status)
@send error.status, error
else
@send Response.INTERNAL_SERVER_ERROR, error
## *Boolean* Response::isSucceed()
Returns `true` if the response status is in range from 200 to 299.
isSucceed: ->
300 > @status >= 200
# Glossary
- [Networking.Response](#class-response)