Axios post request to springboot backend - java

I'm trying to send a formData post request (using axios) to my backend (springboot) but I'm not sure of the proper way to do it. My plan is to pass the data through the controller to a service that will utilize it.
Axios call -
startStreamLocation() {
const location = new FormData();
location.set("accuracy", this.accuracy)
location.set("lat", this.lat)
location.set("lng", this.lng)
location.set("timeStamp", this.timeStamp)
axios.post("http://localhost:8080/api/v1/location/request-location", location,
{headers: {'Content-Type': 'application/json'}})
},
Controller -
#PostMapping(value = "request-location")
public ResponseEntity<?> requestLocation() {
connectionRequestService.addDataToStream();
return new ResponseEntity<Authenticator.Success>(HttpStatus.OK);
}
Service -
public void addDataToStream() {
BasicAWSCredentials awsCredentials = new BasicAWSCredentials(awsAccessKey, awsSecretKey);
AmazonKinesis kinesisClient = AmazonKinesisClient.builder()
.withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
.withRegion(awsRegion)
.build();
PutRecordsRequest putRecordsRequest = new PutRecordsRequest();
putRecordsRequest.setStreamName("location-stream");
List <PutRecordsRequestEntry> putRecordsRequestEntryList = new ArrayList<>();
PutRecordsRequestEntry putRecordsRequestEntry = new PutRecordsRequestEntry();
putRecordsRequestEntry.setData(ByteBuffer.wrap(( INJECT DATA HERE ).getBytes()));
putRecordsRequestEntry.setPartitionKey(String.format("partitionKey-%d"));
putRecordsRequestEntryList.add(putRecordsRequestEntry);
putRecordsRequest.setRecords(putRecordsRequestEntryList);
PutRecordsResult putRecordsResult = kinesisClient.putRecords(putRecordsRequest);
System.out.println("\nData sent successfully... \n" + putRecordsResult);
try {
Thread.sleep(1000);
}
catch (InterruptedException exception) {
throw new RuntimeException(exception);
}
}

Since you want to send form data to the server, you would need to change the Content-Type header in your Axios call to multipart/form-data. This helps the server understand the resource type being sent by the client.
On the server end, you'll want to read this form data. I can think of the following two ways to do that
Use #RequestParam to read individual form keys. For example, if my form data contains a key named Foo, I'd read it on the server end as this
#PostMapping(value = "/form-data")
public void readFormData( #RequestParam(value = "Foo") String foo )
Use #RequestBody to map the form data to a MultiValueMap which can be then read from like a normal map. Here's the code snippet for the same
#PostMapping(value = "/form-data")
public void readFormData( #RequestBody MultiValueMap<String,String> formData )

Related

Using BodyInserters to pass parameter with webClient

There is my code.
public Mono<RespDto> function(TransReqDto1 reqDto1, TransReqDto2 reqDto2, String token) {
MultipartBodyBuilder builder = new MultipartBodyBuilder();
builder.part("TransReqDto1", reqDto1);
builder.part("TransReqDto2", reqDto2);
MultiValueMap<String, HttpEntity<?>> parts = builder.build();
LinkedMultiValueMap map = new LinkedMultiValueMap();
map.add("TransReqDto1", reqDto1);
map.add("TransReqDto2", reqDto2);
return
client.post()
.uri("/api")
.body(BodyInserters.fromValue(reqDto1))
.headers(h -> h.setBearerAuth(token.split(" ")[1]))
.retrieve()
.bodyToMono(RespDto.class);
}
My probelm is that I need to send both reqDto1 & reqDto2. I've successfully sent reqDto1 with the code above but I can't figure out a way to send two objects.
Tried MultipartBodybuild and MultiValueMap but both are returning error from the target API. Please give me some hints!! Thank you
Here is the API I am trying to call!
#PostMapping("")
#ApiOperation(value = "test", notes = "test")
public Mono<?> transPost(#Valid #RequestBody TransReqDto1 reqDto1,
#Valid #RequestBody TransReqDto2 reqDto2) {
return testService.function(reqDto1, reqDto2);
}
You cannot use two #RequestBody. It can bind to a single object only. The expected way to do that is to create a wrapper DTO containing all the relevant data:
public class TransReqDto {
private TransReqDto1 transReqDto1;
private TransReqDto2 transReqDto2;
//...
}

Passing a BODY of a POST request to the server

I have built a Restful-API Java(SpringBoot) and created the needed requests.
The following request is a POST Request to add new Category.
I have tested the POST request by POSTMAN, and it working as expected.
I am building the client-side in ASP.NET 5.x.x.
Now the problem appear when I am calling the post request, it seems the API doesn't receive the data (#RequestBody category) that has been send from the client.
Here is a code simple of how I have created them
Server Side:
#ResponseStatus(HttpStatus.CREATED)
#PostMapping(value = "/add", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public CategoryDTO create(#RequestBody CategoryDTO category) {
log.info("Adding new Category Name: " + category.getName());
return categoryMapper.asCategoryDTO(categoryService.save(categoryMapper.asCategory(category)));
}
Client Side
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(Category category)
{
Category newCategory = new Category();
// Serialize the concrete class into a JSON String
var stringPayload = JsonConvert.SerializeObject(category);
// Wrap the JSON inside a StringContent which then can be used by the HttpClient class
StringContent content = new StringContent(stringPayload);
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
using (var httpClient = new HttpClient())
{
using (var response = await httpClient.PostAsync("http://localhost:8080/category/add", content))
{
string apiResponse = await response.Content.ReadAsStringAsync();
newCategory = JsonConvert.DeserializeObject<Category>(apiResponse);
}
}
return RedirectToAction("Index");
}
I don't know what is wrong there, could anybody help!
EDIT--
Here is the request via postman
EDIT
I have created another POST request but as a RequestParam instead of RequestBody
#ResponseStatus(HttpStatus.CREATED)
#PostMapping(value = "/add", produces = MediaType.APPLICATION_JSON_VALUE)
public CategoryDTO addCategory(#RequestParam(name = "categoryName") String categoryName){
return categoryMapper.asCategoryDTO(categoryService.addCategory(categoryName));
}
and created in the client side the request as following
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(Category category)
{
Category newCategory = new Category();
var parameters = new Dictionary<string, string> { { "categoryName", category.Name } };
var encodedContent = new FormUrlEncodedContent(parameters);
using (var httpClient = new HttpClient())
{
using (var response = await httpClient.PostAsync("http://localhost:8080/category/add", encodedContent))
{
string apiResponse = await response.Content.ReadAsStringAsync();
newCategory = JsonConvert.DeserializeObject<Category>(apiResponse);
}
}
return RedirectToAction("Index");
}
And It's works fine!
So the problem is how to pass the data via the httpClient, which need to be of type RequestBody (the data in the body not in the header!) also as a application/json.
So how to pass the data?
I suppose that your spring boot application just blocks POST request because you didn't provide instruction how to handle requests. Try to disable csrf protection like it did here: https://stackoverflow.com/a/48935484/13314717
It might be a problem in the naming convention. Starting with capital letters in properties in C#, and starting with lowercase in Java.
If your class looks like this in C#
class Category {
int Id;
string Name;
...
}
And like this in Java
class Category {
int id;
string name;
...
}
It is not going to work so you have to match the property names. So make either both id or both Id.

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.

GET/POST Requst to REST API using Spring Boot

I have a REST Service an external server like https://api.myrestservice.com and I have a Spring Boot Application running locally on http://localhost:8080. Now I want to make GET or POST request to the REST API address i.e https://api.myrestservice.com/users to get all users, using my locally running Spring Boot App i.e through http://localhost:8080/users. I am not getting how to redirect local app request to external server request.
I hope I got your question right. You are trying get your local app to get data from app running on your server.
You can use the below sample code in your spring boot application.
private void getUsers() {
final String uri = "https://api.myrestservice.com/users";
RestTemplate restTemplate = new RestTemplate();
Users result = restTemplate.getForObject(uri, Users.class);
System.out.println(result);
}
Then your getUsers can be invoked by getUsers Controller in your spring boot app.
I am adding the reference if you want to look at more examples -
https://howtodoinjava.com/spring-restful/spring-restful-client-resttemplate-example/
Making post Api call from your code to another server:
suppose you have a server https://searchEmployee... which returns you list of employees belonging to a particular city or belonging to a particular organization:
request body:
{
"city" : "Ranchi",
"organisation" : "Bank Of America"
}
json response: [{"name": "Vikash"},{"name":"kumar" },{}...etc]
Then to make a post api call you can use RestTemplate in java like this:
public void makeApiCall(){
final String uri = "https://searchEmployee...";
RestTemplate restTemplate = new RestTemplate();
String reqBody = "{"city": "Ranchi"}";
String result = restTemplate.postForObject(uri, reqBody, String.class);
// convert your result into json
try {
jsonResponse = new JSONObject(result);
} catch (JSONException e) {
e.printStackTrace();
}
//extract a value "name" from your json data:
try{
String value = jsonResponse.getString("name");
}catch(JSONException e) {
e.printStackTrace();
}
}
/********************************************************************/
if you have more than one request body parameters to set do it like this:
String reqBody = "{\"quantity\":100,\"name\":\"product1\",\"ifBoolean\":false}";
false is a boolean value here in your request body and 100 is an integer.
NOTE
if you are having problem in setting request body copy it directly from postman request body and paste it inside double quote.
There are many ways to do it. Like Apache HTTP Components and other. Sample
String type = "application/x-www-form-urlencoded" Or Set your desire content type;
String encodedData = URLEncoder.encode( rawData, "UTF-8" );
URL u = new URL("your remote url");
HttpURLConnection conn = (HttpURLConnection) u.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty( "Content-Type", type );
conn.setRequestProperty( "Content-Length",
String.valueOf(encodedData.length()));
OutputStream os = conn.getOutputStream();
os.write(encodedData.getBytes());
There are a couple of thing going on here, Like URLEncoding is really mattered when came to security.
Note: Source of above code:here.
This is very Simple By using Java Clients you can Use RestTemplate or UniRest
That one running on Remote is simply Producer and the one which is in local is Consumer So you can exchange method of Resttemplate or get method of Unirest
Example Code is here.
#RequestMapping(value = "/testclient")
public String testclient()
{
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
HttpEntity<String> entity = new HttpEntity<String>(headers);
return restTemplate.exchange("https://www.mocky.io/v2/5185415ba171ea3a00704eed", HttpMethod.GET, entity, String.class).getBody();
}
For Unirest code is like this
HttpResponse<JsonNode> jsonResponse = null;
try {
jsonResponse = Unirest.get("https://www.mocky.io/v2/5185415ba171ea3a00704eed")
.header("accept", "application/json").queryString("apiKey", "123").asJson();
} catch (UnirestException e) { // TODO Auto-generated catch block
e.printStackTrace();
}
return jsonResponse.getBody().toString();

Notification for HTTP POST

I am new to Spring framework and have tried creating an api for others to use.
This is in my controller class
POST method
// -------------------Create a Report-------------------------------------------
#RequestMapping(value = "/report/", method = RequestMethod.POST)
public ResponseEntity<?> createReport(#RequestBody Report report, UriComponentsBuilder ucBuilder) {
logger.info("Creating Report : {}", report);
if (reportRepository.isReportExist(report)) {
logger.error("Unable to create. A report with name {} already exist", report.getCrisisID());
return new ResponseEntity(new CustomErrorType("Unable to create. A Report with crisisID " +
report.getCrisisID() + " already exist."),HttpStatus.CONFLICT);
}
reportRepository.saveReport(report);
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ucBuilder.path("/api/report/{crisisID}").buildAndExpand(report.getCrisisID()).toUri());
return new ResponseEntity<String>(headers, HttpStatus.CREATED);
}
GET Method
// -------------------Retrieve All Reports---------------------------------------------
#RequestMapping(value = "/report/", method = RequestMethod.GET)
public ResponseEntity<List<Report>> listAllReports() {
List<Report> reports = reportRepository.findAllReports();
if (reports.isEmpty()) {
return new ResponseEntity(HttpStatus.NO_CONTENT);
// You many decide to return HttpStatus.NOT_FOUND
}
return new ResponseEntity<List<Report>>(reports, HttpStatus.OK);
}
Below is the an example code for others to create the report object and send it to my api.
// POST
private static void createReport() {
System.out.println("Testing create Report API----------");
RestTemplate restTemplate = new RestTemplate();
Report report = new Report(20, "General", 4, "AA1",10000,"crisis details", "1 hour", "COA1", "COA1");
URI uri = restTemplate.postForLocation(REST_SERVICE_URI + "/report/", report,
Report.class);System.out.println("Location : "+uri.toASCIIString());
}
I am wondering if the following is possible or if there is any way to approach this situation:
When someone creates a report and sends it to me via POST URL, my POST method will be able to automatically detect that a new report entry is created and then sends a notification in my HTML/JSP page (such as a pop up window).
Update
RestApiController.java
#RestController
#RequestMapping("/api")
public class RestApiController {
public static final Logger logger = LoggerFactory.getLogger(RestApiController.class);
#Autowired
ReportRepository reportRepository; //Service which will do all data retrieval/manipulation work
// -------------------Create a Report-------------------------------------------
#RequestMapping(value = "/report/", method = RequestMethod.POST)
#SendTo("/channel/publicreport")
public ResponseEntity<?> createReport(#RequestBody Report report, UriComponentsBuilder ucBuilder) {
logger.info("Creating Report : {}", report);
if (reportRepository.isReportExist(report)) {
logger.error("Unable to create. A report with name {} already exist", report.getCrisisID());
return new ResponseEntity(new CustomErrorType("Unable to create. A Report with crisisID " +
report.getCrisisID() + " already exist."),HttpStatus.CONFLICT);
}
reportRepository.saveReport(report);
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ucBuilder.path("/api/report/{crisisID}").buildAndExpand(report.getCrisisID()).toUri());
return new ResponseEntity<String>(headers, HttpStatus.CREATED);
}
}
WebSocketConfig.java
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chatservice");
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/app");
registry.enableSimpleBroker("/channel");
}
}
main.js
'use strict';
var stompClient = null;
var username = null;
function connectReport(event) {
username = "myname";
if(username) {
//var socket = new SockJS('/ws');
//stompClient = Stomp.over(socket);
stompClient = Stomp.client('ws://localhost:8080/chatservice');
stompClient.connect({}, onConnectedReport, onError);
}
event.preventDefault();
}
function onConnectedReport() {
// Subscribe to the Public Channel
stompClient.subscribe('/channel/publicreport',onReportMessageReceived);
}
function onError(error) {
connectingElement.textContent = 'Could not connect to WebSocket server. Please refresh this page to try again!';
connectingElement.style.color = 'red';
}
function onReportMessageReceived(payload) {
//Code for pop up window
}
window.addEventListener("load", connectReport, true)
In general taks like this is delegated to client. I.e. client polls the server for the changes it is interested in and once detected the client reacts accordingly. The oldest way (which is now absolete) was to add a tag into HTML that forces the entire page to refresh with a certain frequency which means the page sends a request to the server and receives an updated page to display. IN our days there are all kinds of frameworks that do partial updates to the page. One of the first ones was Ajax, then DHTML and so on and so forth. I am not a client side progrqammer. But as far as the concept goes such task is usually given to client

Categories

Resources