XML request and response with fetch? - javascript

The Postal Service has an API that allows you to send an xml request with package weight, travel info, etc. It will return back an xml response.
How do I handle the xml response? I either need to parse the xml on the client-side, or more preferably, put the xml in a variable that I can send to my laravel backend for parsing.
Btw, I'm using react and laravel.
getPostagePrice = () => {
fetch('http://production.shippingapis.com/ShippingApi.dll?API=RateV4&XML=<RateV4Request USERID="XXXXXXXXXXX"><PackageID="1ST"><Service>PRIORITY</Service><ZipOrigination>44106</ZipOrigination><ZipDestination>20770</ZipDestination><Pounds>1</Pounds><Ounces>8</Ounces><Container>NONRECTANGULAR</Container><Size>LARGE</Size><Width>15</Width><Length>30</Length><Height>15</Height><Girth>55</Girth></Package></RateV4Request>', {
method: 'get',
}).then((response) => {
console.log(response.text());
}).then(str => (new window.DOMParser()).parseFromString(str, "text/xml")
).then(data => console.log(data));
}

Response.text() returns a Promise, chain .then() to get the Promise value of .text() call.
If you are expecting a Promise to be returned from getPostagePrice function, return fetch() call from getPostagePrice() call.
getPostagePrice = () => {
fetch('/path/to/server')
.then(response => response.text())
.then(str => (new window.DOMParser()).parseFromString(str, "text/xml"))
.then(data => console.log(data));
}

Also with async/await you can do the same without lost your scope (remember that if you use .then, you only can work INSIDE the callback function).
async function display(){
const xmlFetch = await fetch("./yourXMLorXSL.xml")
const xmlText = await xmlFetch.text()
const xml = await (new window.DOMParser()).parseFromString(xmlText, "text/xml")
console.log(xml)
}

Related

Javascript Fetch Function returns [object Promise]

I'm currently working on a project, which includes a website, built and run by Django. On this website, I'm trying to load data through fast API and try to load this data through JavaScript and the Fetch API. But I always get instead of the Data provided through the API, an [object Promise]. I've tried many different methods but none seem to work.
I've tried for example:
document.getElementById("1.1").innerHTML = fetch('the URL')
.then(response => response.text())
or
document.getElementById("1.1").innerHTML = fetch('the URL')
.then(response => response.text())
.then((response) => {
console.log(response)
})
and many other methods. I've also checked and the API request works perfectly, returning a string.
You want the setting of the html to appear when you log the final response, eg:
fetch('the URL')
.then(response => response.text())
.then((response) => {
console.log(response)
document.getElementById("1.1").innerHTML = response
})
Other ways including making the whole of the response promise to be fulfilled:
const getData = async (url) => {
const res = await fetch(url)
const resText = await res.text()
return resText
}
const addTextFromUrl = async (url, element) => {
const text = await getData(url)
element.innerHtml = text
}
addTextFromUrl('theUrl', document.getElementById("1.1"))
Generally it is a little easier to follow the async/await syntax when learning, but you should always try/catch any errors.
Every .then call does return a new promise. So
You need to assign value in a callback or use async/await
fetch('the URL')
.then(response => response.text())
.then((response) => {
document.getElementById("1.1").innerHTML = response
})
or do it inside an async function
async function getHtml() {
document.getElementById("1.1").innerHTML = await fetch('the URL')
.then(response => response.text())
}
getHtml();
W/o using then
async function getHtml() {
const response = await fetch('the URL');
const html - await response.text();
document.getElementById("1.1").innerHTML = html;
}
getHtml();

How to handle '+' sign in fetch api?

Here is my code.
function GETdynamoDBapi(phoneNumber) {
return new Promise(function (resolve, reject) {
fetch(
'https://api?phoneNumber=' +
phoneNumber
)
.then((res) => {
return res.json();
})
.then((res) => {
resolve(data);
})
.catch((err) => {
reject(err);
});
});
}
I have tried following two case of with and without +. I have both '4100000000' and '+4100000000' data on my database table. Phone Number is defined as string in database.
let response = await GETdynamoDBapi('+4100000000'); //error return data
let response = await GETdynamoDBapi('4100000000'); //return date success
How can I handle the '+' sign? Thanks!
(edited)
I also tried to test the api https://api?phoneNumber=+4100000000 on Insomnia and it works well. But when I try following in my code, it cannot return any data.
fetch(
'https://api?phoneNumber=+4100000000'
)
You forgot to encode the value:
fetch(`https://api?phoneNumber=${encodeURIComponent(phoneNumber)}`)
This way, it will turn into e.g. phoneNumber=%2B1234567890 so that when decoding on the server it will turn back into +1234567890. The + may otherwise be interpreted as a space character on the server.
You should always encode query arguments, otherwise you will have a bug at the very least and a security vulnerability at the worst.
Another, more expressive way would be to use URLSearchParams:
fetch(`https://api?${new URLSearchParams({ phoneNumber })}`)
Or a URL object:
const url = new URL('https://api')
url.searchParams.set('phoneNumber', phoneNumber)
fetch(url)
Or, you could use a tagged template function like uri-tag:
import uri from 'uri-tag'
fetch(uri`https://api?phoneNumber=${phoneNumber}`)
On another note: You are using the explicit promise construction anti-pattern. There is no need for any new Promise because fetch already returns a promise, otherwise you couldn't do .then!
function GETdynamoDBapi (phoneNumber) {
return fetch(`https://api?${new URLSearchParams({ phoneNumber })}`)
.then(res => res.json())
}
Or you could make the function async and use await, then it would be even easier to maintain in case more logic is added and would be consistent with your other functions for which you apparently already use async/await:
async function GETdynamoDBapi (phoneNumber) {
const response = await fetch(`https://api?${new URLSearchParams({ phoneNumber })}`)
return await response.json()
}
Preemptive comment: Read here as for why I do use return await.

How can I send data on a get and receive a return?

I have to send this data in a get request but I don't know how to do it. Can you help me?
const ROUTE = "public/v1/route";
export async function showRoute(
flow: string,
token: string
): Promise<RouteParams> {
const response = await client.get(ROUTE);
return response.data;
}
You can use async/await or .then() promise chaining:
import {showRoute} from './path-to-showRoute'
showRoute(/* params */).then(data => sendGetRequest(data))
//or
async function sendRouteInfo(){
const routeData = await showRoute(/* params */)
if (routeData) sendGetRequest(routeData)
}
PS: sendGetRequest is a mock function which simply sends a get request using axios or fetch
axios.get(${URL})
.then(response => console.log(response.data)
.catch(err)=> console.log(err)
That is when you are using axios (npm i axios) then import it
I think what you're looking for is the Fetch-API. For example,
const ROUTE = resourcePath + '?' + new URLSearchParams({ ...params })
fetch(ROUTE) // sends a GET request
.then((res: Response) => res.json() as MyExpectedDataType) // parses JSON response content
.then((data: MyExpectedDataType) => {
// do something with data
})
.catch(err => {
})
// or
async function showRoute(): Promise<Something> {
try {
const res: Response = await fetch(ROUTE)
const data = await res.json() as MyExpectedDataType
// do something with data
}
catch (err) {
}
}
fetch returns a Promise type on which you can chain asynchronous callbacks using .then and handle errors with .catch and .finally. You can also pass request method, headers, body content etc. as an optional second argument to fetch, see the documentation.

making second api call after getting data from the first api

I have this first API call which gets me some data and once I have got the data from this api , only then I need to make the second api call . It must happen in the series and not parallelly. How can we do this in react ComponentDidMount?
I am listening to firebase .
Let us suppose that the first api gets me a matchId and now we need to use this matchid to make second call just after first api call without any click .
Let us suppose that this is my first firebase call .
const cardsListener =
getDATA()
.onSnapshot( (doc)=>{
console.log("doc is ",doc);
let data = doc.data();
console.log("data",data);
this.setState({
datainstate:data
});
});
Thanks to async/await, you can wait until an action is done.
componentDidMount() {
this.firstApiCall()
}
async firstApiCall() {
await fetch("http://myurl.com", {
method: 'POST',
body: JSON.stringify(data), // data can be `string` or {object}!
headers:{
'Content-Type': 'application/json'
}
})
.then(res => res.json())
.then((responseJson) => {
//if it worked
this.secondApiCall()
})
.catch(error => console.error('Error:', error))
}
secondApiCall() {
}
There are many ways you could do this. My preferred way is to use async await. I'll give an example of how you would use this below.
const getData = async() => {
try {
const apiCall1 = await axios.get(SOME_URL);
const apiCall2 = await axios.get(SOME_URL/apiCall1.data.id)
return apiCall2
} catch(e) {
return e
}
}
It's a silly example but you hopefully get the point. I make my first API call and await the response. Then I make my second API call using some data from the first call then return. You can do whatever logic you want in-between that.
You could also use a callback or promise but I think async await is clearer, and generally less code.
Async Await Documentation - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
Promises Documentation - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
Callback Documentation - https://developer.mozilla.org/en-US/docs/Glossary/Callback_function
You can follow something like this:
componentDidMount() {
fetch("apiUrl").then(res => {
//Do whatever you want to do with the response or get the id
const {id} = res;
fetch(`apiUrl/${id}`).then(response => {
// Do anything with the response of the api call here
}).catch(error => {
//Thing to do on error
});
}).catch(err => {
//Thing to do on error of 1st api call
});
}

Typescript: how to structure a fetch API call inside a method that returns a Promise response

Maybe a trivial one, but I am new with Typescript and fetch API.
In an exported class I have a public method remoteFetchSomething like:
export class className {
remoteFetchSomething = (url : string) : Promise<Response> => {
return fetch(url)
.then(
(r) => r.json()
)
.catch((e) => {
console.log("API errore fetching " + objectType);
});
}
}
export const classInstance = new className();
The method queries a remote JSON API service, and in the code, I am using it like:
import { classInstance } from ...
classInstance.remoteFetchSomething('https://example.url')
.then((json) => {
console.log(json);
}
)
The console.log is actually showing the results, but the remoteFetchSomething returns a Promise and I am unable to parse and access the JSON object values.
I would like to wait for the response before executing the remaining code, but how do I unwrap content from promise? Should I again put another .then? What am I missing?
Thank you.
By now I resolved the problem defining the return type of the remoteFetch as any:
remoteFetchSomething = (url : string) : any => {
return fetch(url)
.then(
(r) => r.json()
)
.catch((e) => {
console.log("API errore fetching " + objectType);
});
}
And now I can access JSON values like data below:
classInstance.remoteFetchSomething('https://example.url').then(
(json) => {
console.dump(json.data);
}
)
[sincerely still not clear why I cant' use the Promise<Response> type]
You can't synchronously block while waiting for a request in javascript, it would lock up the user's interface!
In regular javascript, and most versions of TypeScript, you should be / must be returning a promise.
function doRequestNormal(): Promise<any> {
return fetch(...).then(...);
}
function someOtherMethodNormal() {
// do some code here
doRequestNormal.then(() => {
// continue your execution here after the request
});
}
In newer versions of typescript, there's async/await keyword support - so instead it might look like this:
async function doRequestAsync() {
var result = await fetch(...);
// do something with request;
return result;
}
async function someOtherMethodAsync() {
// do some code here
var json = await doRequestAsync();
// continue some code here
}
Keep in mind, doRequestAsync still returns a Promise under the hood - but when you call it, you can use await to pretend that you're blocking on it instead of needing to use the .then( callback. If you call an async method from a non-async method, you'll still need to use the callbacks as normal.
this is how I do it:
type Payload = {
id: number
}
type ReturnType = number
export const functionThatHasNumberType = async (
payload: Payload
): Promise<ReturnType> => {
let url = `/api/${payload.id}`
return await axios.get(url)
}

Categories

Resources