3

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: enter image description here

update: I added the CORS setting in the Azure API Management and still has the issue: enter image description here

3-10-2023 update: I added the Accept Header in the Javascript and removed the access key for the moment. Also changed the API to HTTPS just to see if things change.Also changed the CORS value in the API enter image description here

enter image description here

It works with Postman though but not with the Javascript: enter image description here

Last Update: Changed CORS again and it now works! enter image description here

Ziggy
  • 491
  • 1
  • 6
  • 17
  • Can you shows Postmana's succussed screens with required information (endpoint, modelUri and other)? – Bench Vue Feb 19 '23 at 01:59
  • 1
    @BenchVue i added my JS and the Postman sample – Ziggy Feb 19 '23 at 02:14
  • I can get the result by Postman but I try to call by script, can't get the result. Fetch did not POST call. – Bench Vue Feb 19 '23 at 03:39
  • @BenchVue same here so i dont know why – Ziggy Feb 19 '23 at 03:47
  • I don't know either, let's wait someone help your problem – Bench Vue Feb 19 '23 at 05:34
  • What error did you get @Ziggy? Please, be sure that your REST endpoint is sending the `allow-*` CORS related headers appropriate for your javascript application, it could be very likely related to your problem. – jccampanero Feb 27 '23 at 22:58
  • @jccampanero it is related to that but the endpoint has no way im told to allow CORS – Ziggy Feb 27 '23 at 23:39
  • @jccampanero I was on vacation but couldnt reply back.. anyways, I added the CORS setting as per your suggestion and I still get the issue – Ziggy Mar 09 '23 at 13:57
  • Thank you very much for the feedback @Ziggy. I even removed the answer... Please, can you review it? I included further alternatives. Please, could you try? – jccampanero Mar 09 '23 at 16:46
  • @jccampanero added your answers as seen in the update above.. still nothing :( – Ziggy Mar 11 '23 at 00:28

1 Answers1

1

As stated in my comment, the error could be very likely related to a CORS problem.

Please, consider configuring your REST endpoint for sending the CORS headers appropriate for your Javascript application.

You seem to be using API Management for exposing the REST endpoint: if that is correct, you can configure CORS by defining the appropriate policy.

This page provides the necessary information about how to set or edit API Management policies.

The CORS policy is documented in this other page. The documentation provides a sample configuration, adapted for your use case:

<cors allow-credentials="true">
    <allowed-origins>
        <!-- Localhost useful for development -->
        <origin>http://localhost:8080/</origin>
        <origin>http://your-javascript-app-domain.com/</origin>
    </allowed-origins>
    <allowed-methods preflight-result-max-age="300">
        <method>POST</method>
    </allowed-methods>
    <allowed-headers>
        <header>content-type</header>
        <header>accept</header>
    </allowed-headers>
</cors>

This related SO question could be of help as well.

Additionally, please, consider including an Accept header when posting your information, we have experienced problems when this header is not present when invoking an API exposed by the API Management service, I am not absolutely sure, but I think it is not included by default by fetch (in contrast to Postman):

fetch('http://ziggyapimanagementservice.azure-api.net/score', {
        method: 'POST',
        headers: {
            'Accept': '*/*',
            '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)
        });
jccampanero
  • 50,989
  • 3
  • 20
  • 49
  • @Ziggy Were you able to test the proposed solution? – jccampanero Mar 02 '23 at 22:13
  • @Ziggy I included an alternative solution in the answer. I hope it helps. – jccampanero Mar 04 '23 at 15:15
  • I did what you mentioned..added Accept Header and Added the CORS setting. still nothing :( – Ziggy Mar 10 '23 at 04:45
  • @Thank you very much for the feedback @Ziggy. Please, could you try two more things? First, could you include `https://cdpn.io` in your CORS configuration? That is actually the domain from which Codepen sends the requests to the application. If that doesn't work, please, could you remove `` from your `` definition in API Management? I still think that the error is motivated by CORS. – jccampanero Mar 11 '23 at 18:14
  • wow yes it does indeed work. Thank you so much!! You have helped me tons! Now If I would create a static Web app and Azure for this, what should i put in the domain? – Ziggy Mar 12 '23 at 16:15
  • That is nice @Ziggy, I am happy to hear that it is working fine now. Regarding your question, when you create the Static Wep App, Azure auto-generates a domain name for your website, something like `https:///azurestaticapps.net/`. That is the domain you need to include in your CORS configuration. If you prefer to, you could define a [custom domain](https://learn.microsoft.com/en-us/azure/static-web-apps/custom-domain) for the website as well: in that case, it should be the one you need to provide in your CORS configuration. – jccampanero Mar 12 '23 at 18:02
  • oh thanks let me try this. for codepen how did you know it was https://cdpn.io. Where did it say btw? – Ziggy Mar 13 '23 at 01:06
  • Of course, I hope it helps. Regarding codepen, please, see the errors provided in the browser development console, in case of CORS related problems it will indicate the host from which the requests are being sent, in this case, cpdn.io. – jccampanero Mar 13 '23 at 16:51
  • @Ziggy Please, forgive me to point it out but, if you want to award the bounty, you must do it explicitly because the answer was posted before you started it. Again, sorry, but it is always very frustrating for both the OP and the person who provides the answer to realize that the bounty is lost for that reason. – jccampanero Mar 16 '23 at 17:50
  • oh sorry! I thought accepting the answer was awarding it!!!! – Ziggy Mar 20 '23 at 16:56
  • Please, there is no need to say sorry @Ziggy. In the end the only important thing is that you were able to solve the problem. – jccampanero Mar 20 '23 at 22:32