Skip to content

Toro Cloud Dev Center


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.

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.