POST request using Rest Assured with Headers and Request Body - java

I am trying to setup code in such as way that executes a POST request in my step definition class, and the POST request includes authorization (bearer token), content type, and Cookies in headers, as well as a request body in json format.
I have the bearer token process setup and am using the bearerToken for the authorization as header, content type is application/json, and the request body has the below structure:
I am unsure how to proceed in this way using Rest Assured. Below is a given method that sets the base uri and the bearer token based on environment, and based on that the bearer token will be used accordingly for authorization as header when executing the POST request:
#Given("Request the environment for the Master API {string}")
public void getMasterAPIBaseUrl(String region) throws JSONException {
if (region.equalsIgnoreCase("DEV")) {
bearerToken = accTokenSetup.accessTokenSetup(region);
RestAssured.baseURI = urlProps.getProperty("devMasterAPIUrl");
}
else if (region.equalsIgnoreCase("STG")) {
bearerToken = accTokenSetup.accessTokenSetup(region);
RestAssured.baseURI = urlProps.getProperty("stgMasterAPIUrl");
}
Reporter.log("Getting master api base url for the environment which is " + RestAssured.baseURI, true);
}
Now I need an #When step that will execute the mentioned POST request with the request body and the headers (authorization, content-type, and Cookies). I know what is required would be the endpoint, headers, request body, etc. but unsure of how to proceed with it. Any help would be appreciated!

Related

How to set request cookie header in Feign Client

I have a basic FeingClient and I need to set a cookie in the request headers so that I have a valid response. I don't really know how to do this, I have tried with #Headers and #Header as well but no success. I need for the /dogs request to have the CUSTOM_TOKEN set like I see in Postman (Cookie: CUSTOM_COOKIE={VALUE})
#FeignClient(value = "petShopApi", url="http://localhost:8080/pets")
public interface PetShopFeignClient {
#GetMapping("/dogs")
Response getResponse(#CookieValue("CUSTOM_TOKEN") String token);
}

Can not send POST with body

I have issue in my application. I have various REST enpoints which are working fine. But now I want to send POST request with body. I already have 2 endpoints for POST method, but data are send using PathParam.
I created new endpoint, but when I send request I am getting CORS error. When I use the same endpoint without body in request everything is okay but of course at backend side I do not get any data from frontend (I have breakpoint inside method).
this is how I send request from my angular application:
post(requestUrl: string, body?: any): Observable<any> {
return this.httpClient.post<any>(this.API_URL + requestUrl, {password: 'test'});
}
After sending request I got:
Access to XMLHttpRequest at 'http://localhost:8080/...' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
If I send request like this (without body) this endpoint works fine:
post(requestUrl: string, body?: any): Observable<any> {
return this.httpClient.post<any>(this.API_URL + requestUrl);
}
At backend side I have added settings for CORS:
return Response.ok(object).header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT")
.allow("OPTIONS").build();
When I am sending request from Insomnia everything is ok - I can send body and I am getting sent data on backend.
Should I somehow set request headers at frontend side?
Here is my AdminApiController class:
#Path("/admin")
#RequestScoped
public class AdminApiController extends BaseApiController {
#Inject
private AdminAssembler adminAssembler;
#POST
#Path("/login")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Response login(LoginRequest request) {
return Response.ok(adminAssembler.login(request))
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT")
.header("Access-Control-Allow-Headers", "Content-Type")
.allow("OPTIONS").build();
}
}
When your angular application sends a JSON payload in a POST request, it probably adds the header Content-Type: application/json. This header classifies the POST request as a "non-simple" request (that is, a request that cannot result out of an HTML <form> element without additional Javascript). Such "non-simple" requests cause to browser to make a preceding preflight request, that is an OPTIONS request with headers
Origin: http://localhost:4200
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type
to which the server must respond with an Access-Control-Allow-Origin header and Access-Control-Allow-Headers: Content-Type. If it does not, the browser will not make the POST request and show an error like you observed.
Your Java code covers only #POST, not #OPTIONS, that's why the server does not respond to the preflight request with the necessary headers. How best to handle the OPTIONS requests for all endpoints on your server is a question for Java experts (which I am not).
You need to define your httpOptions.
Try this.
httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json'
})
};
post(requestUrl: string, body?: any): Observable<any> {
this.httpClient.post<any>(this.API_URL + requestUrl, {password: 'test'}, this.httpOptions)
}
Let me know if it worked for you.

Sending an authorised post request using RequestBuilder and HttpUriRequest

I want to send a post request which has a bearer authorization required in java. The body of the post request takes parameters of in the following json format in postman:
{
"name": "project-002",
"description": "Test number 2",
"users": [
"ppallavalli#umass.edu"
]
}
I want to send a post request in the following way by which i executed my get request which needed authorization because authorization easier this way.
HttpUriRequest httpGet = RequestBuilder.get().setUri("https://sandbox.predera.com/aiq/api/projects/a-443018111").setHeader(HttpHeaders.AUTHORIZATION,authHeader).build();
In specific i want to send a post request using HttpUriRequest and RequestBuilder.post because authorization is easier in this case especially because the authorization required in my case is a Bearer token. Also, in the above request execution, auth header is string i have already initialized to a Bearer authorization token
You can use RequestBuilder.post() to build a POST request with a StringEntity to pass your JSON String. Rest of the headers including Authorization etc. should remain same.
String url = "https://sandbox.predera.com/aiq/api/projects/a-443018111";
String jsonString = "{...}";
HttpUriRequest httpPost = RequestBuilder.post(url).setHeader(HttpHeaders.CONTENT_TYPE, "application/json").addHeader(HttpHeaders.AUTHORIZATION, authHeader).setEntity(new StringEntity(jsonString)).build();
...

Angular Spring Boot: Redirection error: Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response

I'm using Angular 6 in the frontend and Java Spring Boot in the backend.
I want my login page to make request to server. Server redirects to dashboard page.
I have http://localhost:4200/login angular page which makes a POST request to server http://localhost:8080/login
The .ts file contains:
onLoginClickPost() {
console.log('redirect request clicked');
this.data.getUserInfoPost().subscribe(
data => {
console.log(data);
this.userInfo = data;
}
);
}
getUserInfoPost() {
return this.http.post('http://localhost:8080/login', {nextUrl: 'http://localhost:4200/dashboard'});
}
The server has #RestController with a method mapping to incoming POST request, which should redirect to http://localhost:4200/dashboard :
#CrossOrigin(origins = "http://localhost:4200")
#RequestMapping(value = "/login", method = RequestMethod.POST)
public ResponseEntity<?> login_post(#RequestBody LoginReqPostParam payload) {
HttpHeaders headers = new HttpHeaders();
try {
headers.setLocation(new URI(payload.getNextUrl()));
headers.add("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
} catch (URISyntaxException e) {
logger.error("URI Exception: ", e);
e.printStackTrace();
}
return new ResponseEntity<>(headers, HttpStatus.FOUND);
}
LoginReqPostParam is a simple class to have incoming JSON payload as object.
The login angular page is able to make POST request to the server. Now at the server, after returning the ResponseEntity from server, I'm getting following error in browser console:
Failed to load http://localhost:4200/dashboard: Request header field
Content-Type is not allowed by Access-Control-Allow-Headers in
preflight response.
How do I redirect to http://localhost:4200/dashboard page? Do I need to add something to angular dashboard component files?
You are using #CrossOrigin for POST request but Angular (in development) is sending a Preflight request using OPTIONS.
I recommend you to use a development profile that permit all origins (you must create a custom filter in a Bean for these profile)
Use Allow-Control-Allow-Origin: * extension for google chrome.
And enable cross origin resource sharing
https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi?hl=en

Header values overwritten on redirect in HTTPClient

I'm using httpclient 4.2.5 to make http requests which have to handle redirects as well.
Here is a little example to understand the context:
A sends http request (using httpclient 4.2.5) to B
B sends 302 redirect (containing url to C) back to A
A follows redirect to C
C retrieves request URL and do some work with it
If C parses the request URL by request.getRequestURL() (HttpServlet API) it contains e.g. host and port of the original request from step 1, which is wrong.
The problem exists in step 2, where httpclient handles the redirect. It just copies all headers from the original request (step 1) to the current request (step 3). I already had a look at the responsible code, via grepcode:
DefaultRequestDirector
HttpUriRequest redirect = redirectStrategy.getRedirect(request, response, context);
HttpRequest orig = request.getOriginal();
redirect.setHeaders(orig.getAllHeaders());
I don't really understand why all headers of the original request are copied to the current request.
E.g. using cURL for a simple test is doing it as expected, C would receive the correct host and port.
Implementing my own redirect strategy does not help because the original headers are copied after it.
I had the same problem when trying to download files from bitbucket's download section using HttpClient. After the first request bitbucket sends a redirect to CDN which then complains if the Authorization header is set.
I worked around it by changing DefaultRedirectStrategy.getRedirect() method to return redirect object which does not allow Authorization headers to be set.
I work with Scala so here is the code:
val http = new DefaultHttpClient()
http.setRedirectStrategy(new DefaultRedirectStrategy() {
override def getRedirect(
request: HttpRequest, response: HttpResponse, context: HttpContext
): HttpRequestBase = {
val uri: URI = getLocationURI(request, response, context)
val method: String = request.getRequestLine.getMethod
if (method.equalsIgnoreCase(HttpHead.METHOD_NAME)) {
new HttpHead(uri) {
override def setHeaders(headers: Array[Header]) {
super.setHeaders(headers.filterNot(_.getName == "Authorization"))
}
}
}
else {
new HttpGet(uri) {
override def setHeaders(headers: Array[Header]) {
super.setHeaders(headers.filterNot(_.getName == "Authorization"))
}
}
}
}
})
Please note orig.getAllHeaders() returns an array of headers explicitly added to the message by the caller. The code from DefaultRequestDirector posted above does not copy request headers automatically generated by HttpClient such as Host, Content-Length, Transfer-Encoding and so on.
You post a wire log of the session exhibiting the problem I may be able to tell why redirects do not work as expected.

Categories