Skip to content

2. HttpController

shturec edited this page Feb 24, 2017 · 19 revisions

HttpController

Module: arestme/http

Usage

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.

Creating HTTP (REST) services with HttpController

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.

HttpController extensions

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();

HttpController API

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.

Constructor

  • HttpController

    • oConfig Object

      (optional) This controller instance configuration for resource handlers. See HttpController#addResourceHandlers parameter specification for schema and description.

Properties

  • logger log/loggers/Logger Object

    The log/loggers/Logger instance for this HttpController instance.

Methods

  • 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 is a/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 or Content-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")