So I have a simple Grails UI which takes a few fields .. firstName, lastName etc. in a form. The controller calls a service method which then uses the Rest Client Builder plugin to call a REST service.
The rest service is not recognizing the parameters however.
Here is the simple rest call.
def resp = rest.post(baseUrl, params)
{
header 'Accept', 'application/json'
contentType "application/x-www-form-urlencoded"
}
Using version 2.0.1 of the plugin.
params looks like
[firstName:Kas, action:index, format:null, controller:myController, max:10]
Rest Service Method looks like ...
#POST
#Path("/employees")
#Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
#Consumes({MediaType.APPLICATION_FORM_URLENCODED})
public IdmResult createNewEmployee(#FormParam("firstName") String firstName) {
try {
if(firstName == null) return constructFailedIdmResult("First Name is a required field");
// Do some other stuff
}
}
Service responds with "First Name is a required field"
When I submit the Post from Postman it works fine. Successful request from Postman looks like
POST /idm/employees HTTP/1.1
Host: <ip>:<url>
Accept: application/json
firstName: Kas
Cache-Control: no-cache
Content-Type: application/x-www-form-urlencoded
Would like to figure how I can see the request that the plugin is constructing so I can compare differences, but ultimately I just need to know how to properly send the request from the plugin so that the Rest Service recognizes the form parameters.
Rest client should be using request body to POST:
def resp = rest.post(baseUrl) {
header 'Accept', 'application/json'
contentType "application/x-www-form-urlencoded"
json {
firstName = "Kas"
}
}
or simply,
def resp = rest.post(baseUrl) {
header 'Accept', 'application/json'
contentType "application/x-www-form-urlencoded"
json firstName: "Kas"
}
Refer docs for detail.
UPDATE:
Since producer is expecting request params as big query string instead of JSON, you might end up doing this instead:
def queryString = params.collect { k, v -> "$k=$v" }.join(/&/)
def resp = rest.post("$baseUrl?$queryString") {
header 'Accept', 'application/json'
contentType "application/x-www-form-urlencoded"
}
or just def resp = rest.post("$baseUrl?$queryString")
To pass the values cleanly in the request body, use a MultiValueMap and the (undocumented, from what I see) 'body()' method as per this answer. https://stackoverflow.com/a/21744515/17123
Related
I am using axios#0.21.1 and I want to validate the response headers.
I am unable validate the headers "Content-Type" and "Content-Encoding" from a GET response.
"Content-Type": No matter what content-type i pass in request, the content-type in response is always application/JSON.
Example Code Snippet:
if (<token is present>) {
request.headers = {
authorization : 'Bearer ${token}'
}
} else {
config.auth = {}
}
config.headers = Object.assign(config.header, {
'content-type': application/<custom content>,
'accept-encoding': 'gzip, deflate, br'
}
await axios.get(endPoint, config)
.then(response => {
return response
}*
When i am checking response.header, i see that content-type is showing as "application/json" instead of the custom type. But when i hit the same url in POSTMAN i could see that content-type is as expected.
Content-Encoding: I want to validate the content-encoding in the response, but what i learnt is axios does not return content-encoding header in the response and when i check their github, they are asking to use axios.interceptors. I tried using interceptors but still i am not seeing the header in response. But this header is present in response when i try in POSTMAN. There have been some solution say CORS needs to be enabled in server side. I am strictly asking it from QA point of view because we cannot enable CORS in server side.
Any help is highly appreciable.
Try:
axios.post(your-url, {
headers: {
'Content-Encoding': 'gzip'
}
})
or
axios.post(your-url, {
headers: {
'Accept-Encoding': 'gzip',
}
})
This is by design: https://axios-http.com/docs/req_config
I also ran into this and couldn't find a solution. Ended up using node-fetch instead.
I'm currently building out an Angular 7 App, and trying to implement the following HTTP API Call Scenario:
Request for an Application Token:
https://(URL)/token
Request Type: POST
Headers:
Accept: application/json
Request Body: empty
I have a Service class in the Angular app and the code is as follows:
import { HttpClient } from '#angular/common/http';
import { HttpHeaders } from '#angular/common/http';
The requestToken function is implemented as follows:
requestToken() {
let headers = new HttpHeaders();
headers = headers.set('Accept', 'application/json');
return this.http.post(this.configUrl + '/token', headers);
}
The Service is then called in one of the components in the App:-
getToken() {
this.service.requestToken().subscribe( res => {
console.log(res);
}, error => {
console.log(error);
});
}
When I run the App, I get a 404 Not Found error in the console. I used Postman to make an API call, setting the 'Accept' header to 'application/json' and then specifying url as https://(URL)/token and I successfully get a response. But I'm unable to make it work via Angular.
Is there something else I need to do to set the header properly in Angular? Also, I have no way to check if CORS has been enabled on the API server as this is a third-party service which I'm trying to call.
Any help would be appreciated. Thanks
Solved the problem. Changed the POST call to the following:
requestToken() {
const httpHeaders = new HttpHeaders({
'Accept': 'application/json'
});
return this.http.post(this.configUrl + '/token', { body: ''}, { headers: httpHeaders });
}
Had to add an empty 'body' parameter
Why is RestSharp posting form name/value pairs instead of JSON when I have this line: `request.RequestFormat = DataFormat.Json;
var request = new RestRequest($"api/Users/{userId}/UpdateProperty", Method.PUT);
request.RequestFormat = DataFormat.Json;
request.AddObject(new { key = key, value = value });
Execute(request);
This results in the following http request (checked using Fiddler):
PUT /api/Users/c8c946f9-e1dd-49c6-9c7f-23572017058a/UpdateProperty HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 23
Accept-Encoding: gzip, deflate
key=Gender&value=Female
I was expecting the body to be JSON:
{
key: "Gender",
value: "Female"
}
What am I doing wrong?
Instead of the AddObject method, you want to use the AddJsonBody method. You probably also want to add the "Content-type" header with "application/json" value.
Basically something like this:
var request = new RestRequest($"api/Users/{userId}/UpdateProperty", Method.PUT);
request.AddHeader("Content-type", "application/json");
request.RequestFormat = DataFormat.Json;
request.AddJsonBody(new { key = key, value = value });
Execute(request);
I'm trying to use the ebay REST-API for the first. I am simply trying to generate an access_token using the client credentials grant-request. I followed the instructions here https://developer.ebay.com/api-docs/static/oauth-client-credentials-grant.html
HTTP method: POST
URL (Sandbox): https://api.sandbox.ebay.com/identity/v1/oauth2/token
HTTP headers:
Content-Type = application/x-www-form-urlencoded
Authorization = Basic <B64-encoded_oauth_credentials>
Request body (wrapped for readability):
grant_type=client_credentials&
redirect_uri=<RuName-value>&
scope=https://api.ebay.com/oauth/api_scope
I'm getting this error: {'error': 'invalid_client', 'error_description': 'client authentication failed'} and my code looks like this:
path = 'https://api.sandbox.ebay.com/'
app_json = 'application/json'
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': base64.b64encode(b'Basic CLIENT_ID:CLIENT_SECRET')
}
payload = 'grant_type=client_credentials&redirect_uri=Searchez&scope=https://api.ebay.com/oauth/api_scope'
def get_oath_token():
url = 'https://api.sandbox.ebay.com/identity/v1/oauth2/token'
r = requests.post(url, headers=headers, data=payload)
print(r.json())
get_oath_token()
What do I have configured incorrectly? Thanks.
You're base64encoding "Basic " and shouldn't be.
The doc says just encode your Client ID + ":" + Client Secret, and leave the word "Basic" and the space that follows it alone.
In your code, i can see sandbox endpoint URI but in the request body scope, you have used production URL, instead of sandbox
I'm using Grails version 2.4.3 . I am creating an application that supports RESTful APIs. Since access to these APIs should be authenticated , I tried out the Spring Security REST plugin. I checked out this example and what I could understand is , the /api/login controller is the authentication point which receives the user credentials in JSON format and after successful authentication it provides the acces token as response. I tried sending a POST request to /api/login/ with valid JSON data using the POSTMAN Rest Client. But it gives me the following error.
401 Unauthorized , Similar to 403 Forbidden, but specifically for use when authentication is possible but has failed or not yet been provided. The response must include a WWW-Authenticate header field containing a challenge applicable to the requested resource.
I also tried using IntellijIDEA's REST Client but doesn't work.
Then i tried by sending AJAX Request to /api/login/ with valid JSON data
, but getting 401 on console. What is the problem here? Is this the correct login end point? How can i get authenticated using JQuery?
Try this
$.ajax({
url: " http://localhost:8080/AppName/api/login",
type: "POST",
crossDomain: true,
data: JSON.stringify({"username":"yourusername" , "password":"yourpassword"}),
contentType: 'application/json; charset=utf-8',
dataType: "json",
success: function (response) {
console.log(response);
},
error: function (xhr, status) {
alert("error");
}
}) });
You can try this code for authentication,I am sending user id and password in request header you can try as you wish :-
inject following services:-
def springSecurityService
def authenticationManager
and use following code
def login = {
final String authorization = request.getHeader("Authorization");
if (authorization != null && authorization.startsWith("Basic")) {
boolean authResult = authenticateUser(authorization)
if (authResult) {
render response.status
} else {
render authFailed(response)
}
} else {
render authFailed(response)
}
}
protected boolean authenticateUser(String authorization) {
// Authorization: Basic base64credentials
def base64Credentials = authorization.substring("Basic".length()).trim();
byte[] credentials = base64Credentials.decodeBase64()
String actualCredential = new String(credentials)
// credentials format like username:password
final String[] values = actualCredential.split(":", 2);
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(values[0], values[1]);
try {
def authentication = authenticationManager.authenticate(authRequest);
def securityContext = SecurityContextHolder.getContext();
securityContext.setAuthentication(authentication);
def session = request.session;
session.setAttribute("SPRING_SECURITY_CONTEXT", securityContext);
}
catch (BadCredentialsException exception) {
return false
}
return true
}
protected HttpServletResponse authFailedResponse(HttpServletResponse response) {
response.setStatus(401)
response.setHeader("WWW-Authenticate", "Basic realm=\"nmrs_m7VKmomQ2YM3:\"")
return response;
}