1
votes

I write an angular based client app for Django API project. One of the endpoints accepts application/x-www-form-urlencoded formatted requests, as it contains both file and string data and I'm pretty sure it works just fine on server-side - I've prepared an application/x-www-form-urlencoded request using POSTMAN:

HEADERS:
   Content-Type: application/x-www-form-urlencoded
BODY (form-data):
   experiment: http://127.0.0.1:8000/api/v1/experiments/6/
   measurement: http://127.0.0.1:8000/api/v1/measurements/4/
   variable: 
   x_axis: X_AXIS
   y_axis: Y_AXIS
   file_object: // here I've changed the field type and chose the .txt file

Of course the server responded correctly, and file has been added. Here's how the exact request's body looks like:

experiment=http://127.0.0.1:8000/api/v1/experiments/6/measurement=http://127.0.0.1:8000/api/v1/measurements/4/variable=x_axis=os Xy_axis=os Yfile_obj=[object Object]

But now, things are getting more complicated. I try to prepare the same request in Angular using reactive form and HttpClient. Let's say the reactive form itself works as should, but sending the request with 'Content-Type' set to:

  • 'application/x-www-form-urlencoded' returns '500 Internal Server Error', and
  • 'multipart/data-form' return '415 Unsupported Media Type'

Here's how I send the request:

post(formGroup: FormGroup): Observable<DataFile> {
    const httpOption = {
      headers: new HttpHeaders({
        'Content-Type': 'application/x-www-form-urlencoded'
      })
    };

    return this.httpClient.post<DataFile>(this.apiEndpoints.datafilesCreateEndpoint(), formGroup.value, httpOption);
  }

and here's how the exact request looks like:

{"experiment":"http://127.0.0.1:8000/api/v1/experiments/6/","measurement":"http://127.0.0.1:8000/api/v1/measurements/4/","variable":" ","x_axis":"X AXIS","y_axis":"Y AXIS","file_obj":"C:\\fakepath\\navon.txt"}

Dunno why the request's Form Data is a JSON when I have set the Content-Type to a different one. Could it be a reason of this problem?

@UPDATE Solution

I've removed the httpOptions from post function, to let the Angular pass the Content-Type automatically. Then, instead of passing the FormGroup.value to httpClient's post, I've created the FormData and passed it instead.

Here's how my POST function looks like:

post(experiment: SharedModel, measurement: SharedModel, andOtherDataINeed: any): Observable<DataFile> {

    const fd = new FormData();
    fd.append('experiment', experiment as any);
    ...
    fd.append('file_obj', file);

    return this.httpClient.post<DataFile>(this.apiEndpoints.datafilesCreateEndpoint(), fd);
2
@FrancescoFortin It's a step forward, indeed and thank you for this answer, but the form's file input tag returns the "fake" file path instead of File object as I expected - need to find out how to handle this.Lukasz Nowak
Transform that file to base64 encoded and post that base64 instead.Ryukote
As far as I can tell, FormData gets sent as multipart/form-data. If you want application/x-www-form-urlencoded, use new HttpParams({ fromObject: formGroup.value }).Ron Inbar

2 Answers

0
votes

Try to research Axios library https://github.com/axios/axios

If you scroll down, you will notice example that sou need. You can use Axios in Angular app without problems.

-1
votes

Change your original code to

    return this.httpClient.post<DataFile>(this.apiEndpoints.datafilesCreateEndpoint(), new HttpParams({ fromObject: formGroup.value }));

FormData gets sent as multipart/form-data, not as application/x-www-form-urlencoded.