-
Notifications
You must be signed in to change notification settings - Fork 0
2. HttpController
Module: arestme/http
HttpController is the core class in module arestme/http. It implements generic controller logic to delegate request/response processing to a matching handler function according, to a predefined configuration. You can create instances of it, one per ScriptingService file, configure with handlers and invoke its service method to handle a request, or use the constructor function to extend it into your own.
The simplest HTTP service that you can create with aRESTme HttpController looks like this:
require('arestme/http').get().service();
Congratulations! You've got a service now. If you save this code in a file myservice.js
in a Dirigible project's ScriptingServices
section, you can request it as HTTP resource: GET /services/js/myservice.js
and it will service your request.
Check Dirigible's console (if you use the Web IDE look for Log Console or if running locally check the server's console). When you send a request you will see the following printed for you:
[arestme/HttpController] No suitable resource handler for resource [myservice.js], Verb[GET], Content-Type[], Accept["text/html", "application/xhtml+xml", "application/xml", "image/webp", "*/*"] found
Headers can vary, depending on what agent you used, but the important part now is the message in this log. Despite being functional this service is not very useful without handlers for requests to it. We need to instruct it how to behave upon different requests.
Suppose you want to send request GET /services/js/myservice.js
and receive response with status code 200 and body payload "OK".
Here is how you need to change myservice.js
to achieve this:
require('arestme/http').get() .addResourceHandler("","get", function(ctx, io){ io.response.println('OK'); }).service();
A quick look at the console after requesting the service now looks something like this:
[arestme/HttpController] Serving request for resource [myservice.js], Verb[GET], Content-Type[], Accept["text/html", "application/xhtml+xml", "application/xml", "image/webp", "*/*"] finished
We've just made our first functional HTTP service!
Now, if you wanted to add one more endpoint path to the myservice.js
resource that is not static and print the dynamic parts of its URL template when requested with GET verb, this would look like this:
require('arestme/http').get() .addResourceHandler("","get", function(ctx, io){ io.response.println('OK'); }) .addResourceHandler("{part1}/part2/{part3}","get", function(ctx, io){ io.response.println('part1: ' + ctx.pathParams.part1 + ', part3: ' + ctx.pathParams.part3); }).service();
If you request the service with: GET /services/js/myservice.js/abc/part2/123
you will now receive payload: part1: abc, part3: 123
Note, how the resource path variables got resolved to the concrete values from the request and have been made available to the handler function to print to the output stream.
Use the object extension capabilities provided by the JS runtime in Dirigible to create new classes and constructor functions out of HttpController.
Example:
// provide your own constructor function var MyController = function(){ // get a reference to the HttpController constructor var HttpController = require('arestme/http').HttpController; // invoke the HttpController constructor function to initialize this (i.e. like calling super() in other languages) HttpController.call(this); } // ensure prototypical inheritance MyController.prototype = Object.create(HttpController.prototype); // ensure the right constructor function (because of the previous line) MyController.prototype.constructor = MyController; // add new methods as appropriate MyController.prototype.method1 = function(){}; // get an instance of your new class var ctrl = new MyController(); // call its specific methods ctrl.method1(); // call any inherited methods from HttpController ctrl.service();
The API for HttpController can be considered in two aspects - setup and execution. Generally speaking, an instance of HttpController
is setup with the addResourceHandler(s)
methods and is invoked to service a request with the service
method.
The setup with addResourceHandler
or addResourceHandlers
provides a mapping between a request (template) and a handler function that will be invoked upon matching this template with the current request.
When the service
method handles an HTTP request, it tries to match it to a request specification among those configured for it. Should there be a match (including path, verb and optionally i/o media types), it will invoke the configured handler and provide as arguments the _context _ of the request (an object including any resolved path variables and query parameters) and an io object that is a shortcut to the current request
and response
objects.
-
HttpController
-
oConfig
Object(optional) This controller instance configuration for resource handlers. See
HttpController#addResourceHandlers
parameter specification for schema and description.
-
-
logger
log/loggers/Logger ObjectThe log/loggers/Logger instance for this HttpController instance.
-
addResourceHanlder
Add a new resource handler specification.
-
sPath
String(required) The HTTP request path that should match this handler. Must be a valid URL path string, relative to the service resource path (i.e. in
/services/js/myservice.js/a/b
this isa/b
). Can be a URL pattern with some or all of its path segments being placeholders that are resolved upon request. For example,1
,abc
,{id}
,{id}/abc/{a}
are all valid paths for a resource handler specification. Among other things, while servicing a request, the service matching function will try to resolve the placeholders in a URL pattern and then check for a matching path.Note: When designing URL templates, make sure that the parameters do not repeat in the pattern or the handler function will receive only the last resolved parameter of this kind.
-
sMethod
String(required) The HTTP verb that this handler services. Can be any valid HTTP verb string.
-
fHandler
Function(required) A function handling a matched request. It will be invoked with two arguments:
-
context
: an object with the following schema
{ pathParams: an object map for with the resolved path parameter names and values in case of URL template sPath, queryParams: an object map with the resolved query parameters. Parameters without value are resolved with value boolean true. In case of overlapping parameter names, the last in the query string wins. }
-
io
: an object with the following schema
{ request: the current HTTP request. response: the current HTTP response. }
-
-
arrConsumesMediaTypes
Array(optional) An array of valid MIME type strings for the media types inputs that this handler can consume from a request. Specifying this will constrain the match to this handler to account for a match between the request Content-Type header and what is specified as arrConsumesMediaTypes
-
arrProducesMediaTypes
Array(optional) An array of valid MIME type strings for the media types that this handler produces in response. Specifying this will constrain the match to this handler to account for a match between the request Accept header and what is specified as arrProducesMediaTypes
-
fBeforeHandler
Function(optional) A function that is invoked prior to the handler function for any pre-handling routines.
Returns: the HttpController instance on which it was invoked (for chaining)
Example:
require('arestme/http').get() .addResourceHandler("","get", function(ctx, io){ io.response.println('OK'); })
-
-
addResourceHandlers
Adds multiple resource handler specifications.
-
ohandlersMap
Object(required) Schema:
{ request_path: { verb: [{ "produces": [mime types], "consumes": [mime types], "beforeHandle": function, "handler": function }] } }
Returns: the HttpController instance on which it was invoked (for chaining)
Example
require('arestme/http').get().addResourceHandlers( { "": { "get": [{ "produces": ["application/json"], "handler": function(ctx, io){ var arr = [1,2,3,4,5]; io.response.println(JSON.stringify(arr, null, 2)); } }] }, "{id}": { "post": [{ "consumes": ["application/json"], "handler": function(ctx, io){ var input = io.request.readInputText(); var entity = JSON.parse(input); console.info('received: ' + input); io.response.setStatus(io.response.NO_CONTENT); }] } } });
-
-
getResourceHandlersMap
Returns: a reference to this HttpController's instance resource handler specifications.
-
sendError
Determines whether the requesting agent accepts HTML using the request header
Accept
and delegates to the container error pages configuration in that case (see the javax.servlet.http.HttpServletResponse#sendError specification for details). In all other cases sends back a JSON formatted message with the following schema:{ "err": { "code": httpCode "message": sErrMessage } }
-
httpCode
: (optional) -
sErrMessage
: (optional)
-
-
closeResponse
Closes and flushes the response.
-
service
Matches the current request to the request specifications and invokes a handler if found.
-
normalizeMediaTypeHeaderValue
The canonical representation of the values of media-type HTTP headers such as
Accept
orContent-Type
includes not only the the mime type formatted string but also additional properties (such as quality) that can tail each mime type string after a;
character. This function strips anything off the mime type strings leaving just the basic info that comes along - group and type, and returns an array of these cleansed strings.-
sMediaType
String(required) A media type header raw value.
Returns Array
An array of standard MIME type formatted strings ("group/value")
-