How can I specify the content-type of a multi-part/form field?

I’m trying to post a multipart/form request like so:

const baseUrl = 'https://api-int.nmlv.nml.com/v1/aca-cip/documents';
  const params = {
    headers: {
      'Content-Type': ''multipart/form-data",
      'x-nm-nm_login_id': 'acakvlrt',
      "x-nm-request-id": "k6loadtest",
      'apikey': `${__ENV.ACA_APIKEY}`
    }
  };
  // metadata for multi-part form to create a document
  const metaData =  {
    "authLevelCde": authLevelCode,
    "aclName": authLevelCode,
    "attributes": {
      "docDescrCde": 5000
    },
    "singleValueAttributes": {
      "docDescrCde": 5000
    },
    "multiValueAttributes": {
    }
  }

  const formData = new FormData();
  formData.append('metadata', metaData);
  const randomUUID = uuidv4();
  formData.append('fileSize', randomUUID.length);
  formData.append('file', http.file(randomUUID, 'myuuid.txt', 'text/plain'));

  const res = http.post(baseUrl, formData.body(), params );
  console.log(res);

but the post returns a stats 500, and the res.error, error_code, and request fields are:

  "error": "",
  "error_code": 1500,
  "request": {
    "method": "POST",
    "url": "https://api-int.nmlv.nml.com/v1/aca-cip/documents",
    "headers": {
      "X-Nm-Request-Id": [
        "k6loadtest"
      ],
      "Apikey": [
        "xxxxxxxxxxxxxxxx"
      ],
      "User-Agent": [
        "k6/0.50.0 (https://k6.io/)"
      ],
      "Content-Type": [
        "multipart/form-data"
      ],
      "X-Nm-Nm_login_id": [
        "acakvlrt"
      ]
    },
    "body": "--------RWWorkerFormDataBoundary0.46vp38bxrw9\r\nContent-Disposition: form-data; name=\"metadata\"\r\nContent-Type: application/octet-stream\r\n\r\n\r\n--------RWWorkerFormDataBoundary0.46vp38bxrw9\r\nContent-Disposition: form-data; name=\"fileSize\"\r\nContent-Type: application/octet-stream\r\n\r\n\r\n--------RWWorkerFormDataBoundary0.46vp38bxrw9\r\nContent-Disposition: form-data; name=\"file\"; filename=\"myuuid.txt\"\r\nContent-Type: text/plain\r\n\r\nd1248d6d-763d-4a63-83ee-c2fb3b7cb6e2\r\n--------RWWorkerFormDataBoundary0.46vp38bxrw9--\r\n",
    "cookies": {}
  }

I see two possible clues in the res.request.body field:

  1. the ‘metadata’ form field is cited as having content-type ‘application/octet-stream’, whereas my µservice expects it to be ‘application/json’;
  2. the ‘fileSize’ form field is also cited as having content-type app/octet-stream, but i mean for it to be an integer.

Any idea what I’m doing wrong? Thanks!

Hi @jondetert, welcome to the community forum! :tada:

Given your questions and code you want to set specific content type.

The easiest way will be to use either use http.file.

The following example should illustrate the usage:
Also note that:

  1. the second argument to http.file is null so it doesn’t have a filename - if you want that just set it accordingly
  2. I do encode both arguments to string, one by JSON.stringify, one by concating to a an empty string. As the http.file doesn’t know what it is suppsoed to be do with just a general purpose object or a number.
  3. You MUST set the Content-Type header with the boundary as in the provided example as otherwise the server wouldn’t know how to parse it. This might actually be the major problem you are having not any of the fields not being encoded in some of the above ways.
import http from "k6/http";
import { uuidv4 } from 'https://jslib.k6.io/k6-utils/1.4.0/index.js';
import { FormData } from 'https://jslib.k6.io/formdata/0.0.2/index.js';
export default () => {
	const baseUrl = 'https://httpbin.test.k6.io/get';
	const params = {
		headers: {
			'Content-Type': 'multipart/form-data',
			'x-nm-nm_login_id': 'acakvlrt',
			"x-nm-request-id": "k6loadtest",
		}
	};
	// metadata for multi-part form to create a document
	const metaData = {
		"attributes": {
			"docDescrCde": 5000
		},
		"singleValueAttributes": {
			"docDescrCde": 5000
		},
		"multiValueAttributes": {
		}
	}

	const formData = new FormData();
	formData.append('metadata', http.file(JSON.stringify(metaData), null, "application/json"));
	const randomUUID = uuidv4();
	formData.append('fileSize', http.file("" + randomUUID.length, null, 'integer'));
	formData.append('file', http.file(randomUUID, 'myuuid.txt', 'text/plain'));

	params.headers["Content-Type"] = 'multipart/form-data; boundary=' + formData.boundary
	const res = http.post(baseUrl, formData.body(), params);

	console.log(JSON.stringify(res, null, "  "));
}

Hope this helps you!

Thanks @mstoykov! You guessed my problem in your note #3. I was not adding the boundary to the Content-Type header.

Doing so like you showed resolved my problem.

1 Like