Qore RestHandler Module Reference
1.1
|
RestHandler.qm Copyright (C) 2013 - 2014 Qore Technologies, sro
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
The RestHandler module provides functionality for implementing REST services with the Qore HTTP server.
To use this module, use "%requires RestHandler"
and "%requires HttpServer"
in your code.
All the public symbols in the module are defined in the RestHandler namespace.
The main classes are:
see example file "restserver.q"
in the examples directory for an example of using this module to implement REST services.
The RestHandler class uses any of the following modules if the modules are available when the RestHandler module is initialized:
For standard REST web service development, the json module will be required to support JSON serialization.
The RestHandler class will automatically deserialize request bodies if the incoming MIME type is supported and additionally will serialize outgoing messages automatically based on the client's declared capabilities (normally responses are serialized with the same serialization as the incoming message).
The class that models a REST entity or object in this module is AbstractRestClass.
This class should be subclassed for each object type, and methods implemented for each REST method that the object will support.
Incoming requests matched by your RestHandler subclass (when called by the HttpServer when requests are appropriately matched) will be dispatched to methods in your AbstractRestClass specialization (ie your user-defined subclass of this class) according to the following naming convention:
httpmethod
[RequestRestAction]For example:
"GET /obj HTTP/1.1"
: matches method AbstractRestClass::get()
"POST /obj HTTP/1.1"
: matches method AbstractRestClass::post()
"DELETE /obj/subobj"
: match method AbstractRestClass::del()
"GET /obj?action=status HTTP/1.1"
: matches method AbstractRestClass::getStatus()
"PUT /obj?action=status HTTP/1.1"
: matches method AbstractRestClass::putStatus()
In other words, if a REST action is given in the request (either as a URI parameter or in the message body), the first letter of the action name is capitalized and appended to a lower case version of the HTTP method name (except "DELETE"
is mapped to "del"
because "delete"
is a keyword); if such a method exists in your AbstractRestClass specialization, then it is called. If not, then, if the REST action exists under a different HTTP method (ie a request comes with "HTTP GET /something?action=setData"
, and "putSetData"
exists, but "getSetData"
was used for the search), then a 405 "Method Not Allowed"
response is returned. If no variation of the requested REST method exists, then a 501 "Not Implemented"
response is returned.
If a REST request is made with no action name, then a method in your class is attempted to be called with just the HTTP method name in lower case (except "DELETE"
is mapped to "del"
because "delete"
is a keyword).
HTTP Method Name to Qore Method Name
HTTP Method | Qore Method |
GET | AbstractRestClass::get() |
PUT | AbstractRestClass::put() |
POST | AbstractRestClass::post() |
DELETE | AbstractRestClass::del() |
OPTIONS | AbstractRestClass::options() |
In all cases, the signature for these methods looks like:
The arguments passed to the REST action methods are as follows:
"action"
argumnt was sent either in the message body or as a URI argument"action"
argument was sent)ah:
these are the parsed URI query arguments to the REST call; see Argument and Message Body Handling for more informationThe return value for these methods is the same as the return value for HttpServer::AbstractHttpRequestHandler::handleRequest().
consider the following example class:
Assuming this object corresponds to URL path /files/info.txt, the following requests are supported:
"GET /files/info.txt HTTP/1.1"
: calls the get() method above (no action)"PUT /files/info.txt?action=chown;user=username HTTP/1.1"
: calls the putChown() method above (such arguments could also be passed in the message body; see Argument and Message Body Handling for more information)"PUT /files/info.txt?action=chmod;mode=420 HTTP/1.1"
: calls the putChmod() method above (note that 420 = 0644)"PUT /files/info.txt?action=rename;newPath=/tmp/old.txt HTTP/1.1"
: calls the putRename() method aboveTo implement a hisearchy of REST objects in the URL, each AbstractRestClass subclass reimplements the subClass() method that returns a child AbstractRestClass object representing the child object.
If no such sub object exists, then the method should return NOTHING, which will cause a "REST-CLASS-ERROR"
exception to be thrown by default (to change this behavior, reimplement unknownSubClassError() in your specialization of RestHandler. See Exception Handling in REST Calls for more information
The following is an example of a class implementing a subClass() method:
There are two ways to pass arguments to REST action methods:
REST action methods have the following signature:
In the usual case when only one of the above methods is used, then the argument information is copied to both places, making it easier for the Qore REST implementation to handle arguments in a consistent way regardless of how they were passed. This means arguments, including any action
argument, can be passed in either the URI path as URI query arguments, or in the message body as a hash.
Therefore, the following cases are identical:
Request With URI Argument
GET /files/info.txt?action=info;option=verbose HTTP/1.1 Accept: application/x-yaml User-Agent: Qore-RestClient/1.0 Accept-Encoding: deflate,gzip,bzip2 Connection: Keep-Alive Host: localhost:8001
Request With Arguments in the Message Body
GET /files/info.txt HTTP/1.1 Accept: application/x-yaml User-Agent: Qore-RestClient/1.0 Accept-Encoding: deflate,gzip,bzip2 Connection: Keep-Alive Host: localhost:8001 Content-Type: application/json;charset=utf-8 Content-Length: 36 { "action" : "info", "verbose" : 1 }
Qore exceptions are serialized in a consistent way by the RestHandler class so that they can be recognized and handled appropriately by clients.
Qore exceptions are returned with a 409 "Conflict"
HTTP return code with the message body as an exception hash.
OPTIONS
method