
Working with Multipart Form Data in Angular
Assume you have an API that accepts 'multipart/form-data' and you have created an Angular service to POST some data to this API...
1@Injectable({ providedIn: 'root' })
2export class MemberService {
3	protected readonly URL = 'url to api endpoint';
4	constructor(protected http: HttpClient) { }
5	
6	post(name: string, age: number, alive: boolean) {
7	  const data = new FormData();
8	  data.append('name', name);
9	  data.append('age', age);
10	  data.append('alive', alive);
11
12	  const headers = new HttpHeaders()
13		  .set('content-type', 'multipart/form-data');
14		  
15	  return this.http.post(URL, data, { headers });
16	}
17}What is wrong with the approach above?
hint #1 Have a look at the request headers
hint #2 Multipart forms need a boundary
Issue
By explicitly setting the content-type, you do not get the important boundary component of the header.  
Solution
Let HttpClient do the work for you. First off, do not set the content-type. Instead, HttpClient will see that the payload (data) is FormData and will set the header appropriately (with the boundary component).
If you want to specify the content-type header yourself, have a look at the specification to learn more about how boundaries are required and how to set them.
Asides
Here are a couple of gotchas that have experienced over the years.
Headers vs HttpHeaders
I jump between Angular and plain JavaScript in my projects, and this gotcha has resulted in way too much wasted time on my part.
When I set headers for my fetch statement in JavaScript, it looks like this...
1const header = new Headers();
2header.append('x-api-code', '123');
3header.append('x-api-version', '3');
4header.append('x-api-ns', 'alpha');
5//check
6header.forEach((value, key) => {
7  console.log(key, value);
8});This results in:
"x-api-code" "123"
"x-api-ns" "alpha"
"x-api-version" "3"
But I get nothing when I move to Angular and try similar code.  There is nothing in the header.
1const header = new HttpHeaders();
2header.append('x-api-code', '123');
3header.append('x-api-version', '3');
4header.append('x-api-ns', 'alpha');
5//check
6header.keys().forEach((key) => {
7  const value = header.get(key);
8  console.log(key, value);
9});I had to adjust the //check code because HttpHeaders does not have a .forEach() method. But, the fact remains - there is no output. Why?
Immutability! HttpHeaders are immutable. So you adjust your code to the following, and the headers will be back.
1const header = new HttpHeaders()
2  .append('x-api-code', '123')
3  .append('x-api-version', '3')
4  .append('x-api-ns', 'alpha');
5//check
6header.keys().forEach((key) => {
7  const value = header.get(key);
8  console.log(key, value);
9});HttpHeaders .set vs .append
When you are working with headers, there are two methods of adding a header: .set() and .append().
Both will add a header key/value pair. The difference between the two is visible when there is already a header with the same key in the group.
- .set()will override the existing value and replace it with the new value.
- .append() will add the new value to the existing value.
Unless I know I need multiple values on my header, I stick with .set().  This preference is personal, and it stems from intent. By using .set() I feel it is clear that my intent is to add a new single-value header, where .append() suggests that I am adding a new multi-value header.

