Skip to content

Toro Cloud Dev Center


HTTP response data mapping in Gloop

Once request data has been mapped into your service and the service has been invoked, Martini will try to map the output of your service to the HTTP response.

Exceptions in services

If your service throws an uncaught exception, Martini will wrap it with an APIException. These exceptions are annotated to allow Martini to respond with error messages in a common format such as:

  • JSON

    1
    2
    3
    4
    5
    {
      "result" : "ERROR",
      "apiErrorCode" : -1,
      "message" : "Unhandled Error: null"
    }
    
  • XML

    1
    2
    3
    4
    5
    <APIException>
      <result>ERROR</result>
      <apiErrorCode>-1</apiErrorCode>
      <message>Unhandled Error: null</message>
    </APIException>
    

There are Gloop model-compatible versions of these Java classes at io.toro.martini.api, in the core/models directory (seen in the Navigator view).

Gloop API-related models in the Navigator

Rendering responses with JSP

If you wish to render the output of your service with a JSP page, simply add an output property called $gloopView. If this property exists, a ModelAndView object will be returned to Spring Web MVC. This object contains the name of the view and the output from the service as the model. The service output will be wrapped in a custom class that implements the Map interface, allowing the named JSP to use JSTL to access the properties from the output of the service. Since the response handling from this point on is delegated back to Spring, the use of the redirect: prefix is also supported.

JSPs for Martini must be in the web directory of the corresponding Martini package where the top-level service also resides in. $gloopView's value doesn't need the web directory included in it, nor does it need the file extension. Therefore, if you wanted your service to use the JSP web/myOutput.jsp, then $gloopView's value should be myOutput. Similarly, if your service was to use the JSP web/my/views/here/view1.jsp then the corresponding value for $gloopView should be my/views/here/view1.

Rendering binary output

If the output of your service is binary data (such as having a service that renders an image or PDF, or prompts the user to download a file), then the output of the service should only contain a single model property that references the io.toro.martini.gloop.http.MultipartFile model. The name of the model isn't important. If the contentType of the model is compatible with application/octet-stream, then Martini will set the Content-Disposition response headers for you, which normally trigger web browsers to prompt the user for downloading a file (and also includes the filename in the header). Otherwise, the contentType from the model will be set as the response content type. If the size property is set, it too will be passed to the response. Once all the headers are taken care of, the inputStream of the service output io.toro.martini.gloop.http.MultipartFile model is copied to the response output stream.

Other response types

If the output of the service doesn't tell Martini to use binary data or a JSP page, then the output of the service itself is sent to the response. Martini uses the detected response content type to determine whether to write the response out as XML, JSON, or YAML. For output properties that are models, Martini will use another customised ContentNegotiationManager for responses to determine the format (content-type) of the output. The ContentNegotiationManager in Martini doesn't use file extensions to detect the content type. Instead, it uses a parameter called dataFormat to detect whether to use formats such as XML or JSON. If the dataFormat parameter doesn't exist in the request, then the Accept header of the request is used. Finally, if no Accept header exists (or is too broad), it will fall back to the format specified in the api.rest.default-content-type instance property.

Using different Content-Type and Accept headers for your requests and responses

Since Martini uses both the Content-Type and Accept headers to work out the request and response data types, it's possible to construct a request with a Content-Type header of application/json, an Accept header of application/xml to mix-and-match your request and response formats!

Serialization of output data

Martini behaves slightly differently if there's only one output parameter in your service. If your Gloop service has one output parameter, then only that will get serialised.

Example response per type

In this section, we'll show you how Martini behaves with certain output types.

Single string parameter

Below is the output of a service called TestOutput that returns a single String property called name, whose value is John Smith.

Single output parameter

  • JSON

    1
    "John Smith"
    
  • XML

    1
    2
    <?xml version="1.0"?>
    <name>John Smith</name>
    
  • YAML

    1
    name: John Smith
    

More than one parameter

Below is the output of a service called TestOutput that returns two properties called name and age, with the values of John Smith and 25, respectively.

Double output parameter

  • JSON

    1
    2
    3
    4
    {
      "name": "John Smith",
      "age": 25
    }
    
  • XML

    1
    2
    3
    4
    5
    <?xml version="1.0"?>
    <TestOutputOutput>
        <name>John Smith</name>
        <age>25</age>
    </TestOutputOutput>
    
  • YAML

    1
    2
    3
    TestOutputOutput:
      name: John Smith
      age: 25
    

Notice how the output has been wrapped in all three formats. For XML and YAML, the parent node is called the name of the service, suffixed with Output.

Single Gloop model parameter

Below is the output for a service called TestOutput that returns one model property called person, which has two properties called name and age, with a value of John Smith and 25.

Single model output parameter

  • JSON

    1
    2
    3
    4
    {
        "name": "John Smith",
        "age": 25
    }
    
  • XML

    1
    2
    3
    4
    5
    <?xml version="1.0"?>
    <person>
        <name>John Smith</name>
        <age>25</age>
    </person>
    
  • YAML

    1
    2
    3
    person:
      name: John Smith
      age: 25
    

Notice how the output has been wrapped in all three formats again. Also, the XML and YAML outputs are now wrapped with a nicer name (person instead of TestOutputOutput).

Complex output

Below is the output for a service called TestOutput that returns one model property called person, which has two properties called name and age, with a value of John Smith and 25. It also has two other output parameters called reponseMessage with a value of OK and responseTime with a value of 50.

Complex output parameter

  • JSON

    1
    2
    3
    4
    5
    6
    7
    8
    {
      "person": {
        "name": "John Smith",
        "age": 25
      },
      "responseMessage": "OK",
      "responseTime": 50
    }
    
  • XML

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <?xml version="1.0"?>
    <TestOutputOutput>
        <person>
            <name>John Smith</name>
            <age>25</age>
        </person>
        <responseMessage>OK</responseMessage>
        <responseTime>50</responseTime>
    </TestOutputOutput>
    
  • YAML

    1
    2
    3
    4
    5
    6
    TestOutputOutput:
      person:
        name: John Smith
        age: 25
      responseMessage: OK
      responseTime: 50
    

Notice how the output has been wrapped in all three formats again. But since the service has more than one output parameter, the XML and YAML responses have gone back to using TestOutputOutput as the name or the root node.

Writing data directly to the response output stream

It's also possible for a service to write data directly to the response output stream. To do this, the service should have a $response input property of type object1, and a $requestHandled boolean output property with a value of true. The $response object has a writer field (of type PrintWriter) which can be used by the service to write the data. Meanwhile, $requestHandled = true tells Martini that it should not handle the request and response anymore because it's already been fully-handled by the service. Here's a usage example:

Writing data directly to the response output stream


  1. Martini will automatically assume this object references the HttpServletResponse type.