2 way ssl using spring boot java - java

I am new to this concept.
I am using Insomnia for testing my api end points.
I have a .crt file and a .key file added in the collections environment inside insomnia.
when i send in my api, i get a valid response. this is how its code format looks like:
HttpResponse<String> response = Unirest.post("https://covdch-api.cdc.gov/v0/upload/cvrs/batch")
.header("accept", "application/json")
.header("Authorization", "eyJhbGciO")
.header("Content-Type", "text/plain")
.body("VkFYX0VWR")
.asString();
and this is the output i get:
{
"id": "b719a89",
"totalRecords": 1,
"validationErrors": [
],
"validationErrorsCount": 0,
"storageResult": {
"REDACTED_DB": {
"status": "SUCCESS",
"processingErrors": [
],
"processedCount": 0,
"processingErrorsCount": 0
}
}
}
I am trying to use this in my separate spring boot project as a getmapping like this:
#RequestMapping(path = "/validate")
public String hello() throws UnirestException{
HttpResponse<String> response = Unirest.post("https:post-api.com-someexample")
.header("accept", "application/json")
.header("Authorization",
"eyJhbGciOiJIUzU")
.header("Content-Type", "text/plain")
.body("VkFYX0VWRU5")
.asString();
}
ofcourse im not getting the ouptut because I did not configure my .crt file and .key file in the eclipse (which I did inside insmonia).
Probably thats where Im stuck.
Can anyone guide me on how to achieve this?

Related

Filtering response using webclient

I'm new using webclient to cosume a Rest API and I want to know how can I filter a response to match only what I want.
So I have this endpoint which brings me a customerById but I need to show only the the systemsId = 100
Let me show:
#GetMapping("/getCucoId/{cucoId}")
public Mono<CuCoPerson> getCucoRelationById(#PathVariable Integer cucoId) {
WebClient webClient = WebClient.create();
return webClient.get()
.uri(GET_RELATION_BY_ID + cucoId)
.header("Accept", "application/json")
.header("Authorization", "Bearer eyJraWQiOi.....")
.retrieve()
.bodyToMono(CuCoPerson.class);
}
And the POJO:
#Data
#NoArgsConstructor
#AllArgsConstructor
public class CuCoPerson {
private Integer cucoID;
private List<CustomerRelation> relatedCustomers;
}
And this is the response in Postman:
{
"cucoID": 100288298,
"relatedCustomers": [
{
"customerId": "F6305957",
"systemId": 100
},
{
"customerId": "F8364917",
"systemId": 400
},
{
"customerId": "F4194868",
"systemId": 101
}
]
}
So I need only to show the relatedCustomers who only have a systemID = 100
Thanks in advance!
I think you are looking for either Mono.map(), or Mono.flatMap().
Remove the customers, who don't match in the function, and return the changed object.
#GetMapping("/getCucoId/{cucoId}")
public Mono<CuCoPerson> getCucoRelationById(#PathVariable Integer cucoId) {
WebClient webClient = WebClient.create();
return webClient.get()
.uri(GET_RELATION_BY_ID + cucoId)
.header("Accept", "application/json")
.header("Authorization", "Bearer eyJraWQiOi.....")
.retrieve()
.bodyToMono(CuCoPerson.class)
.map(cuCoPerson -> {
List<CustomerRelation> matches = cuCoPerson.getRelatedCustomers()
.stream()
.filter(relation -> relation.getSystemId().equals(100))
.collect(Collectors.toList());
cuCoPerson.setRelatedCustomers(matches);
return cuCoPerson;
});
}
As mentioned in other answers, doing this kind of filtering on client side is bad practice. If possible the API should expose parameter for systemId and return only the data you need.
First of all this is bad Backend design. Since you (client side) have the need for such info you should have an endpoint available to get your info by customer ID and System ID. Data filtering should be done on the backend and the client should remain as thin as possible. Otherwise you perform logic both on server-side and client-side plus you send some completely unneeded info over the network and then filter it out on the client side. But if that's your available resources and you can't change the server-side then you you take your JSON response, and parse it into your class that maps to that JSON or just into Map<String,Object> if you don't have the class for that JSON and filter it out yourself. To parse a json string to map or a specific POJO you can use Jackson library - method readValue() of ObjectMapper Or Gson library. Also, I wrote my own simple wrapper over Jackson library that simplifies the use. Class JsonUtils is available as part of MgntUtils library (written and maintained by me). This class just has the methods that allow you to parse and de-serialize from/to Json String from/to a class instance. Here is a simple example on how to parse your JSON string into a Map<String,Object> with JSONUtils class
Map<String,Object> myMap
try {
myMap = JsonUtils.readObjectFromJsonString(myJsonStr, Map.class);
} catch(IOException ioe) {
....
}
MgntUtils library available as Maven artifact and on Github (including source code and Javadoc)
it could be something like this:
return webClient.get()
.uri("/someUrl")
.header("Accept", "application/json")
.header("Authorization", "Bearer eyJraWQiOi.....")
.retrieve()
.bodyToFlux(CuCoPerson.class)
.filter(cuCoPerson -> cuCoPerson.getRelatedCustomers().stream().anyMatch(cr -> cr.getSystemId() == 100))
.take(1)
.next();
But this has disadvantage that you are filtering the results on client side (your application). I would try to ask the api provider if s/he is able to provide filter parameter (something like systemId) and in that case you would call the endpoint with that query param.

Sent Json to REST API - Access Control Allow Origin [ERROR]

I want to send a json to my REST API. i tried it with Postman and it works fine. Now i want to sent Data from my frontend. I dont know where i need to add the header and how i do it. Im using Springboot for my BackEnd and Vue for my FrontEnd.
My Controller:
#RestController
#RequestMapping("/api/auth")
public class FileController {
FileService fileService;
public FileController(FileService fileService) {
this.fileService = fileService;
}
#RequestMapping(
value = "/data",
method = RequestMethod.POST,
consumes = "application/json")
public void process(#RequestBody String payload) throws Exception{
System.out.println(payload);
try {
FileWriter writer = new FileWriter(...);
writer.write(payload);
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
My main.js, which shall send the data:
const toSend ={
"name": "test",
"test1":"test2"
};
const jsonString = JSON.stringify(toSend);
const xhr = new XMLHttpRequest();
xhr.open("POST", "http://localhost:8090/api/auth/data");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.send(jsonString);
console.log(jsonString)
You need to enable cors for this controller.
There is an annotaion for that matter.
Check out this guide
https://spring.io/guides/gs/rest-service-cors/
Are you sure that sending by xhr is best solution? why don't you use fetch?
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
Yours vue app and spring boot apps runs on different ports and browser sees it separate websites that why it blocks because of cors. Other solution that adding cors headers, can be proxy on js side.

How to send a Content-Type form-data request using rest assured?

I need to invoke a form-data typed API using Rest Assured. Here is my code.
private Map<String, String> getFormParamsMap() {
Map<String, String> formParams = new HashMap<>();
formParams.put("creatorId", "Instructor1");
formParams.put("creatorPlatform", "Web");
formParams.put("creatoredSource", "File");
formParams.put("creatoredType", "Auto");
formParams.put("deckId", "5a605b472e02d86561172dad");
formParams.put("userId", "kind");
return formParams;
}
public void invoke() {
response = given()
.header("Content-Type", "application/form-data")
.header(AUTHORIZATION_HEADER_NAME, accessToken) //Some API contains access token to run with the API
.headers(headers)
.formParams(getFormParamsMap()) // requestParamsMap here.
.when()
.post(invokingEndpoint);
}
When I execute this, I am getting the below error.
Message: java.lang.IllegalArgumentException: Don't know how to encode creatorPlatform=Web&creatoredType=Auto&deckId=5a605b472e02d86561172dad&creatorId=Instructor1&creatoredSource=File&userId=kind as a byte stream.
Please use EncoderConfig (EncoderConfig#encodeContentTypeAs) to specify how to serialize data for this content-type.
For example: "given().config(RestAssured.config().encoderConfig(encoderConfig().encodeContentTypeAs("application/form-data", ContentType.TEXT))). .."
Stack Trace:
io.restassured.internal.http.EncoderRegistry.encodeStream(EncoderRegistry.java:130)
When I use .config(RestAssured.config().encoderConfig(encoderConfig().encodeContentTypeAs("application/form-data", ContentType.TEXT))) in the invoke() method, it gives the result as below.
{
"status": 400,
"message": "Content type 'application/x-www-form-urlencoded;charset=ISO-8859-1' not supported",
"error": "Bad Request",
"exception": "org.springframework.web.HttpMediaTypeNotSupportedException"
}
My request is not x-www-form-urlencoded type, it is form-data type. I can execute it using postman.
Appreciate your support on this.
Thanks.
I have solve this issue by using encodeContentTypeAs("multipart/form-data", ContentType.TEXT)
Ex:-
public void invoke() {
response = given()
.config(
RestAssured.config()
.encoderConfig(
encoderConfig()
.encodeContentTypeAs("multipart/form-data", ContentType.TEXT)))
.headers(headers)
.formParams(formParams)
.when()
.post(oAuthBaseURI).then().extract().response();
}
Please add the consumer as well.
See here for the encoders available for Rest Assured.
This might be causing the problem -
encodeContentTypeAs("application/form-data", ContentType.TEXT)
You can also try this -
.encoderConfig(encoderConfig().appendDefaultContentCharsetToContentTypeIfUndefined(false).encodeContentTypeAs("application/form-data", ContentType.TEXT));
As far as I can tell, headers(headers) method replaces all headers, and then RestAssured uses x-www-form-urlencoded content type as default.
Try adding "Content-Type" header after the call to headers(headers).

Post multipart file and json in one request with #RequestPart from angular4

I use Jhipster and this is a controller method:
Controller:
#RequestMapping(value = UPLOAD_URL, method = {RequestMethod.POST},
headers = {"content-type=multipart/mixed", "content-type=multipart/form-data"},
consumes = {"multipart/form-data"})
public ResponseEntity<?> uploadWithMetaData(#RequestPart(value = "file") MultipartFile file,
#RequestPart(value = "documentDTO") DocumentDTO documentDTO,
Locale locale) throws IOException, URISyntaxException, JSONException {
// business logic
}
Essentially I want to post a file and also a json object.
I my integration test, I can verify that it works as expected:
Integration test:
DocumentDTO documentDTO = getDocumentDTOMockFile();
Long originId = originRepository.findAll().stream().findFirst().get().getId();
documentDTO.setOriginId(originId);
MockMultipartFile jsonFile = new MockMultipartFile("documentDTO", "", "application/json",
jsonUtils.toJson(documentDTO, null).getBytes());
restClientMockMvc
.perform(MockMvcRequestBuilders.fileUpload("/api/v1/documents/upload")
.file(fstmp)
.file(jsonFile))
.andDo(MockMvcResultHandlers.log())
.andExpect(status().isOk());
}
Angular frontend:
let fd: FormData = new FormData();
let file = fileForm.files[0];
fd.append("file", file);
let documentDTO = JSON.stringify(document);
fd.append("documentDTO",new Blob([JSON.stringify({
"documentDTO": documentDTO})], {
type: "application/json"
})
);
his.httpClient.post("/api/v1/documents/upload", fd ).subscribe(request => {
console.log("request", request);
});
I got an interceptor that sets the content-type in the request headers to:
Content-Type:multipart/form-data; boundary=----WebKitFormBoundary4PnIOSOLe5Djj95R
This is how the Request payload looks like:
This is the spring boot log message:
Resolved exception caused by Handler execution: org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present
This is the response I see in the browser:
{
"type" : "http://www.jhipster.tech/problem/problem-with-message",
"title" : "Bad Request",
"status" : 400,
"detail" : "Required request part 'file' is not present",
"path" : "///api/v1/documents/upload",
"message" : "error.http.400"
}
What I've tried:
setting content-type to 'Content-Type' : 'multipart/mixed' => result same
Creating a pojo with the dto and the file, using #ModelAttribute => same error
Then I checked if I got a Multipart Resolver, got it
I'm out of ideas, someone any suggestions?
Post as a multipart-form from the JavaScript and use something like this:
final WebRequest webRequest,
#RequestParam("fileContent") final MultipartFile fileContent,
#RequestParam("inputJson") String inputJsonString
as the parameters.
The WebRequest is useful if you need to access the session.

Sending #RequestBody from node js to Spring Boot Rest API

After spending more than half a day still not able to get down to whats wrong with the following:
Trying to send form data from NodeJSto Spring Rest API.
Node JS:
var inputData = { base : req.body.base, test : req.body.test }
var queryParams = {
host: '127.0.0.1',
port: 8080,
path: '/start',
method: 'POST',
headers: {'Content-type': 'application/json'},
body: inputData //Used JSON.stringify(inputData) - didn't work
};
Using http module to send request:
var req = http.request(queryParams, function(res) {
//do something with response
});
req.end();
Spring Rest:
#RequestMapping(value = "/start", method = RequestMethod.POST, consumes = "application/json")
#ResponseBody
public String startApp(#RequestBody String body) {
System.out.println(body);
return "{\"msg\":\"Success\"}";
}
Using postman I am able to see the same inputData going through the Rest. But when sent from NodeJS, all I see is
{
timestamp: 1506987022646,
status: 400,
error: 'Bad Request',
exception: 'org.springframework.http.converter.HttpMessageNotReadableException',
message: 'Required request body is missing: public java.lang.String ApplicationController.startApp(java.lang.String)',
path: '/start'
}
Using spring-boot-starter parent in the maven.
Am I missing anything here? Any suggestions would be greatly appreciated!
I don't think that you put request body in queryParams will work.
You can try using req.write() to write data to request body as follows:
...
req.write(inputData);
req.end();
...

Categories

Resources