95

I'm trying to make a POST request but i can't get it working:

testRequest() {
      var body = 'username=myusername?password=mypassword';
      var headers = new Headers();
      headers.append('Content-Type', 'application/x-www-form-urlencoded');

      this.http
        .post('/api',
          body, {
            headers: headers
          })
          .subscribe(data => {
                alert('ok');
          }, error => {
              console.log(JSON.stringify(error.json()));
          });
}

I basically want to replicate this http request (not ajax) like it was originated by a html form:

URL: /api

Params: username and password

SnareChops
  • 13,175
  • 9
  • 69
  • 91
Christopher
  • 3,379
  • 7
  • 25
  • 36
  • have a look at this http://stackoverflow.com/a/34758630/5043867 and http://stackoverflow.com/a/34823818/5043867 this will explain all about POST request in deep ! – Pardeep Jain Feb 05 '16 at 05:37
  • @PardeepJain i'm not trying to consume an API. Just to simulate a POST originated by a html form. – Christopher Feb 07 '16 at 22:08
  • also check here, post a file with `user_name` and `password`, https://stackoverflow.com/a/45879409/2803344 – Belter Aug 25 '17 at 10:39

9 Answers9

114

Update for Angualar 4.3+

Now we can use HttpClient instead of Http

Guide is here

Sample code

const myheader = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded')
let body = new HttpParams();
body = body.set('username', USERNAME);
body = body.set('password', PASSWORD);
http
  .post('/api', body, {
    headers: myheader),
  })
  .subscribe();

Deprecated

Or you can do like this:

let urlSearchParams = new URLSearchParams();
urlSearchParams.append('username', username);
urlSearchParams.append('password', password);
let body = urlSearchParams.toString()

Update Oct/2017

From angular4+, we don't need headers, or .toString() stuffs. Instead, you can do like below example

import { URLSearchParams } from '@angular/http';

POST/PUT method

let urlSearchParams = new URLSearchParams();
urlSearchParams.append('username', username);
urlSearchParams.append('password', password);
this.http.post('/api', urlSearchParams).subscribe(
      data => {
        alert('ok');
      },
      error => {
        console.log(JSON.stringify(error.json()));
      }
    )

GET/DELETE method

    let urlSearchParams = new URLSearchParams();
    urlSearchParams.append('username', username);
    urlSearchParams.append('password', password);
    this.http.get('/api', { search: urlSearchParams }).subscribe(
      data => {
        alert('ok');
      },
      error => {
        console.log(JSON.stringify(error.json()));
      }
    )

For JSON application/json Content-Type

this.http.post('/api',
      JSON.stringify({
        username: username,
        password: password,
      })).subscribe(
      data => {
        alert('ok');
      },
      error => {
        console.log(JSON.stringify(error.json()));
      }
      )
Frank Nguyen
  • 6,493
  • 3
  • 38
  • 37
  • 14
    Don't forget to import the URLSearchParams Class `import { URLSearchParams } from "angular2/http"` – Sebastian Hernandez Nov 10 '16 at 18:14
  • 10
    my import looks different: import { URLSearchParams } from '@angular/http'; – dang Nov 15 '16 at 15:28
  • but, there is not a more simple way to send a form object ? i did not see any tutorial using URLSearchParams() to send post for a backend with restful. how they do ? return this.http.post(this.actionUrl , body, { headers: this.headers }) .map((response: Response) => response.json()) .catch(this.handleError); – stackdave Dec 01 '16 at 11:57
  • How does this work with booleans? Getting an error saying that I cant add booleans or numbers, just strings (in append) – WJA Feb 23 '17 at 22:27
  • About boolean, maybe this topic can help you https://stackoverflow.com/questions/14774907/typescript-convert-a-bool-to-string-value – Frank Nguyen Jun 13 '17 at 06:04
  • @user623396 not anymore, as V Stoykov said in the answer (currently) below, if you use Angular's URLSearchParams you don't need to 1) do the .toString on it, and 2) set the content type. Angular will infer it automatically for you: https://github.com/angular/angular/blob/4.4.4/packages/http/src/static_request.ts#L134 and https://github.com/angular/angular/blob/4.4.4/packages/http/src/static_request.ts#L157 and https://github.com/angular/angular/blob/4.4.4/packages/http/src/body.ts#L54 – Eran Medan Oct 09 '17 at 04:03
51

I think that the body isn't correct for an application/x-www-form-urlencoded content type. You could try to use this:

var body = 'username=myusername&password=mypassword';

Hope it helps you, Thierry

Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • yes with that content type in the header, it is the only solution passing values in "the old way" instead of json string – Salvatore Pannozzo Capodiferro Oct 07 '16 at 09:28
  • This is not a good answer. Use URLSearchParams instead, like mentioned below with more upvotes. – Mick Aug 29 '17 at 14:01
  • 1
    To people from the future coming from a Google search, this is _not_ the best answer (no offense Thierry! your answer is still technically correct :)). V Stoykov's [answer](https://stackoverflow.com/a/41381299/239168) is so far the most accurate. p.s. make sure to `import { URLSearchParams } from "@angular/http"` and not the default one so 1) you don't need to do the `.toString` on it, and 2) you don't need to set the content type. Angular will infer it automatically for you (see https://github.com/angular/angular/blob/4.4.4/packages/http/src/static_request.ts#L134) – Eran Medan Oct 09 '17 at 04:12
  • Hi ! if i want to pass post service with header -> content type like 'application/json' what i need to pass in body .... i am trying to pass json object but it;s not working properly ... – VjyV Jan 25 '18 at 10:26
42

In later versions of Angular2 there is no need of manually setting Content-Type header and encoding the body if you pass an object of the right type as body.

You simply can do this

import { URLSearchParams } from "@angular/http"


testRequest() {
  let data = new URLSearchParams();
  data.append('username', username);
  data.append('password', password);

  this.http
    .post('/api', data)
      .subscribe(data => {
            alert('ok');
      }, error => {
          console.log(error.json());
      });
}

This way angular will encode the body for you and will set the correct Content-Type header.

P.S. Do not forget to import URLSearchParams from @angular/http or it will not work.

VStoykov
  • 1,705
  • 12
  • 15
  • Do you know in which version this has been added? – britter Feb 14 '17 at 15:08
  • I don't know in which version it is added but in 2.3.1 and later version it works. – VStoykov Feb 16 '17 at 22:46
  • 2
    @VStoykov it doesn't work, you have to .toString() on the params and you have to specify the content type, and I use angular 4.0.3 – Konrad Apr 25 '17 at 17:22
  • 1
    @i'myourhuckleberry It should work even on 4.0.3. Look at the source code https://github.com/angular/angular/blob/4.0.3/packages/http/src/static_request.ts#L100-L140 – VStoykov Apr 26 '17 at 11:26
  • 1
    @VStoykov it doesn't work for me and I have reported it as a bug on Github – Konrad Apr 27 '17 at 23:43
  • 1
    OK. Nvm I had to import this from "@angular/http" otherwise it recognizes the type but it's not angular's type. – Konrad Apr 27 '17 at 23:50
  • 1
    @i'myourhuckleberry the import was the first line in my example, but probably you missed it. From the built in types in the browser you can use `FormData`, and angular will set `Content-Type` as `multipart/form-data` which also work. – VStoykov May 03 '17 at 06:37
  • This doesn't work, only appending params to the url works – Frankie Drake Jul 10 '17 at 07:15
  • @Daria if you are appending params to the URL this is different then sending POST request with payload in the body. Appended URL params are called "query string". – VStoykov Jul 10 '17 at 08:12
  • 1
    @i'myourhuckleberry I saw your comment, and still missed it :) and thought I'm going crazy. to everyone reading this: do the `import { URLSearchParams } from "@angular/http"` otherwise it will import the default one from lib.es6.d.ts! (which will require you to mention the content type manually and do the `.toString()`) – Eran Medan Oct 09 '17 at 03:59
  • @EranMedan that's the reason i switched to react/vue, bloody mess in angular, if you use vue/react you can actually choose yourself what http library suits best for you. I don't like observables, I can choose a library that uses futures instead. Funny fact: angular developers probably struggle theirselves wth they made :) Personally vue looks really easy! react is a little mess with state management but i got it solved with Resub from microsoft (i'm not a fanboy of microsoft, it annoys me that they advertise azure in their all tutorials!) – Konrad Oct 12 '17 at 10:12
  • I used angular for 1 project though, it worked but it's a framework, I remember always having some issues with simple things, and most often some part of library didn't work, when I reported that issue on github I got completely ignored. It would be better if it was more simple! I kinda liked these special attributes like `ngFor` but too many complications with imports. When you use react or vue you have to install things like routing, internationalization separately. – Konrad Oct 12 '17 at 10:21
  • NIce I forgot to import the URLSearchParams now its all working thanks – Cesar Vega Nov 06 '17 at 13:14
11

so just to make it a complete answer:

login(username, password) {
        var headers = new Headers();
        headers.append('Content-Type', 'application/x-www-form-urlencoded');
        let urlSearchParams = new URLSearchParams();
        urlSearchParams.append('username', username);
        urlSearchParams.append('password', password);
        let body = urlSearchParams.toString()
        return this.http.post('http://localHost:3000/users/login', body, {headers:headers})
            .map((response: Response) => {
                // login successful if there's a jwt token in the response
                console.log(response);
                var body = response.json();
                console.log(body);
                if (body.response){
                    let user = response.json();
                    if (user && user.token) {
                        // store user details and jwt token in local storage to keep user logged in between page refreshes
                        localStorage.setItem('currentUser', JSON.stringify(user)); 
                    }
                }
                else{
                    return body;
                }
            });
    }
dang
  • 1,549
  • 1
  • 20
  • 25
6

These answers are all outdated for those utilizing the HttpClient rather than Http. I was starting to go crazy thinking, "I have done the import of URLSearchParams but it still doesn't work without .toString() and the explicit header!"

With HttpClient, use HttpParams instead of URLSearchParams and note the body = body.append() syntax to achieve multiple params in the body since we are working with an immutable object:

login(userName: string, password: string): Promise<boolean> {
    if (!userName || !password) {
      return Promise.resolve(false);
    }

    let body: HttpParams = new HttpParams();
    body = body.append('grant_type', 'password');
    body = body.append('username', userName);
    body = body.append('password', password);

    return this.http.post(this.url, body)
      .map(res => {
        if (res) {          
          return true;
        }
        return false;
      })
      .toPromise();
  }
333Matt
  • 1,124
  • 2
  • 19
  • 29
  • 1
    thanks for the above solution. But when running ng build --prod my body param's are looking like "{"params":{"rawParams":"","queryEncoder":{},"paramsMap":{}}}:". Is there any work around. – Hemanth Poluru May 07 '19 at 12:28
5

If anyone is struggling with angular version 4+ (mine was 4.3.6). This was the sample code which worked for me.

First add the required imports

import { Http, Headers, Response, URLSearchParams } from '@angular/http';

Then for the api function. It's a login sample which can be changed as per your needs.

login(username: string, password: string) {
    var headers = new Headers();
    headers.append('Content-Type', 'application/x-www-form-urlencoded');
    let urlSearchParams = new URLSearchParams();
    urlSearchParams.append('email', username);
    urlSearchParams.append('password', password);
    let body = urlSearchParams.toString()

    return this.http.post('http://localhost:3000/api/v1/login', body, {headers: headers})
        .map((response: Response) => {
            // login successful if user.status = success in the response
            let user = response.json();
            console.log(user.status)
            if (user && "success" == user.status) {
                // store user details and jwt token in local storage to keep user logged in between page refreshes
                localStorage.setItem('currentUser', JSON.stringify(user.data));
            }
        });
}
Krishnadas PC
  • 5,981
  • 2
  • 53
  • 54
3
angular: 
    MethodName(stringValue: any): Observable<any> {
    let params = new HttpParams();
    params = params.append('categoryName', stringValue);

    return this.http.post('yoururl', '', {
      headers: new HttpHeaders({
        'Content-Type': 'application/json'
      }),
      params: params,
      responseType: "json"
    })
  }

api:   
  [HttpPost("[action]")]
  public object Method(string categoryName)
Muniyan
  • 31
  • 1
  • Hi and welcome to Stackoverflow. Thank you for answering this question, but just posting a block of code is hard to understand for the OP or anyone coming across this question in the future. Would you be able to [edit](https://stackoverflow.com/posts/59087847/edit) your question and give a (short) explanation as to what the problem was you solved, and how you solved it, to help us understand your solution better? – Plutian Nov 28 '19 at 11:55
  • 1
    Hi @Plutian when i passed the value on 2nd parameter of post request it returning me the null values on api so i passed that 2nd parameter as empty string and I passed the values on params property of 3rd parameter so this method worked for me – Muniyan Nov 28 '19 at 12:52
1

I was having problems with every approach using multiple parameters, but it works quite well with single object

api:

    [HttpPut]
    [Route("addfeeratevalue")]
    public object AddFeeRateValue(MyValeObject val)

angular:

var o = {ID:rateId, AMOUNT_TO: amountTo, VALUE: value};
return this.http.put('/api/ctrl/mymethod', JSON.stringify(o), this.getPutHeaders());


private getPutHeaders(){
    let headers = new Headers();
    headers.append('Content-Type', 'application/json');
    return new RequestOptions({
        headers: headers
        , withCredentials: true // optional when using windows auth
    });
}
Sonic Soul
  • 23,855
  • 37
  • 130
  • 196
-2

I landed here when I was trying to do a similar thing. For a application/x-www-form-urlencoded content type, you could try to use this for the body:

var body = 'username' =myusername & 'password'=mypassword;

with what you tried doing the value assigned to body will be a string.

adongo
  • 125
  • 1
  • 11