Dropwizard Multipart Form QuickstartPublished on
I hear you are interested in forms with multiple parts
The other day I had the requirement where I had to code an endpoint such that a client could submit two bodies, one containing JSON, and the other one containing XML. One could get clever and embed the XML in JSON, vice versa, or even make two requests, but the HTTP spec already has this issue solved: multipart messages. If you took a peek at the Wikipedia page or the stackoverflow question, “What is [a] HTTP multipart request”, you might be confused because there is a lot of talk about submitting forms, files, and email. These are the typical use cases, but not the only use cases. I’m here to talk about (document) the other use case: multiple bodies.
I’ll be using Dropwizard for the examples but multipart messages should work across frameworks and languages.
Step 1: Add the bundle
First we add the dependency to our
And then register the bundle:
Step 2: Create resource endpoint
Our resource endpoint will consume JSON content and XML content. Both will be representing the same not-null and valid
Person class. We’ll return the difference between the ages of the JSON person and the XML person.
Couple of notes:
- Notice the usage of pure domain objects. Removing all the annotations would reveal a very simplistic function that has zero ties to REST or HTTP. This allows for a much easier time testing endpoints because, in this case, the business logic can be thoroughly tested like any other domain object
- There is no notion that the object for the
json-bodyparam is even JSON. One could supply JSON for both parts or an entirely different content type that is known.
FormDataParammust come last in the annotation list as Jersey interprets the last annotation specially. Otherwise, you’re going to get those nasty “No injection source found for a parameter”
- While both
Personobjects are validated, their validation errors currently lacks the nice context of other
*Paramannotations. See issue 1782 for more info.
Step 3: Create Test
Assuming you added
dropwizard-testing to your pom:
Here we have to explicitly register the Jersey
MultiPartFeature, which is what the bundle did in step 1. It’s a tad inconvenient.
If you have a healthy dose of skepticism whether XML or JSON is really being used you can add another test where you use JSON and XML directly.
Step 4: Curl Example
Oftentimes across companies and teams, Dropwizard may not be persasive, so handing them the test code snippet as a way to call the API may be inappropriate. That’s why it’s good to include a curl example as an unbiased mechanism for calling the API. It is normally easy enough to work backwards from a curl example to the language or framework of choice. For the API shown earlier a request from curl would look like:
Of course, it came out a little more complicated than I wanted due to my fruitless search in how to escape
< in the
-F flag. I initially tried embedding the XML data like the JSON data, but curl parses the
-F flag and
< is a special character signalling to embed the file’s contents.
type=application/xml is critical as curl interprets the snippets and adds the appropriate
Content-Type to each part. This content type is interpreted by Dropwizard, so that it can be deserialized correctly.
This curl statement is translated into the following request:
As an aside, I lament the documentation for the
lets curl emulate a filled-in form in which a user has pressed the submit button
The documentation makes it appear as if the only use case is someone filling in a form. The sheer amount of documentation missing the use case of having multiple bodies can be misleading. Many times while writing this post I was left scratching my head wondering if what I was doing was against some kind of unspoken law. If it is, feels good.
Step 5: The missing steps
There are some steps that were omitted earlier as they distracted from the main part of using multipart forms:
Since Dropwizard is a JSON first framework, one needs to add in basic XML support:
The Jackson package (for Dropwizard 1.0.2) automatically registers an XML provider on the client and server sides, so you don’t have to do anything.
Person class is described below.
I can’t help it, but I really enjoy AutoValue and want its usage to spread