Azure Machine Learning REST Endpoint - Failed to Fetch - azure

I created an Azure Machine Learning model with a REST Endpoint as a way to consume it. When I run the service using Postman everything seems to work fine.
However, when I try to create an HTML website (Codepen) with a javascript to call the REST Endpoint I only get an Error: Failed to Fetch message.
I also tried with Azure Static Web Apps and I am unsuccessful as well.
I was however able to verify (in the Console) that my input to the Rest Endpoint via Codepen is the same as Postman.
Is there anything I am missing out here?
Here is a sample of my javascript:
<script>
const form = document.querySelector('#agriculture-form');
form.addEventListener('submit', (event) => {
event.preventDefault();
const areaHarvest = parseFloat(document.querySelector('#area-harvest').value);
const farmGatePrice = parseFloat(document.querySelector('#farm-gate-price').value);
const volumeOfImport = parseFloat(document.querySelector('#volume-of-import').value);
const lowTemp = parseFloat(document.querySelector('#low-temp').value);
const averageTemp = parseFloat(document.querySelector('#average-temp').value);
const highTemp = parseFloat(document.querySelector('#high-temp').value);
const precipitationMm = parseFloat(document.querySelector('#precipitation-mm').value);
const precipitationDays = parseFloat(document.querySelector('#precipitation-days').value);
const tropicalCyclones = parseFloat(document.querySelector('#tropical-cyclones').value);
const volumeProductionGuess = 0;
const data = {
"Area_Harvested": areaHarvest,
"FarmGatePricePHPPSA": farmGatePrice,
"Volume_of_Import": volumeOfImport,
"temp_low": lowTemp,
"temp_ave": averageTemp,
"temp_high": highTemp,
"precipitation_mm": precipitationMm,
"precipitation_days": precipitationDays,
"tropical_cyclone": tropicalCyclones,
"Volume_of_Production": volumeProductionGuess
};
const formattedData = [data];
console.log('formatted data:', formattedData);
const testData = JSON.stringify(formattedData);
console.log('test data:', testData);
document.getElementById("demo").innerHTML = testData;
fetch('http://ziggyapimanagementservice.azure-api.net/score', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Ocp-Apim-Subscription-Key': 'cd529cc993494fdfb1530eaf04ae63dc'
},
body: testData
})
.then(response => response.json())
.then(data => {
console.log(data);
const result = data.result[0]; // Get the result array from the response
const volumeForecastElement = document.querySelector('#volume-forecast');
volumeForecastElement.textContent = result.join(', '); // Update the text content of the <b> element with the result array joined by commas
document.getElementById("result").innerHTML = result;
})
.catch(error => {
document.getElementById("error").innerHTML = error.message;
console.error(error.message)
});
});
And here is what I get in Postman:

Related

Correctly fetch authentication tokens server-side in a node.js React app hosted on Cloud Run

While not a front-end developer, I'm trying to set up a web app to show up a demo for a product. That app is based on the Sigma.js demo app demo repository.
You'll notice that this app relies on a graph which is hosted locally, which is loaded as:
/src/views/Root.tsx :
useEffect(() => {
fetch(`${process.env.PUBLIC_URL}/dataset.json`)
.then((res) => res.json())
.then((dataset: Dataset) => {...
// do things ....
and I wish to replace this by a call to another service which I also host on Cloud Run.
My first guess was to use the gcloud-auth-library, but I could not make it work - especially since it does not seem to support Webpack > 5 (I might be wrong here), the point here this lib introduces many problems in the app, and I thought I'd be better off trying the other way GCP suggests to handle auth tokens: by calling the Metadata server.
So I replaced the code above with:
Root.tsx :
import { getData } from "../getGraphData";
useEffect(() => {
getData()
.then((res) => res.json())
.then((dataset: Dataset) => {
// do even more things!
getGraphData.js :
import { getToken } from "./tokens";
const graphProviderUrl = '<my graph provider service URL>';
export const getData = async () => {
try {
const token = await getToken();
console.log(
"getGraphData.js :: getData : received token",
token
);
const request = await fetch(
`${graphProviderUrl}`,
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);
const data = await request.json();
console.log("getGraphData.js :: getData : received graph", data);
return data;
} catch (error) {
console.log("getGraphData.js :: getData : error getting graph data", error);
return error.message;
}
};
tokens.js :
const targetAudience = '<my graph provider service base URL>'; // base URL as audience
const metadataServerAddress = "169.254.169.254"; // use this to shortcut DNS call to metadata.google.internal
export const getToken = async () => {
if (tokenExpired()) {
const token = await getValidTokenFromServer();
sessionStorage.setItem("accessToken", token.accessToken);
sessionStorage.setItem("expirationDate", newExpirationDate());
return token.accessToken;
} else {
console.log("tokens.js 11 | token not expired");
return sessionStorage.getItem("accessToken");
}
};
const newExpirationDate = () => {
var expiration = new Date();
expiration.setHours(expiration.getHours() + 1);
return expiration;
};
const tokenExpired = () => {
const now = Date.now();
const expirationDate = sessionStorage.getItem("expirationDate");
const expDate = new Date(expirationDate);
if (now > expDate.getTime()) {
return true; // token expired
}
return false; // valid token
};
const getValidTokenFromServer = async () => {
// get new token from server
try {
const request = await fetch(`http://${metadataServerAddress}/computeMetadata/v1/instance/service-accounts/default/token?audience=${targetAudience}`, {
headers: {
'Metadata-Flavor': 'Google'
}
});
const token = await request.json();
return token;
} catch (error) {
throw new Error("Issue getting new token", error.message);
}
};
I know that this kind of call will need to be done server-side. What I don't know is how to have it happen on a React + Node app. I've tried my best to integrate good practices but most questions related to this topic (request credentials through a HTTP (not HTTPS!) API call) end with answers that just say "you need to do this server-side", without providing more insight into the implementation.
There is a question with similar formulation and setting here but the single answer, no upvote and comments is a bit underwhelming. If the actual answer to the question is "you cannot ever call the metadata server from a react app and need to set up a third-party service to do so (e.g. firebase)", I'd be keen on having it said explicitly!
Please assume I have only a very superficial understanding of node.js and React!

How to execute SQL function in Azure function project

I am working on an azure function that is invoking a web service in node.js and it works fine. I have a function GetDetails to make an SQL query to retreive data from sql server database.
const sql = require("mssql");
const dataSQL = {};
const GUID = "";
const navServiceKey = "";
const navUserName = "";
async function GetDetails() {
var email = "yamen#gmail.com";
var password = "password";
try {
console.log("nav service" + navServiceKey);
// make sure that any items are correctly URL encoded in the connection string
await sql.connect(
"Server=tcp:app.windows.net,1433;Database=BHUB_TEST;User Id=AppUser;Password=password;Encrypt=true MultipleActiveResultSets=False;TrustServerCertificate=False;ConnectionTimeout=30;"
);
const result =
await sql.query`select * from users where email = ${email} AND password = ${password} `;
if (result.rowsAffected[0] >= 1) {
dataSQL = result.recordset[0];
navServiceKey = JSON.stringify(dataSQL.navServiceKey);
GUID = JSON.stringify(dataSQL.userGUID);
navUserName = JSON.stringify(dataSQL.navUserName);
} else {
console.log("failed");
}
} catch (err) {
}}
so since this is in node.js if i were to test this sql function only i'd do the following i.e. node index.js - then function will be executed successfully and return result. However, I am calling this function within the azure function like below but when I run the azure function project, then I copy the URL given to test it on postman, the sql function won't return anything !
Any idea of how to execute SQL query function in Azure function if that makes sense ?
module.exports = async function (context, req) {
GetDetails();
const axios = require("axios");
const data = {
email: req.query.email,
password: req.query.password,
};
var cred = "YAMEN" + ":" + "jbdv******";
const encoded = Buffer.from(cred, "utf8").toString("base64");
var credbase64 = "Basic " + encoded;
const headers = {
Authorization: credbase64,
"Content-Type": " application/json",
};
{
try {
const url = `https://tegos/BC19-NUP/QryEnwisAppUser?filter=UserSecurityID eq ${GUID}`;
const response = await axios.get(url, {
headers,
});
console.log(response);
console.log(response.data);
context.res = {
// status: 200, /* Defaults to 200 */
body: response.data,
};
} catch (e) {
// maybe return the error
console.error(e);
}}};
That is not how you connect to a SQL database from an Azure application. You need to use the pyodbc module instead.
Quickstart: Use Python to query a database

Pokemon API fetch (axios) data then render all the data issue

I'm fairly new to front end and back end dev. Trying to build a small web with React / Node.js, trying to fetch data from Pokemon API: https://pokeapi.co/
I'm trying to fetch (using axios) all pokemons' ID, Name, Types, Pics then render it. I got all the data back, but when rendering it, it can only render the first data. With error message
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at new NodeError (node:internal/errors:371:5)
at ServerResponse.setHeader (node:_http_outgoing:576:11)
.....
code:
router.get('/', async function (req, res, next) {
const pokemonUrl = 'https://pokeapi.co/api/v2/pokemon?limit=10';
var pokemonPic = [];
var pokemons = [];
// a nest fetch (aixos) data
await axios({
method: 'get',
url: pokemonUrl,
timeout: 10000
})
.then((all) => {
// store data and give access for all
let { data } = all;
// fetch pokemon infomation from each url
data.results.forEach(function (pokemon) {
// the second url to fecth data
const urll = pokemon.url;
axios({
method: 'get',
url: urll,
timeout: 10000
})
.then((respon) => {
// otherwise have no access to respon
let { data } = respon;
var pokeTypes = [];
let pokeName = data.name;
let pokeID = data.id;
let pokePic = data.sprites.front_default;
// pokemon types
for (var i = 0; i < data.types.length; i++) {
pokeTypes += data.types[i].type.name + ' '
}
// check the outcome
console.log(pokeID, pokeName, pokeTypes, pokePic);
// render index from view
res.render('index', {
pokePic,
name: pokeName,
pokeTypes: pokeTypes,
pokeID
})
// return pokeID, pokeName, pokeTypes, pokePic;
})
.catch((error) => {
console.log(error);
})
})
})
Any hint will be helpful.
Warm thanks.
You can access the image of a pokemon by using :
const getPokemon = async (pokemonName) => {
await axios.get(`https://pokeapi.co/api/v2/pokemon/${pokemonName}`).then(response => {
return response.data.sprites.front_default
}).catch(err => console.log(err))
}
getPokemon('pikachu')
You should get this :

Pass query from Link to server, first time load query value undefined, after reload get correct query

I try to create some API to external adobe stock.
Like in the title, first time i get query from Link router of undefined, but after reload page it work correctly. My
main page
<Link
href={{
pathname: "/kategoria-zdjec",
query: images.zdjecia_kategoria
}}
as={`/kategoria-zdjec?temat=${images.zdjecia_kategoria}`}
className={classes.button}>
</Link>
and my server
app
.prepare()
.then(() => {
server.get("/kategoria-zdjec", async (req, res) => {
const temat = await req.query.temat;
console.log(temat)
const url = `https://stock.adobe.io/Rest/Media/1/Search/Files?locale=pl_PL&search_parameters[words]=${temat}&search_parameters[limit]=24&search_parameters[offset]=1`;
try {
const fetchData = await fetch(url, {
headers: { ... }
});
const objectAdobeStock = await fetchData.json();
res.json(objectAdobeStock);
const totalObj = await objectAdobeStock.nb_results;
const adobeImages = await objectAdobeStock.files;
} catch (error) {
console.log(error);
}
});
and that looks like getInitialProps on page next page
Zdjecia.getInitialProps = async ({req}) => {
const res = await fetch("/kategoria-zdjec");
const json = await res.json();
return { total: json.nb_results, images: json.files };
}
I think it is problem due asynchronous.
I think this might be due to the fact that you are using fetch which is actually part of the Web API and this action fails when executed on server.
You could either use isomorphic-fetch which keeps fetch API consistent between client and server, or use node-fetch when fetch is called on the server:
Zdjecia.getInitialProps = async ({ req, isServer }) => {
const fetch = isServer ? require('node-fetch') : window.fetch;
const res = await fetch("/kategoria-zdjec");
const json = await res.json();
return { total: json.nb_results, images: json.files };
}
This problem is solved, the issue was in another part of my app, directly in state management, just created new variables, and pass to link state value.

Getting data from external API before render

I have an application based on the React Starter Kit.
Every page have a fetch function that getting data from API in componentDidMount lifecycle.
I want to get data first and then render page with data and return it to the client. UX in my case no matter.
I know that RSK is isomorphic, I'm ready to change boilerplate or create my own. But I do not understand how to fetch data from API before render page(I mean how to tell express server what data requires).
How App fetching data now:
example_page.js:
import getBooks from 'queries/getAllBooks';
...
class IdTag extends React.Component {
componentDidMount(){
this.getBooks();
}
getBooks() => {
const request = getBooks();
request
.then(...)
}
}
getAllBooks.js:
import doGet from './doGet';
let result = '';
const request = async () => {
const reqUrl = '/api/books/';
result = await doGet(reqUrl);
return result;
};
export default request;
doGet.js:
const request = async reqUrl => {
let requestResult = null;
const doQuery = async () => {
const response = await fetch(reqUrl, {
method: 'GET',
});
const result = await response.json();
result.status = response.status;
return result;
};
requestResult = await doQuery();
return requestResult
}
...
export default request;
server.js:
...
app.get('/api/*', async (req, res) => {
const newUrl = config.gate.URL + req.url.replace('/api', '');
const accessToken = req.cookies.access_token;
const response = await nodeFetch(newUrl, {
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
const result = await response.json();
res.status(response.status);
res.json(result);
});
...
If each page has api calls, then Its better to use redux and redux saga. Purpose of redux saga is to handle api calls. It will process the actions in a Q. The moment u call api using fetch method, create below actioncreators
1) InitialLoading(true)
2) Fetch api call action creator
3) Based on success, error create action creator to store fetch method output data in store
4) InitialLoading(false)
You could simply set a flag when you begin your fetch, and while it's fetching return null instead of rendering. Something like:
flag = true;
request = getBooks();
request.then(flag = false);
and then:
render(){
if (flag){
return null;
} else {
return this.view;
}
}

Resources