Photo credit: Pexels

Rest easy with Json and Binary

Nidhi Sadanand
Walmart Global Tech Blog
3 min readMar 3, 2017

--

In a SOA based micro-services model, most POST & PUT service contracts use JSON or Xml Payloads over HTTP(S). However there might be a need to send binary data along with the JSON if you are dealing with images or PII or HIPAA data.

This blog explains the approach and setup required to achieve this. We assume you are familiar with a Java — JAX-RS RESTful Service setup.

There are two options to achieve this:

  1. Using Base64 Encoding for the binary data so that it is transformed into text — and then can be sent with an application/json content type as another property of the JSON payload. This is an acceptable solution but the flip side is that it is not at all efficient especially if you are dealing with low bandwidth and intermittent network. This is because the encoded image data will increase the payload size by around 30% more than the original data.
  2. Using Multipart Form data as the Content Type of the request with individual parts in the multipart with Content Type of application/json and application/octet stream. Per RFC, an application multipart can define its own Content Type. The Multipart form data is essentially a list of attachments where each attachment is typically a text or file.

For the use-case we had, we used option 2 for optimized performance on the size of the image we were sending. We are outlining a few of the important steps in writing and testing such a RESTful Service. (The solution is based on a Spring , JAX-RS framework for development and cURL to test).

JAX-RS supports a Multipart Form Data Provider out of the box. Providers are the entities that serialize & deserialize the input/output stream so that your Java Service interface can directly work with POJOS. Jax-Rs has providers for pretty much all the standard content types — JSON, text, binary etc. The providers are registered against the various content types so that when the Content-Type is read, the appropriate provider is picked. For this to work with Multipart Form data, you need specify the Content-Type in each part of the attachment.

Writing the REST Interface for your Java Service

@Path("/employees/{id}/employeeDetails")
@POST
Response submitEmployeeDetails(
@PathParam(value="id") UUID empId,
@Multipart(value="depId", type="application/json"; required=false) UUID deptId,
@Multipart(value="details", type="application/json") EmployeeDetails employeeDetails,
@Multipart(value="photoId",type="application/octet-stream", required=false) InputStream imageInputStream) throws ServiceException;

The MultipartProvider has to be registered as a provider in the CXF Bus as

<bean id="multiPart" class="org.apache.cxf.jaxrs.provider.MultipartProvider"/><jaxrs:providers>
<ref bean="multipartProvider"/>
</jaxrs:providers>

This is a rather un-obvious but important step. Even though the providers are picked up during runtime on a service invocation, the context initialization does not happen and de-serialization of the individual attachments will cause an exception. You may end up debugging for hours to figure out what went wrong.

Testing the Service

Testing this can be a challenge if you are using PostMan or Advanced REST Client as these clients only allow either “text” or “file” as attachments. cURL solves this problem by allowing us to set the Content type explicitly in each part of the form data using the “type” property.

curl -X POST -H "Accept: application/json" -F "depId=\"596ac151-53ea-460c-bd5f-2e5665307971\";type=application/json" -F "details={\"firstName\":\"John\",\"lastName\":\"Doe\"};type=application/json" -F "photoId=@/testdir/john_doe.png;type=image" "http://yourhost.domain.com:8080/app/employees/ddbe8f98-75d4-4764-8f48-39e4a68ca187/employeeDetails"

And thats it folks!

You are ready to go with a service that accepts both JSON & Binary in a single payload.

--

--