Problem with fetching data from Spring Boot API endpoint using Java Script - javascript

I work on web application and encountered an issue with fetching data from an endpoint using Java Script. If I type endpoint adres in a browser it works perfectly fine but somehow it does not work in the script. The response.ok is returns False.
Here is script:
(function() {
function requestAuthorization() {
let response = fetch("http://localhost:8080/authorizationData")
.then(response => response.json());
if (response.ok) {
let json = response.json();
alert(json);
} else {
alert("HTTP response not ok");
}
}
requestAuthorization();
})();
Here is controller:
#RestController
class AuthController {
private final AuthService service;
AuthController(AuthService service) throws IOException {
this.service = service;
}
#GetMapping("/authorizationData")
public ResponseEntity<AuthData> authorize() throws IOException {
return ResponseEntity.ok(service.getAuthData());
}
}
Here is service:
#Service
class AuthService {
private final ObjectMapper mapper;
AuthService(ObjectMapper mapper) {
this.mapper = mapper;
}
public AuthData getAuthData() throws IOException {
String resourcePath = "data/applicationSettings.json";
InputStream resource = new ClassPathResource(resourcePath).getInputStream();
return mapper.readValue(resource, AuthData.class);
}
}
What is wrong? If You have any other advice regarding my work I will be pleased to hear it.
EDIT
The script and and HTML file which runs it are both located in static directory in classpath.

You should be doing it like this:
// mark your function as async
async function requestAuthorization() {
// always try using const rather than let
const response = await fetch("http://localhost:8080/authorizationData");
if (response.ok) {
const json = response.json();
alert(json);
} else {
alert("HTTP response not ok");
}
}

Related

Differentiating Types of API (Apex) Exceptions In JavaScript Try/Catch

In a Lightning Web Component, I'm making an API call to an Apex method, which can throw an exception. Currently, in the catch block, there's code checking for a specific string in the exception, b/c if it's a certain type of exception we want to display a certain message to the user; otherwise we want to display another generic message. Obviously determining the specific exception by string is not robust.
Is there a good way in JavaScript to determine which specific Apex exception was thrown?
I noticed that the error object that is currently being passed to the catch block does include a headers property, and I'm wondering if I could pass a custom value in there like exceptionType? Something like:
async myFunc() {
try {
const response = await myApexMethodCall();
} catch(err) {
if (err.headers.exceptionType === 'E123') {
alert('The order must be associated with a case before processing');
} else {
alert('There was an error with the API call. Please contact your administrator');
}
}
}
You can create a custom class which represents the response. For instance,
public with sharing class CustomOrderStatusResponse {
#AuraEnabled
public String errorCode { get; set; }
#AuraEnabled
public Map<String, String> result { get; set; }
public CustomOrderStatusResponse(String errorCode, Map<String, String> result) {
this.errorCode = errorCode;
this.result = result;
}
}
And, then in controller class, you can create instance of CustomOrderStatusResponse based on different scenarios and can set differnet values for errorCode. For instance,
public with sharing class CustomOrderStatus {
#AuraEnabled
public static CustomOrderStatusResponse getOrderStatus(String orderId){
CustomOrderStatusResponse response;
try {
if (orderId.equals('123')) {
Map<String, String> result = new Map<String, String>();
result.put('status', 'completed');
response = new CustomOrderStatusResponse(null, result);
} else if (orderId.equals('456')) {
response = new CustomOrderStatusResponse('E123', null);
} else if (orderId.equals('789')) {
response = new CustomOrderStatusResponse('E789', null);
}
return response;
} catch (Exception e) {
throw new AuraHandledException(e.getMessage());
}
}
}
In frontend (LWC), you can do something like this:
import { LightningElement } from 'lwc';
import getOrderStatus from "#salesforce/apex/CustomOrderStatus.getOrderStatus";
export default class OrderStatus extends LightningElement {
handleFirstClick(event) {
this.displayOrderStatus('123');
}
handleSecondClick(event) {
this.displayOrderStatus('456');
}
handleThirdClick(event) {
this.displayOrderStatus('789');
}
displayOrderStatus(orderId) {
getOrderStatus({ orderId: orderId })
.then(response => {
if (response.errorCode === 'E123') {
alert('The order must be associated with a case before processing');
} else if (response.errorCode) {
alert('There was an error with API Call');
} else {
alert('Status: ' + response.result.status);
}
})
.catch(console.error);
}
}
Reference: https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.apex_wire_method and https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.apex_call_imperative
I hope this answers your question. Any suggestions and comments are welcome.

make a javaScript call to consume REST API running on localhost

I have a java-springboot microservice running on port 8080 and localhost server. It looks like this :
#RequestMapping("/user")
#RestController
public class UserController {
#Autowired
UserService userService;
#RequestMapping(method = RequestMethod.GET, value = "")
public User getUser() {
return userService.getUser();
}
}
I am trying to access the User data using the call "http://localhost:8080/user". While testing it through the browser and Postman the call is returning the data. But with javacript it is returning an empty response.
I am a newBee in js.
My javascript code loks like this:
function getCurrentUser()
{
try
{
var userUrl = "http://127.0.0.1:8080/user";
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
try
{
if (this.readyState == 4 ) {
var response = this.responseText;
document.getElementById("idCurrentName").innerHTML = response;
}
}
catch(erMs)
{
document.getElementById("idCurrentName").innerHTML = erMs;
}
};
xhttp.open("GET", userUrl, true);
xhttp.setRequestHeader('Content-Type', 'text/plain');
xhttp.send();
}
catch(erMsg)
{
document.getElementById("idCurrentName").innerHTML = erMsg;
}
}
Please help in accessing the data on loclhost.
Thanks!!
The issue was actually related to CORS. I initially added a chrome browser extension, but then as I am using SpringBoot in the backend for my services, I added the annotation #CrossOrigin on my RestController. That fixed the CORS problem.
Hope it helps.
The backend code now looks like this:
#CrossOrigin
#RequestMapping("/user")
#RestController
public class UserController {
#Autowired
UserService userService;
#RequestMapping(method = RequestMethod.GET, value = "")
public User getUser() {
return userService.getUser();
}
}

What is a way to return exception caught in asp.net Web Api to Angular 8?

I have my angular service like:
GetPaymentDeadlineExtension(data: PatientInput): Observable<any> {
return this.httpClient.post<any>(
this.root + `/api/PaymentDeadline/RegisterPatientInput`,data);
}
in my web api controller:
[Route("RegisterPatientInput")]
public SrvInvoiceCompositView[] RegisterGetPaymentDeadlineExtension(PatientInput data)
{
SrvInvoiceCompositView[] list = null;
string ContractNo = String.Empty;
string DktInvoiceNo = String.Empty;
try
{
ContractNo = data.BillNumber.Split('-')[0];
DktInvoiceNo = data.BillNumber.Split('-')[1];
list = DkService.SrvFindInvoiceCompositViewDentaPay(DktInvoiceNo, data.Amount, data.PatientNumber, ContractNo);
}
catch(Exception ex)
{
// exception to be returned to angular app.
}
return list;
}
and in my component.ts file:
this.homePageService.GetPaymentDeadlineExtension(this.input).subscribe(
data=>
{
this.patientInfo = data;
},
error=>
{
//i want to get my ex.message here, so i can display it
}
)
this.homePageService.GetPaymentDeadlineExtension(this.input)
.pipe(catchError((error)=> { handleError here}).subscribe(
data=>
{
this.patientInfo = data;
}
)
More info: https://www.learnrxjs.io/learn-rxjs/operators/error_handling/catch
To get an error in RxJS subscribe method you have to return such a http response that doesn't have 2xx status code. Based on your code snippet Bad Request (400) could be a good choice for example. So on .NET Core side you need to return an IActionResult following way:
[Route("RegisterPatientInput")]
public IActionResult RegisterGetPaymentDeadlineExtension(PatientInput data)
{
SrvInvoiceCompositView[] list = null;
string ContractNo = String.Empty;
string DktInvoiceNo = String.Empty;
try
{
ContractNo = data.BillNumber.Split('-')[0];
DktInvoiceNo = data.BillNumber.Split('-')[1];
list = DkService.SrvFindInvoiceCompositViewDentaPay(DktInvoiceNo, data.Amount, data.PatientNumber, ContractNo);
return Ok(list); // This is has http status code 200 in the http response
}
catch(Exception ex)
{
return BadRequest(ex.Message); // This has http status code 400 in the http response
}
}
If you put in the Angular Component file following:
this.homePageService.GetPaymentDeadlineExtension(this.input).subscribe(
data=>
{
this.patientInfo = data;
},
error=>
{
console.log(error);
}
)
After a http request you will be able to see the exception message from the backend in the browser console.
I don't know exactly the use case of the developed software, but it is not recommended to display the exception on the frontend side in production. A hacker could extract some information from the server code with causing intentionally exceptions.

Download a file from spring boot rest services from angular 5

I have spring boot service which provides csv file as response.
How do we call this service from angular 5 typescript.
download of a file should happen depends on some input parameters so I will have post call with user clicks the export button.
below is the rest code in controller.
#Controller
public class MyController {
#RequestMapping(value = "/downLoadDataQueryCsv", method = RequestMethod.GET)
public ResponseEntity<Object> downLoadDataQueryCsv(Model model) throws IOException {
FileWriter fileWriter = null;
try {
DataQueryRequestParams dataQueryRequestParams = new DataQueryRequestParams();
dataQueryRequestParams.setMbuCategory("UKY");
// Result table.
List<OrderIdFinalRank> rankList = // call api to get data.
// construct headers
List<String> csvHeaders = constructDataQueryHeaders();
StringBuilder fileContent = new StringBuilder(String.join(",", csvHeaders));
fileContent.append("\n");
// construct file content from response
for(OrderIdFinalRank finalRank : rankList) {
fileContent.append(StringUtils.join(constructDataQueryRow(finalRank), ",")).append("\n");
}
String fileName = new String("DataQueryTab.csv");
fileWriter = new FileWriter(fileName);
fileWriter.write(fileContent.toString());
fileWriter.flush();
File file = new File(fileName);
InputStreamResource resource = new InputStreamResource(new FileInputStream(file));
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition", String.format("attachment; filename=\"%s\"", file.getName()));
headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
headers.add("Pragma", "no-cache");
headers.add("Expires", "0");
ResponseEntity<Object> responseEntity = ResponseEntity.ok().headers(headers).contentLength(file.length())
.contentType(MediaType.parseMediaType("application/txt")).body(resource);
return responseEntity;
} catch (Exception e) {
System.out.println("Exception: " +e);
return new ResponseEntity<>("Error occurred", HttpStatus.INTERNAL_SERVER_ERROR);
} finally {
if(null != fileWriter) {
fileWriter.close();
}
}
}
}
Now I need to call this from UI when I click export button, what have written is below.
I have read file saver and added below code, but its not working. kindly help me.
#Injectable()
export class ApiService {
onExport(dataQueryRequestParams: any) {
const dataQueryURL = API_URL + '/downLoadDataQueryCsv';
const body = JSON.stringify(dataQueryRequestParams);
this._http.get(dataQueryURL).subscribe(res => {
saveAs(res, 'data.csv');
});
}
}
Note: When I ran rest URL from browser the file is downloaded, but the same needs to happen when I click export button.
Am new to UI technologies.
Thanks
I have fixed problem with below code.
export class ApiService {
onExport(requestParams: any): Observable<any> {
const dataQueryURL = API_URL + '/downLoadDataQueryCsv';
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'Application/json; charset=UTF-8'
}),
responseType: 'text' as 'text'
};
const body = JSON.stringify(requestParams);
return this._http.post(dataQueryURL, body, httpOptions);
}
}
added below in caller Component class.
export class Component implements OnInit {
onExport() { this._apiService.onExport(this.dataQueryForm.value).subscribe(data => {
const blob1 = new Blob([data], { type: 'text/csv' });
FileSaver.saveAs(blob1, 'data.csv');
}) ;
}
}
Thank you all for your responses !

How to use "Fetch API" to pass data between javascript and c#?

I know about how to pass data between javascript and c# by ajax, and now I want to know fetch.
c#:
namespace WebApplication1
{
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
//[System.Web.Script.Services.ScriptService]
public class WebService1 : System.Web.Services.WebService
{
[WebMethod]
public string HelloWorld()
{
return "Hello World";
}
}
}
javascript:
fetch('http://localhost:62177/WebService1.asmx/HelloWorld')
.then(response => {
alert(response.json());
})
.then(response => {
alert(response);
})
it showed:
The usage of this url is based on ajax.
I changed the url to "http://localhost:62177/WebService1.asmx?op=HelloWorld", it showed:
I thought it was response success, however I received nothing and it showed:
Then I modified the method of return data, now it was json-format :
c#:
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
public void HelloWorld()
{
object JSONObj = JsonConvert.SerializeObject("Hello World");
Context.Response.Write(JSONObj);
}
But there was no change.
I don't know how else to change it. Can someone give me a little help?
The output of your web service doesn't produce JSON. It outputs "Hello World" when it should say something like:
{"YourKeyHere":"Hello World"}
I'd change the web service code to something like this:
[WebMethod]
[System.Web.Script.Services.ScriptMethod(UseHttpGet = true, ResponseFormat System.Web.Script.Services.ResponseFormat.Json)]
public void HelloWorld()
{
var obj = new { YourKeyHere = "Hello World" };
string JSONObj = JsonConvert.SerializeObject(obj);
Context.Response.Write(JSONObj);
}
At the top of your web service, uncomment this decoration: [System.Web.Script.Services.ScriptService]. It needs to be uncommented so that JavaScript (and maybe other clients) can see your service.
In your JavaScript, your response will come back as text (not json), and it will come with a {"d":null} bracket appended to it. To clean this up, I used substrings and placed them in a different function:
function SayHello()
{
//...
var options = {
method: 'GET' ,
headers: {
'Content-Type': 'application/json',
}
};
fetch("http://localhost:62177/WebService1.asmx/HelloWorld", options)
// Handle success
.then(response => response.text())
.then(result => DisplayResponse(result))
.catch(err => console.log('Request Failed', err));
//...
}
function DisplayResponse(result) {
console.log(result); //not sure why 'd:null' shows in output
console.log(result.substring(0, result.indexOf('{"d":null}'))); //get rid of 'd:null'
console.log(JSON.parse(result.substring(0, result.indexOf('{"d":null}')))); //get rid of 'd:null' then parse
}
You first need to make sure that your server is returning something in JSON format. But in addition, in your JS, you have to return the response.json() (or the response.text() or whatever method is appropriate) infetch` so that the stream can be processed, so that you can get a response in the next function:
fetch('http://localhost:62177/WebService1.asmx/HelloWorld')
.then(response => {
return response.json();
})
.then(responseJSON => {
alert(responseJSON);
})
The initial response is a response stream object, which doesn't actually contain any data yet.

Categories

Resources