How to correctly pass body to spring rest template? - spring

SOLUTION: The API endpoint to get this specific information is the only one different from all the other ones. Thus I was trying to contact an outdated one.
Everything described in the post works like a charm.
Using kotlin and spring, I want to send a POST request to an API.
This is a curl, generated via postman, that works correctly:
curl --location --request POST 'URL' \
--header 'Content-Type: application/json' \
--data-raw '{
"username":"username",
"password":"password"
}'
However, with spring + rest template using the following code, it seems that the body is not parsed correctly, as the API I am contacting sends me back a 401, that occurs when password/username provided are incorrect/missing.
val body = JwtQuery(getUsername(), getPassword())
return restTemplate.postForObject(url, body, Jwt::class.java)!!
This is the JwtQuery class:
data class JwtQuery (
val username: String,
val password: String
)
Note that getUsername() and getPassword() return the expected value.
What am I doing wrong ?
Edit 1: setting headers
Using:
val body = JwtQuery(getUsername(), getPassword())
val headers = HttpHeaders()
headers.contentType = MediaType.APPLICATION_JSON
val bodyEntity = HttpEntity(body, headers)
return restTemplate.postForObject(url, bodyEntity, Jwt::class.java)!!
Still returns the same error (401)
edit 2: marshaled JwtQuery
val body = JwtQuery(mesProperties.getUsername(), mesProperties.getPassword())
val marshaled = ObjectMapper().writeValueAsString(body)
println(marshaled)
Output:
{"username":"username","password":"password"}

Related

Power Query call to google.webmaster.api , Post, request problem

I call the google.webmasters.api via Power-Query(M) and managed to configure the oath2 and made my first successfull call to get & list.
Now i try to call the /searchAnalytics/query? which is working only with Post.
This always responds in a 400 error. Formating of the Query or the Url is not working correctly.
Here some additional Infomations:
Power Query - Reference
Google Webmaster Api - Reference
PowerBi Community
format Date different:
body = "{ ""startDate"": ""2019-01-01"", ""endDate"": ""2019-02-02"" }",
to
body = "{ ""startDate"": ""2019/01/01"", ""endDate"": ""2019/02/02"" }",
let
body = "{ ""startDate"": ""2019-01-01"", ""endDate"": ""2019-02-02"" }",
AccessTokenList = List.Buffer(api_token),
access_token = AccessTokenList{0},
AuthKey = "Bearer " & access_token,
url = "https://www.googleapis.com/webmasters/v3/sites/https%3A%2F%2Fxxxxxxxxx.xxx/searchAnalytics/query?",
Response = Web.Contents(url, [Headers=[Authorization=AuthKey, ContentType="application/json", Accept="application/json"], Content=Text.ToBinary(body) ]),
JsonResponse = Json.Document(Response)
in
Response
getting a 400 and is shows as 400 call in Gooogle-Api Overview
Any Ideas whats wrong?
Thx
Ensure request headers are valid. Server expects Content-Type header, not ContentType.
The documentation (https://developers.google.com/webmaster-tools/search-console-api-original/v3/searchanalytics/query#try-it) suggest requests should be something like:
POST https://www.googleapis.com/webmasters/v3/sites/[SITEURL]/searchAnalytics/query HTTP/1.1
Authorization: Bearer [YOUR_ACCESS_TOKEN]
Accept: application/json
Content-Type: application/json
{}
So seems like main takeaways are:
HTTP POST method must be used
Web.Contents documentation (https://learn.microsoft.com/en-us/powerquery-m/web-contents) suggests including the Content field in the options record to change request from GET to POST.
URL must be valid
You haven't provided your actual URL, so you'll have to validate it for yourself. I would get rid of the trailing ? in your url (as you aren't including a query string -- and even if you were, you should pass them to the Query field of the options record instead of building the query string yourself).
Headers (Authorization, Accept, Content-Type) should be valid/present.
Build your headers in a separation expression. Then pass that expression to the Headers field of the options record. This gives you the chance to review/inspect your headers (to ensure they are as intended).
Body should contain valid JSON to pass to the API method.
Creating valid JSON via manual string concatenation is liable to error. Using Json.FromValue (https://learn.microsoft.com/en-us/powerquery-m/json-fromvalue) seems a better approach.
All in all, your M code might look something like:
let
// Some other code is needed here, in which you define the expression api_token
AccessTokenList = List.Buffer(api_token),
access_token = AccessTokenList{0},
AuthKey = "Bearer " & access_token,
requestHeaders = [Authorization = AuthKey, #"Content-Type" = "application/json", Accept = "application/json"],
parametersToPost = [startDate = "2019-01-01", endDate = "2019-02-02"], // Can include other parameters here e.g. dimensions, as mentioned in Search Console API documentaton.
jsonToPost = Json.FromValue(parametersToPost, TextEncoding.Utf8), // Second argument not required (as is default), but just be explicit until you've got everything working.
url = "https://www.googleapis.com/webmasters/v3/sites/https%3A%2F%2Fxxxxxxxxx.xxx/searchAnalytics/query", // Uri.EscapeDataString function can be use for URL encoding
response = Web.Contents(url, [Headers=requestHeaders, Content=jsonToPost])
in
response
Untested (as I don't have an account or API credentials).

WebApi not accepting RestSharp AddJsonBody

I have a WebApi endpoint I can call with curl ok :
curl -X POST "https://endpoint/SendPin?email=john#smith.com" -H "accept: application/json"
WebAPI looks like this:
[HttpPost]
[Route("SendPin")]
public async Task<bool> SendPin([Required] [EmailAddress] string email)
{
....
}
Problem: The server returns a BadRequest message "Email is required" when I call it with RestSharp???
var request = new RestRequest("SendCode");
request.AddJsonBody(new { Email = "john#smith.com"});
RestClient client = new RestClient(TheUrl);
var response = await client .ExecutePostTaskAsync<bool>(request );
It appears RestSharp is not sending to the url as a param??
You are adding the email to the request body with the request.AddJsonBody() method.
Instead, add it to the request url as a querystring like you have done in the curl request
var request = new RestRequest("SendPin"+ "?email=john#smith.com");
RestClient client = new RestClient(TheUrl);
var response = await client.ExecutePostTaskAsync<bool>(request);
Because the parameter is a simple type, I need to call it like his:
request.AddParameter("email", credential.Email, ParameterType.QueryString);

Spring RestController only considers the first media type and ignores the rest

#RequestMapping(value = "/test", method = RequestMethod.GET, produces = { "text/plain", "application/json" })
If I send a request:
curl --header "Accept: text/plain, application/json" "http://localhost:8229/test/test"
It sends back a 406 Unacceptable response with HTML response body. Expected Response is a JSON object with 200 OK.
But if I reverse the order of mime-types:
curl --header "Accept: application/json, text/plain" "http://localhost:8229/test/test"
Then it sends the expected response (in JSON).
Is this expected behavior? Why is it ignoring the second media type?
PS: I'm using Spring Boot 1.3.5 release
Edit: I get the same error if I send "Accept: */*". That API can return JSON or text/plain depending upon an internal condition.
I guess it's because of not configuring your web config component in server side. Refer to Content Negotiation to configure it.

Unable to get access token for lyft api

I am trying to use the lyft developer api. I created a new app to get the client Id and client secret . I am following the steps in https://developer.lyft.com/docs/authentication to get an access token in my python code. But I always get the error, "unauthorized client". Can anyone point out my mistake?
def __init__(self):
self.client_id = 'MY_ID'
self.client_secret = 'MY_SECRET'
# obtain access token
self.token = self.__generate_token__()
# define variables to be used in the request parameters
token_val = 'Bearer '+self.token
self.headers = {'Authorization':token_val}
def __generate_token__(self):
url = 'https://api.lyft.com/oauth/token'
# define request parameters
payload = {"Content-Type": "application/json",
"grant_type": "client_credentials",
"scope": "public"}
# request data
res = requests.post(url,
data = payload,
auth = (self.client_id, self.client_secret))
# extract the token from the response
token = res.json()['access_token']
return token
This is a working example for a Java client
https://github.com/yschimke/oksocial/blob/175bdbf66e312d8bdf79183a140c2c5270329cf2/src/main/java/com/baulsupp/oksocial/services/lyft/LyftClientAuthFlow.java
The main thing that looks wrong, is sending "Content-Type" in the POST data body instead of as a header indicating the format of the data.
It looks like from the requests api that you should be sending "json = payload" instead of "data". But I'm not an expert on this python API.
The curl equivalent of the above java code also works
$ ./oksocial --curl --authorize lyft --client
Authorising Lyft API
Lyft Client Id [***********]:
Lyft Client Secret [********************************]:
curl -X POST -H "Authorization:Basic ******************" -H "Connection:Keep-Alive" -H "User-Agent:okhttp/3.5.0" -H "Host:api.lyft.com" -H "Accept-Encoding:gzip" -H "Content-Length:55" -H "Content-Type:application/json; charset=utf-8" -H "Content-Type:application/json; charset=utf-8" -d '{"grant_type": "client_credentials", "scope": "public"}' https://api.lyft.com/oauth/token

Getting Error for jersey client request headers?

I need to set these headers for a REST call via jersey client.
clickatell message send rest call
curl -i \
-X POST \
-H "X-Version: 1" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer Your Authorization Token" \
-H "Accept: application/json" \
My code is:
Client client = Client.create();
WebResource webResource = client.resource("https://api.clickatell.com/rest/message");
ClientResponse response = webResource
.header("Authorization", "Bearer clickATellAuthKey")
.header("X-Version", "1")
.header("Content-Type", "application/json")
.header("Accept", "application/json")
.post(ClientResponse.class, input);
I am getting this error:
{"error":{"code":"001","description":"Authentication
failed","documentation":"http://www.clickatell.com/help/apidocs/error/001.htm"}}
the document says the auth header is not specified. The request is working fine in Postman ( chrome restful client extension) with same headers
Need help.
1) Your headers seem to be going through. If they were not, you would get an error about not setting a version header.
2) The 001 error means your auth token was either not specified, or is incorrect.
3) I suggest that you copy and paste your entire auth token and try again. Watch out for _ or . characters as they are part of the token.
Thanks #whatever_sa there are some improvements required as well in code and also there was an issue with auth key your answer at least make me check the auth key once more. here is the working code
ClientResponse response = webResource.type(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)
.header(MessageServices.API_AUTH_HEADER, MessageServices.AUTH_KEY)
.header(MessageServices.API_VERSION_HEADER, MessageServices.API_VERSION)
.post(ClientResponse.class, input);

Resources