HTTP request data mapping in Gloop
Martini maps request data before invoking a service. In the following topics, this page will describe how Gloop maps different kinds of request data to a service's input properties.
Request cookies
The first thing Martini does is check all cookies in the request and
see if there's an input property with either the same name as the cookie's
name or if there's a property whose name is the same as the cookie's name,
but prefixed with $cookie_
. In both cases, Martini will try to map matching cookies to their respective input
properties. This means that if you want your service to get a cookie's value from the request called JSESSIONID
,
you simply add an input property called either JSESSIONID
or $cookie_JSESSIONID
. If a matching input was found, the
value of the cookie will be passed in.
Next, if the input has a Gloop model property called $cookies
, it will perform the same mapping as
above. However, instead of mapping to the service's input properties, it will instead map them to the properties of the
$cookies
input model. This allows you to have a single, dedicated input model that will only contain cookie data.
Request attributes
The next thing Martini does is check all
attributes in the request and see if there's an
input property with either the same name as any of the attributes' names or if there's a property whose name is the
same as any of the attributes' names, but prefixed with $attribute_
. In both cases, Martini will try to map matching
attributes to their respective input properties. This means that if you want your service to
get the value of an attribute called myRequestAttribute
from the request, you simply add an input property called
either myRequestAttribute
or $attribute_myRequestAttribute
.
Next, if the input has a Gloop model property called $requestAttributes
, it will perform the same
mapping as above. However, instead of mapping to the service's input properties, it will instead map them to the
properties of the $requestAttributes
input model. This allows you to have a single, dedicated input model that will
only contain attribute data.
Request headers
The next thing Martini does is check all headers in the
request, and see if there's an input property with either the same name as any of the headers' names or if there's a
property whose name is the same as any of the headers' names, but prefixed with $header_
. In both cases, Martini will
try to map matching headers to their respective input properties. Note that this check is case-insensitive. This
means that if you want your service to get the value of a header called Accept
from the request, you simply
add an input property to your service called either Accept
, ACCEPT
, AcCePt
, accept
, or $header_Accept
,
$header_ACCEPT
, etc.
Next, if the input has a Gloop model property called $requestHeaders
, it will perform the same mapping
as above. However, instead of mapping to the service's input properties, it will instead map them to the properties of
the $requestHeaders
input model. This allows you to have a single, dedicated input model that will only contain header
data.
More accurate header mapping
You are also allowed to have date and numerical input properties mapped to request headers. If Gloop finds a
date input property, it will call
getDateHeader
. If it finds a
numerical input property,
getIntHeader
will be called to map the header instead. For
all other object types, getHeader
will
be called instead.
Session data
The next thing Martini does is check all
session attributes in the request and see if there's an
input property with either the same name as any of the session attributes' names or if there's a property whose name is
the same as any of the session attributes' names, but prefixed with $sessionAtt_
. In both cases, Martini will try to
map matching session attributes to their respective input properties. This means that if you want your service to get
the value of a session attribute called shoppingCart
from the request, you simply add an input property called either
shoppingCart
or $sessionAtt_shoppingCart
.
Next, if the input has a Gloop model property called $session
, it will perform the same mapping as
above. This allows you to have a single, dedicated input model that will only contain session data.
After iterating over the session attributes, Martini will look for an input property called $sessionId
which, if found, will have the session's ID mapped to it. Finally,
it will check for a property called $sessionCreationTime
, which will have the session's
creation time mapped to it, if it's found.
HTTP session creation
Martini will not create a session when a service is invoked. If you want to associate a session with
the request, you will need to add a $request
property, and call
getSession()
manually.
URI variables
Martini will next check for any URI variable tokens. It does this by reusing the
URI patterns functionality from Spring Web MVC.
Similar to the example in the Spring documentation, if a service is being executed from a URI such as
/owners/123/pets/456
, and the service had a REST URL path or
Gloop REST API path of /owners/{ownerId}/pets/{petId}
, then Martini will
populate the input property called ownerId
with 123
and the property petId
with 456
.
Request-specific properties
Next, Martini will try and map some simple request-specific properties. The table below shows the input
properties that it checks for and which method of HttpServletRequest
will be used to populate it:
Input Property Name | Request Method |
---|---|
$path |
HttpServletRequest#getRequestURI() |
$method |
HttpServletRequest#getMethod() |
$queryString |
HttpServletRequest#getQueryString() |
$contentType |
HttpServletRequest#getContentType() |
Request parameters
Martini will then check for any request parameters, regardless of how they are passed in (e.g. part of the query string, POST-ed). The name of the parameter will be used to try and find a matching input property.
For input properties that are models, Martini will use its customised
Spring ContentNegotiationManager
to determine the format (content-type) of the parameters. The ContentNegotiationManager
in Martini doesn't use file
extensions to detect the content type. Instead, it uses a parameter called requestDataFormat
to detect whether to
use formats such as XML or JSON. If the requestDataFormat
parameter doesn't exist in the request, then
the Content-Type
header of the request is used. Finally, if no Content-Type
header exists (or is too broad), it
will fall back to the format specified in the api.rest.default-content-type
instance property.
URL-encoded requests
If the request Content-Type
is application/x-www-form-urlencoded
and the service has a Gloop model named Body
Parameter
, Martini will map the request parameters to the properties of the model. This does not work for
nested properties (in other words, the model can't have any model properties).
Multipart requests
If the request is detected as a multipart request, then the
parameters are mapped as they normally would be, and any files in
the request will be mapped to their respective input properties. The input properties for multipart files can either be
a Gloop model that references io.toro.martini.http.MultipartFile
, or any object type
supported by the built-in ContentToStreamConverter
.
Request bodies
If the request isn't a multipart request and isn't application/x-www-form-urlencoded
, then the body of the request
(if there is one) will be mapped to the service. If the service was invoked from a
REST URL path or a Gloop REST API path with a set
Body Parameter
, then Martini will try and populate the Body Parameter
input for you. The list below shows
the supported types for the Body Parameter
:
Gloop model request bodies
If the Body Parameter
input is a Gloop model, the same logic that's used when detecting the content type of
request parameters will be used when parsing the body. Also, if
the Body
property is a Gloop model, Martini will map the root element name of the request body (if it's
XML) to an input property of the service called $rootElementName
, if it exists. This is useful if the body could
have different root element names. If Gloop isn't able to convert JSON or XML data to the Gloop model because the
body data is invalid, a 400
will be sent back, and the service will not execute.
Tracker-related data
If Tracker is enabled for the HTTP request, Martini will map the internalId
of the generated Tracker document to an input property called $trackerId
or internalId
, if it exists. This will be set as
the ID of the Tracker document of the service invocation.
Request and response objects
Martini will then check for input properties called $request
, and $response
. These are the properties
that Martini will map the original HttpServletRequest
and
HttpServletResponse
to. These properties are handy if you want to
perform low level manipulation of the request and response (such as creating sessions, adding cookies, setting
response codes, and others).
Order of request mapping
You may have noticed that if a request parameter and cookie had the same name, the request parameter mapping will
overwrite the cookie value because parameters are processed after cookies. This is deliberate and it's why we
included prefixes such as $cookie_
, $attribute
and $sessionAtt
. In fact, request parameters that begin with
$cookie_
, $attribute_
, or $sessionAtt_
are ignored.