Christoffer
Christoffer

Reputation: 26815

Send json part in play-ws multipart request

I'm implementing an external API where I need to send a file attachment bundled with a JSON meta part.

The following code is not accepted by the server since Play hardcodes the content type of DataPart to text/plain, and the server expects application/json

val meta = Json.obj(
  "name" -> s"Invoice ${invoiceNumber}.pdf",
  "referenceType" -> "INVOICE",
  "referenceId" -> 42
)

ws.url("{API-URL}")
  .addHttpHeaders("Authorization" -> s"Bearer ${accessToken}")
  .post(Source(DataPart("meta", meta.toString) :: FilePart("file", s"Invoice ${invoiceNumber}.pdf", Option("application/pdf"), FileIO.fromPath(file.toPath)) :: List()))
  .map(res => {
    logger.debug("Status: " + res.status)
    logger.debug("JSON: " + res.json)

    Right(invoiceNumber)
  })

The example curl (that I've tested and verified) command for the API endpoint is:

curl -H "Authorization: Bearer {accessToken}" \
  -F 'meta={"name": "Invoive 4.pdf", "referenceType": "INVOICE", "referenceId": 42 } \
  ;type=application/json' \
  -F "[email protected]" \
  '{API-URL}'

Is there a simple way to either force DataPart to use a different content-type or use a different Part to get more control over what I'm sending?

Upvotes: 0

Views: 118

Answers (1)

Christoffer
Christoffer

Reputation: 26815

I found a solution to the issue:

First I create a temporary file to hold the meta data

val meta = new File(s"/tmp/${UUID.randomUUID()}")
Files.write(meta.toPath, Json.obj(
  "name" -> s"Invoice ${invoiceNumber}.pdf",
  "referenceType" -> "INVOICE",
  "referenceId" -> 42
).toString.getBytes)

I then use two FilePart's in my request:

ws.url("{API-URL}")
  .addHttpHeaders("Authorization" -> s"Bearer ${accessToken}")
  .post(Source(FilePart("meta", "", Option("application/json"), FileIO.fromPath(meta.toPath)) :: FilePart("file", s"Invoice ${invoiceNumber}.pdf", Option("application/pdf"), FileIO.fromPath(file.toPath)) :: List()))
  .map(res => {
    logger.debug("Status: " + res.status)
    logger.debug("JSON: " + res.json)

    Right(invoiceNumber)
  })

Upvotes: 0

Related Questions