Troubles with Fetch and XMLHttpRequest in javascript - javascript

So I'm doing an assignment for school and am having troubles using an API in java script. When I use XMLHttpRequest I receive the status code "0". After being frustrated from trying with XML I tried using fetch, I now get the error "Fetch failed loading: OPTIONS 'https://api-us.faceplusplus.com/facepp/v3/detect'"
To put it in context I have converted an image to base64 and need to parse that base64 as a parameter to face++ in order to do some face recognition stuff, should be cool when it works!
Here is the XML code:
function getInfo(base64) {
var request = new XMLHttpRequest();
request.open("POST", "https://api-us.faceplusplus.com/facepp/v3/detect");
request.setRequestHeader('api_key', 'my key');
request.setRequestHeader('api_secret', 'my secret');
request.setRequestHeader('image_base64', toString(base64));
request.send(null);
request.onload = function() {
console.log(request.status());
}
}
And here is the same thing attempted with fetch:
function getInfo(base64) {
var url = "https://api-us.faceplusplus.com/facepp/v3/detect"
var data = {
"api_key":"my key",
"api_secret":"my secret",
"image_base64":toString(base64)
}
var params = {
headers:{
"Content-Type":"application/json; charset=UTF-8"
},
body:data,
method:"POST"
}
fetch(url, params).then(data=>{return data.json()}).then(res=>{console.log(res.statusText)}).catch(error=>console.log(error))
}
I'm obviously missing something here and would really appreciate any help! Hope I've formatted this correctly.

you could try removing the headers params. This error
Fetch failed loading: OPTIONS
is because you are sending some header that is not recognized by the server, i would start there.

Related

Content-Disposition is always null

I've a got a function in my web api 2.0 to download a file but hadn't tried it in a while and only discovered yesterday that it was no longer working. I've partially fixed the issue with createObjectURL but one thing I've noticed is that while the Content-Disposition is set in my web api:
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
var response = new HttpResponseMessage();
var filename = this.Document.GetFilename();
var mimeType = MimeMapping.GetMimeMapping(filename);
response.Content = new StreamContent(new MemoryStream(this.Document.ToData()));
response.Content.Headers.ContentLength = this.Document.Data.Length;
response.Content.Headers.ContentType = new MediaTypeHeaderValue(mimeType);
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = filename
};
return Task.FromResult(response);
}
Yet when I check it in JavaScript, it always null from the response header:
success: function (blob, status, xhr) {
var filename = "";
var disposition = xhr.getResponseHeader('Content-Disposition');
...
}
Any ideas why?
Thanks.
UPDATE-1:
The content disposition appears to be returned when I check the response in the Network section of the browser but when I call xhr.getAllResponseHeaders() or xhr.getResponseHeader('Content-Disposition');, it is not returned by either function calls as you can see in the snapshot below:
I just figured out the problem and it was of my own doing unfortunately!!
I had the following in my ajax request:
xhrFields: {
responseType: 'blob'
}
but then I introduced credentials support and introduce this
xhrFields: {
withCredentials: true
}
but I didn't spot this until this morning when I realized I stupidly declared as above clearly i.e. 2 statements, thus, overwriting the responseType: 'blob' setting when I should have declared it as:
xhrFields: {
responseType: 'blob',
withCredentials: true
}
From server side, please set this header in response "Access-Control-Expose-Headers” with value “*” to make all headers in response to be read by frontend script. Or just set “Content-Disposition” for this case, instead of *, to only allow reading value of content-disposition header by frontend script.

Setting an API key as a header for a XMLHttpRequest

Attempting to work with a Fortnite API (https://fortnitetracker.com/site-api) and it requires me to pass the API key in the header along with my requests. I've tried using .setRequestHeader but haven't had any luck.
function getInfo(){
var xhr = new XMLHttpRequest();
xhr.open('GET','https://api.fortnitetracker.com/v1/profile/pc/ninja',true);
xhr.onload = function(){
if(this.status == 200){
console.log("Worked");
} else {
console.log(this.status);
}
}
xhr.onerror = function(){
console.log("Request Error");
}
// Fake API Key
xhr.setRequestHeader("Authorization","12345678910");
xhr.send();
}
Hope someone can help and thanks for reading.
I think you are looking for this:
xhr.setRequestHeader('Authorization', 'Bearer ' + token);
While you are getting to grips working with APIs, play with a REST client:
https://www.getpostman.com/
https://insomnia.rest/
They will help you see what these requests are supposed to look like. Basically, first figure out what the API needs with postman/insomnia and only after that you write your code.
Hope that helps!
For API Key authentication you would call it like this... .setRequestHeader "ApiKey", "MyKey".

XMLHttpRequest Not Sending

This is part of the code for the extension:
let url = "https://mywebsite.com/data.php";
function newRequest() {
var client = new XMLHttpRequest();
client.open("POST", url, true);
client.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
client.send("status=true");
console.log(client.status);
}
newRequest();
Which also logs 0 in the console. I've been following the documentation here: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest, trying countless tweaks, and there aren't any errors in the console. Not really sure what the issue could be.
The PHP on my server definitely works since I was able to POST the data successfully from a local html file.
Since the AJAX request is asynchronous, you need to handle it through a callback onreadystatechange.
The code should be like this
let url = "https://mywebsite.com/data.php";
function newRequest() {
var client = new XMLHttpRequest();
client.onreadystatechange = function() {
console.log(this.readyState) // should be 4
console.log(this.status) // should be 200 OK
console.log(this.responseText) // response return from request
};
client.open("POST", url, true);
client.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
client.send("status=true");
console.log(client.status);
}
newRequest();
Hope this helps.
For More Info: https://www.w3schools.com/js/js_ajax_http_response.asp

XMLHttpRequest - Which format does request.send(data) expect for data?

I have to use a XMLHttpRequest, but I don't know which data format is expected by the function request.send(). I searched for too long now.
I tried to pass a JSON object but it does not work:
var request = new XMLHttpRequest();
request.open("GET","fileApi");
var data = {
action: "read",
targetFile: "testFile"
};
request.addEventListener('load', function() {
if (request.status >= 200 && request.status < 300) {
$("#messageOutput").html(request.responseText);
} else {
console.warn(request.statusText, request.responseText);
}
});
request.send(data);
I get updateFile:155 XHR finished loading: GET "http://localhost/cut/public/fileApi".
But no data is received on the server. I made this simple check to approve this:
PHP (server side):
$action = filter_input(INPUT_GET, "action");
$targetFile = filter_input(INPUT_GET, "targetFile");
echo ("action = '$action' | targetFile = '$targetFile'");
exit();
Returns: action = '' | targetFile = ''
Unfortunatelly I can't use jQuery in my application, since the target is a C# Webbrowser (Internet Explorer) and it detects errors in the jQuery file and stops my scripts from working...
I don't know which data format is expected by the function request.send()
It can take a variety of formats. A string or a FormData object is most common. It will, in part, depend on what the server is expecting.
I tried to pass a JSON object
That's a JavaScript object, not a JSON object.
request.open("GET","fileApi");
You are making a GET request. GET requests should not have a request body, so you shouldn't pass any data to send() at all.
GET requests expect data to be encoded in the query string of the URL.
var data = {
action: "read",
targetFile: "testFile"
};
var searchParams = new URLSearchParams();
Object.keys(data).forEach((key) => searchParams.set(key, data[key]));
var url = "fileApi?" + searchParams;
console.log(url);
// and then…
// request.open("GET", url);
// request.send();
Warning: URLSearchParams is new and has limited browser support. Finding a library to generate a query string is left as a (simple) exercise to any reader who wants compatibility with older browsers.

Basic Authentication Using JavaScript

I am building an application that consumes the Caspio API. I am having some trouble authenticating against their API. I have spent 2-3 days trying to figure this out but it may be due to some understanding on my end. I have read countless articles on stackoverflow post and otherwise but have not solved the issue. Below is a code example of my solution based on what i have looked at and i am getting a 400 Status code message; What am i doing wrong here? (Please provide well commented code example and i would prefer to NOT have links posted here referencing other material as i have looked at these extensively. Thanks!):
Some references i have looked at:
1) Pure JavaScript code for HTTP Basic Authentication?
2) How to make http authentication in REST API call from javascript
I would like to use this authentication method as described by caspio below:
As an alternative to including credentials in the request body, a client can use the HTTP Basic authentication scheme. In this case, authentication request will be setup in the following way:
Method: POST
URL: Your token endpoint
Body: grant_type=client_credentials
Header parameter:
Authorization: Basic Basic authentication realm
Below are my Javascript and HTML code.
JavaScript:
var userName = "clientID";
var passWord = "secretKey";
function authenticateUser(user, password)
{
var token = user + ":" + password;
// Should i be encoding this value????? does it matter???
// Base64 Encoding -> btoa
var hash = btoa(token);
return "Basic " + hash;
}
function CallWebAPI() {
// New XMLHTTPRequest
var request = new XMLHttpRequest();
request.open("POST", "https://xxx123.caspio.com/oauth/token", false);
request.setRequestHeader("Authorization", authenticateUser(userName, passWord));
request.send();
// view request status
alert(request.status);
response.innerHTML = request.responseText;
}
HTML:
<div>
<div id="response">
</div>
<input type="button" class="btn btn-primary" value="Call Web API" onclick="javascript:CallWebAPI();" />
After Spending quite a bit of time looking into this, i came up with the solution for this; In this solution i am not using the Basic authentication but instead went with the oAuth authentication protocol. But to use Basic authentication you should be able to specify this in the "setHeaderRequest" with minimal changes to the rest of the code example. I hope this will be able to help someone else in the future:
var token_ // variable will store the token
var userName = "clientID"; // app clientID
var passWord = "secretKey"; // app clientSecret
var caspioTokenUrl = "https://xxx123.caspio.com/oauth/token"; // Your application token endpoint
var request = new XMLHttpRequest();
function getToken(url, clientID, clientSecret) {
var key;
request.open("POST", url, true);
request.setRequestHeader("Content-type", "application/json");
request.send("grant_type=client_credentials&client_id="+clientID+"&"+"client_secret="+clientSecret); // specify the credentials to receive the token on request
request.onreadystatechange = function () {
if (request.readyState == request.DONE) {
var response = request.responseText;
var obj = JSON.parse(response);
key = obj.access_token; //store the value of the accesstoken
token_ = key; // store token in your global variable "token_" or you could simply return the value of the access token from the function
}
}
}
// Get the token
getToken(caspioTokenUrl, userName, passWord);
If you are using the Caspio REST API on some request it may be imperative that you to encode the paramaters for certain request to your endpoint; see the Caspio documentation on this issue;
NOTE: encodedParams is NOT used in this example but was used in my solution.
Now that you have the token stored from the token endpoint you should be able to successfully authenticate for subsequent request from the caspio resource endpoint for your application
function CallWebAPI() {
var request_ = new XMLHttpRequest();
var encodedParams = encodeURIComponent(params);
request_.open("GET", "https://xxx123.caspio.com/rest/v1/tables/", true);
request_.setRequestHeader("Authorization", "Bearer "+ token_);
request_.send();
request_.onreadystatechange = function () {
if (request_.readyState == 4 && request_.status == 200) {
var response = request_.responseText;
var obj = JSON.parse(response);
// handle data as needed...
}
}
}
This solution does only considers how to successfully make the authenticated request using the Caspio API in pure javascript. There are still many flaws i am sure...
Today we use Bearer token more often that Basic Authentication but if you want to have Basic Authentication first to get Bearer token then there is a couple ways:
const request = new XMLHttpRequest();
request.open('GET', url, false, username,password)
request.onreadystatechange = function() {
// D some business logics here if you receive return
if(request.readyState === 4 && request.status === 200) {
console.log(request.responseText);
}
}
request.send()
Full syntax is here
Second Approach using Ajax:
$.ajax
({
type: "GET",
url: "abc.xyz",
dataType: 'json',
async: false,
username: "username",
password: "password",
data: '{ "key":"sample" }',
success: function (){
alert('Thanks for your up vote!');
}
});
Hopefully, this provides you a hint where to start API calls with JS. In Frameworks like Angular, React, etc there are more powerful ways to make API call with Basic Authentication or Oauth Authentication. Just explore it.
To bring this question up to date, a node.js solution (using node-fetch) would be as follows:
const auth = Buffer.from(`${clientId}:${clientSecret}`).toString("base64");
fetch("https://some-oauth2.server.com/connect/token", {
method: "POST",
body: "grant_type=client_credentials",
headers: {
"Content-type": "application/x-www-form-urlencoded",
Authorization: `Basic ${auth}`,
},
})
.then((response) => response.json())
.then((response) => {
console.log(response); //response.access_token is bearer token, response.expires_in is lifetime of token
});
Sensitive requests like this should be server-to-server, and keeping the credential details in the Header rather than QueryString means it's less likely to be visible in web server logs
EncodedParams variable is redefined as params variable will not work. You need to have same predefined call to variable, otherwise it looks possible with a little more work. Cheers! json is not used to its full capabilities in php there are better ways to call json which I don't recall at the moment.
change var to const for the username, password, token_, and key variables.

Categories