What is returned by the Route method will be sent to the client as the response. The Routing section touched this briefly, here we will go over all the options of respoding to a request.
All returned and resolved values that are not Response
objects will be converted
to Response
objects at some point. When this happens, if your route does not
specify the type of response, a default will be chosen from the context. The
defaults and their conditions are-
200 - Is the default for any resolved/returned request with a payload.
204 - Is the default for any resolved/returned request without a payload.
400 - Is the default for any request that has missing required injectables
or fails DTO
validation.
500 - Is the default for any rejected request, thrown error, failed rule
,
or failed resource resolution
.
For more control over the status code, the generically named Response
object
should be used. When creating a response, you should provide the http status code
as well as the data to be sent to the client.
import {Route, Response} from 'expresskit';
export class FooRouter {
@Route('GET', '/foo')
public static fooRoute() {
return 'foo';
// is the same as
return new Response(200, 'foo');
// is the same as
return Promise.resolve('foo');
// is the same as
return Promise.resolve(new Response(200, 'foo'));
}
}
To respond with an error you can simple return a response with an error code.
return new Response(500, 'something bad happened');
Under two conditions will an error be assumed. Those conditions are if the route
encounters a Thrown Error
or Rejected Promise
. In these cases, the status code
will default to a 500 Internal Server Error
. However, a thrown Error
is not the
same as a thrown Resposne
.
import {Route} from 'expresskit';
export class FooRouter {
@Route('GET', '/foo')
public static fooRoute() {
throw new Error('An error occured')
// is NOT the same as
return Promise.reject('An error occured');
}
}
If an error is thrown, it assumed that there is an actual runtime error and the
stacktrace will be returned. You can throw intended errors by throwing a Response
.
import {Route, Response} from 'expresskit';
export class FooRouter {
@Route('GET', '/foo')
public static fooRoute() {
return new Response(500, 'An error occured');
// is the same as
throw new Response(500, 'An error occured')
// is the same as
return Promise.reject('An error occured');
// is the same as
return Promise.reject(new Response(500, 'An error occured'));
}
}
For convenience sake, some response factories are available. Each response factory defaults the response code as well as the response value if not given.
import {Route, Response} from 'expresskit';
export class FooRouter {
@Route('GET', '/foo')
public static fooRoute() {
return Response.NotFound(`Couldn't find Foo`);
}
}
The available factories and their values are-
Factory Function | Resposne Code | Default Response Value |
---|---|---|
Ok | 200 | Ok |
Created | 201 | Created |
Accepted | 202 | Accepted |
None | 204 | |
BadRequest | 400 | Bad Request |
Unauthorized | 401 | Unauthorized |
PaymentRequired | 402 | Payment Required |
Forbidden | 403 | Forbidden |
NotFound | 404 | Not Found |
MethodNotAllowed | 405 | Method Not Allowed |
NotAcceptable | 406 | Not Acceptable |
Conflict | 409 | Conflict |
Gone | 410 | No Long Available |
Error | 500 | Internal Server Error |
NotImplemented | 501 | Not Implemented |
BadGateway | 502 | Bad Gateway |
TemporarilyUnavailable | 503 | Temporarily Unavailable |
GatewayTimeout | 504 | GatewayTimeout |
Returning a Response
should be used if the route or rule may return different
types of responses. For everything else, use the ResponseCode
and ErrorCode
decorators if you don't intended to use the defaults. These decorators override
the default response codes for success and error responses. Only one default
response code and error code can be used for a particular Route
, Rule
, or
Resolver
.
import {Route, Param, Resolver, ResponseCode, ErrorCode} from 'expresskit';
export class WidgetRouter {
@Resolver('Widget')
@Route('GET', '/widget/:id')
@ResponseCode(200) // Redundant but you get the point
@ErrorCode(404)
public static getWidget(@Param('id') id: string): Promise<Widget> {
let widget = /* get widget from database*/;
if(widget) {
return Promise.resolve(widget);
} else {
return Promise.reject(`Widget by id '${id}' not found.`);
}
}
}
In the above example, the getWidget
method is both a Route
and a Resource Resolver
. If another route wants to resolve the Widget
resource for that route
using this resolver, a 404
error will be returned that the resolution fails.
import {Route, Param, Resolver, ResponseCode, ErrorCode} from 'expresskit';
export class WidgetRouter {
@Resolver('Widget')
@Route('GET', '/widget/:id')
@ResponseCode(200) // Redundant but you get the point
@ErrorCode(404)
public static getWidget(@Param('id') id: string): Promise<Widget> {
let widget = /* get widget from database*/;
if(widget) {
return Promise.resolve(widget);
} else {
return Promise.reject(`Widget by id '${id}' not found.`);
}
}
// If `Widget` cannot be resolved, a 404 error will be returned
@Route('PUT', '/widget/:id')
public static updateWidget(@Resource('Widget') widget: Widget) {
// update widget
}