1

As the title suggests, I am attempting to write an AJAX call using Angular's $http object. I would like to send a post request that submits JSON in the body of the request, but also has a query string appended to the URL. After reading the documentation for $http all the way through, surfing for answers on SO, and attempting several different configurations, I am still not clear on how to pass the parameters correctly. Currently, my API responds with either empty JSON or Bad Request (400).

Code

function inviteStaff (json) {
    authToken = service.getAuthToken();
    return $http({
        method: 'POST',
        url: baseUrl + '/invitations' + '?authToken=' + authToken,
        data: JSON.stringify(json),
        headers: {
            'Content-type': 'application/json'
        }
    });
}

Consuming Function

self.invite = function ($form) {
    self.showLoader = true;
    InvitesService.inviteStaff($scope.inviteModel).then(function () {
        $form.$setPristine();
        $scope.inviteModel.timestamp = new Date();
        $scope.invites.unshift($scope.inviteModel);
        $scope.inviteModel = self.createNewInvite();
        self.showLoader = false;
    }, 
    function () {
       self.showLoader = false;
    });
};

Request log

data: "authToken=********&t=*****" // this is weird because it adds another "t" parameter to this query string here 
headers: Object
    Accept: "application/json"
    Accept-Language: "en"
    Content-type: "application/json"
    authToken: "*********" // just the token here
    __proto__: Object
method: "POST"
params: Object
timeout: Object
transformRequest: Array[1]
transformResponse: Array[1]
url: "http://****.****.com:****/doctors/invitations?authToken=*****"
__proto__: Object

Param JSON object

{
    accountType: "LEAD_DOCTOR", 
    firstName: "kraken", 
    lastName: "lastName", 
    email: "kraken@mail.com"
}

Can anyone shed a little light on how this should work? Do I pass the json object to data or params? Do I need to use JSON.stringify on the data field? In some cases, I also saw people passing an empty string to data.

I also have been running it through Charles Proxy. I can get very close to what I want, but for some reason the JSON is showing under the JSON Text filter as a query string, and not the JSON filter.

Any ideas would be helpful. I will be refactoring and upgrading it all to use the $resource tool, but we are on a tight deadline and I just want to get this working for now. Let me know if you need more info.

UPDATE We're using swagger to document our API, and you can actually hit the endpoint in their UI. It produces the following CURL command. I thought it might help spot the issue.

curl -X POST --header "Content-Type: application/json" --header "Accept: application/json" -d "{
    \"firstName\": \"string\",
    \"lastName\": \"string\",
    \"email\": \"blah@mail.com\",
    \"accountType\": \"CLIENT\"
}" "http://*****.****.com:****/doctors/invitations?authToken=***obfuscatedAuthToken***"
Kraken
  • 5,043
  • 3
  • 25
  • 46
  • 1
    what exactly is the problem here? – M B Mar 22 '16 at 14:28
  • 1
    Second question: you can pass the whole javascript object, Angular will handle it – dex Mar 22 '16 at 14:29
  • @MB I will update the question – Kraken Mar 22 '16 at 14:30
  • 1
    using data is correct, params is used for variables and data for an object. You do not have to do anything to your object just pass it as is – M B Mar 22 '16 at 14:33
  • where are you passing it to? could be you are accepting it wrong on the API side? – M B Mar 22 '16 at 14:35
  • Check the latest update @MB. I get successful response in both swagger and on Advanced REST Client for Chrome. – Kraken Mar 22 '16 at 14:38
  • I'm confused. What URL are you having problems with? You're showing code that posts to an invitations URL, but you're showing the response from a login URL. Which is it? – Brett Mar 22 '16 at 14:51
  • @Brett You are correct! Sorry I was messing with two at once. I updated the log and the json obj – Kraken Mar 22 '16 at 14:59
  • This might seem silly as http headers are supposed to be case-insensitive, but have you tried `Content-Type` instead of `Content-type`? – Brett Mar 22 '16 at 15:06
  • I tried it just now. No dice. :( – Kraken Mar 22 '16 at 15:07
  • It would be interesting to find out where that extra `t` parameter in the query string is coming from. – Brett Mar 22 '16 at 15:13
  • @Brett I looked into it. There is an additional JS file that consumes this. It adds an additional parameter. I'm trying to see if there is anything I should add here. – Kraken Mar 22 '16 at 15:20
  • It's a timestamp @Brett. I stepped into the consuming code, and nothing much happens there since the request fails. – Kraken Mar 22 '16 at 15:44
  • @Brett I added that function above – Kraken Mar 22 '16 at 15:50
  • I found an httpInterceptor function that appears to be breaking the JSON, since previously we were not using JSON. I think I can get to the bottom of this. Thanks for helping me refine my $http request, y'all. I'll post the solution later. – Kraken Mar 22 '16 at 16:29

2 Answers2

2

I would recommend you to take advantage of the header field:

function inviteStaff (json) {
authToken = service.getAuthToken();
return $http({
    method: 'POST',
    url: baseUrl + '/invitations',
    data: JSON.stringify(json),
    headers: {
        'Content-type': 'application/json',
        'authToken': authToken
    }
   });
 }

Then on the server side, ask the current request for the header value of authToken.

Passing Tokens in the URL has some security concerns, for your reading: https URL with token parameter : how secure is it?

Community
  • 1
  • 1
Marcus Höglund
  • 16,172
  • 11
  • 47
  • 69
  • "we are on a tight deadline and I just want to get this working for now" -- Your suggestion is valid, but not what the OP is looking for atm. – Brett Mar 22 '16 at 14:48
  • @Brett was right on the nose. Very helpful advice for the future, though. Thanks! We are actually already planning to tighten up security in the near future. – Kraken Mar 26 '16 at 13:28
0

It turns out we had an HTTP Interceptor function elsewhere in the codebase that was changing the content-type! Wrapped that in a conditional, and it is good to go now. Thanks to everyone who helped me ensure my code was written correctly!

Kraken
  • 5,043
  • 3
  • 25
  • 46