Unable to log response from XMLHttpRequest - javascript

I have created one XMLHttpRequest class wrapper for GET request. I am not able to console log the response i am getting. Is there something i am missing in the code ?
HttpWrapper.js
class HttpCall {
static get(endpoint, headers = {}) {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
//the request had been sent, the server had finished returning the response and the browser had finished downloading the response content
if (4 === xhr.readyState) {
if (200 <= xhr.status && 300 > xhr.status) {
resolve(xhr.response);
} else {
reject(xhr.status);
}
}
};
if (headers) {
Object.keys(headers).forEach(function (header) {
xhr.setRequestHeader(header, headers[header]);
});
}
xhr.open("GET", endpoint, true);
xhr.send(null);
});
}
}
export default HttpCall;
index.js
import HttpCall from "./utils/HttpWrapper";
import { BASE_BACKEND_URL } from "./constants/Config";
HttpCall.get(
BASE_BACKEND_URL + "?event_family=session&source_id=guru1",
function (response) {
console.log(response);
}
);

It looks like you're passing a callback to your method call instead of using the promise you returned. Your call should be formed more like:
HttpCall.get(
BASE_BACKEND_URL + "?event_family=session&source_id=guru1")
.then((response) => {
// handle resolve
console.log(response);
}).catch((error) => {
// handle reject
console.error(error);
})

Related

Getting returned value from another javascript file using async

class monitor {
constructor(){
this.delay = config.delay
delay(time) {
return new Promise(function (resolve) {
setTimeout(resolve, time);
});
}
async redacted (pid) {
if (this.err === true) {
await this.delay(this.delay)
}
console.log("MONITOR > Getting Item Attrs")
const options = {
method: 'get',
url: url + pid + '.json',
headers: {
accept: '*/*',
'accept-encoding': 'gzip, deflate, br',
},
proxy: this.proxy
}
return req(options)
.then((res) => {
//console.log(res)
let variants = res.data.skus
//console.log(variants)
const att = []
for (let [key, value] of Object.entries(variants)) {
if(value.inStock) att.push(key)
}
if(att.length >= 1){
console("MONITOR > Sourced Item")
return att;
} else {
("MONITOR > No Variants Available")
this.oos = true
this.redacted(config.pid);
}
})
.catch((err) => {
if (err?.response?.status == 403) {
console.error("MONITOR > Proxy Block # GET PRODUCT")
this.err = true
this.redacted(config.pid);
}
})
}
}
var hello = new monitor().redacted(config.pid);
console.log(hello)
From what I understand I need to wait for the promise to finish before returning but I am confused on how to execute this with my code and also call this file and store the return value in another file. I'm not sure if my formatting is wrong as well, but I tried changing and no fix anyways
This snippet isn't using asynch but, it gives you the idea. You need to await or .then the promise (the fetch/request). You first fetch the remote JSON file then you parse it / read it. Something like:
function getJSON(url) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open('get', url, true);
//xhr.responseType = 'json';
xhr.onload = function () {
var status = xhr.status;
if (status == 200) {
resolve(JSON.parse(xhr.response)); // <---------------
} else {
reject(status);
}
};
xhr.send();
});
};
getJSON(primaryURL).then(function (res) {
if (res) {
//do something
} else {
console.log("response not found");
}
}).catch(function (error) {
console.log("Error getting document:", error);
});

How does this code that uses a callback in `XMLHttpRequest` work?

This is a very simple callback function but I still can’t wrap my mind around it. Can someone try to explain it to me?
const getToDos = (one) => {
const req = new XMLHttpRequest();
req.addEventListener(`readystatechange`, () => {
if (req.readyState === 4 && req.status === 200) {
one(undefined, req.responseText);
}
else if (req.readyState === 4) {
one(`couldnt fetch data`, undefined);
}
});
req.open(`GET`, `https://jsonplaceholder.typicode.com/todos/`);
req.send();
};
getToDos((err, data) => {
if (err) {
console.log(err);
}
else {
console.log(data);
}
});
Also, can someone tell me what the difference is between XMLHttpRequest and the GET method? Are XMLHttpRequests used in the front end and GET methods used in the back end?
//Defining getToDos function, it takes one argument, which is another function
const getToDos = (one) => {
//Create a request
const req = new XMLHttpRequest();
//Add an event listener on the status of the request and gives code to execute when it happens
req.addEventListener(`readystatechange`, () => {
//if request is completed (4) and its status is good (200)
if (req.readyState === 4 && req.status === 200) {
//Call the callback function give undefined as error and req.responseText as data
one(undefined, req.responseText);
//if request is completed (4) and its status is good (!= 200)
} else if (req.readyState === 4) {
//Call the callback function give `couldnt fetch data` as error and undefined as data
one(`couldnt fetch data`, undefined);
}
});
//prepare request and give endpoint
req.open(`GET`, `https://jsonplaceholder.typicode.com/todos/`);
//send request
req.send();
};
//execute getToDos function and give a function as parameter
getToDos((err, data) => {
//if err is not undefined
if (err) {
//log error
console.log(err);
} else {
//log data
console.log(data);
}
});
This kind of code is old. Instead you should :
let data = await fetch(`https://jsonplaceholder.typicode.com/todos/`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
})
if(data.status == 200){
let parsed = await data.json()
console.log(parsed)
} else {
console.log(data)
}
–––––
Edit: Added example for the OP
const aFunction = (callback) => {
const aRandomBoolean = Math.random() < 0.5
if(aRandomBoolean){
console.log('Boolean is true !')
callback('first parameter', 'second parameter')
} else {
console.log('Boolean is false !')
callback('parameter 1', 'parameter 2')
}
}
aFunction((paramA, paramB)=>{
console.log(paramA, paramB)
})

How can I print the "PUT" and "POST" method at the same time?

The function written to the bottom of the two functions works but the other one does not work. I am not getting an error message either. I think the transaction is taking place but nothing has been written. How can I get both to be written to the console? I'll put the console's printout below. Thank you in advance for your answers.
class Request {
constructor() {
this.xhr = new XMLHttpRequest
}
post(url, data, callback) {
this.xhr.open("POST", url)
this.xhr.setRequestHeader("Content-type", "application/json")
this.xhr.onload = () => {
if (this.xhr.status === 201) {
callback(null, this.xhr.responseText)
} else {
callback("Hata", null)
}
}
this.xhr.send(JSON.stringify(data))
}
put(url, data, callback) {
this.xhr.open("PUT", url)
this.xhr.setRequestHeader("Content-type", "application/json")
this.xhr.onload = () => {
if (this.xhr.status === 200) {
callback(null, this.xhr.responseText, callback)
} else {
callback("Hata", null)
}
}
this.xhr.send(JSON.stringify(data))
}
}
const request = new Request()
request.post("https://jsonplaceholder.typicode.com/albums", {
userId: 9,
title: "Thriller"
}, function (error, response) {
if (error === null) {
console.log(response);
} else {
console.log(error);
}
})
request.put("https://jsonplaceholder.typicode.com/albums/9", {
userId: 2,
title: "Thriller"
}, function (error, response) {
if (error === null) {
console.log(response);
} else {
console.log(error);
}
})
// Console Print
{
"userId": 2,
"title": "Thriller",
"id": 9
}
You should use your xhr once, not multiple times. To fix this, simply call const xhr = new XMLHttpRequest() in each method you need it.
You're only creating one Request object, named request. The first call to request.post() uses this.xhr to perform a POST, but before that async process finishes, you're calling request.put() which performs a PUT, effectively ignoring the previous POST.
A simple way to resolve this is by creating two Request objects:
const request = new Request()
const request2 = new Request()
request.post("https://jsonplaceholder.typicode.com/albums", {
userId: 9,
title: "Thriller"
}, function (error, response) {
if (error === null) {
console.log(response);
} else {
console.log(error);
}
})
request2.put("https://jsonplaceholder.typicode.com/albums/9", {
userId: 2,
title: "Thriller"
}, function (error, response) {
if (error === null) {
console.log(response);
} else {
console.log(error);
}
})
You could also refactor your code to use fetch() instead. Other possible solutions: In JavaScript how do I/should I use async/await with XMLHttpRequest?

Testing an AJAX function with xhr-mock fails

I'm trying to test the following function from my network.js:
export function post (data) {
return new Promise(function (resolve, reject) {
// need to log to the root
var url = window.location.protocol + '//' + window.location.hostname
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = () => {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 204) {
resolve(null)
} else {
reject(new Error('an error ocurred whilst sending the request'))
}
}
}
xhr.open('POST', url, true)
xhr.setRequestHeader('Content-type', 'application/json')
xhr.send(JSON.stringify(data))
})
}
My test case looks like this:
import xhrMock from 'xhr-mock'
import * as network from '../src/network'
describe('Payload networking test suite', function () {
beforeEach(() => xhrMock.setup())
afterEach(() => xhrMock.teardown())
test('POSTs JSON string', async () => {
expect.assertions(1)
xhrMock.post(window.location.protocol + '//' + window.location.hostname, (req, res) => {
expect(req.header('Content-Type')).toEqual('application/json')
return res.status(204)
})
await network.post({})
})
})
When running my test suite I'm getting:
xhr-mock: No handler returned a response for the request.
POST http://localhost/ HTTP/1.1
content-type: application/json
{}
This is mostly based on the documentation and I don't understand why its failing
Solution
add a trailing / to the url you are giving xhrMock.post()
Error Details
The url is http://localhost.
That turns into a req.url() of
{
protocol: 'http',
host: 'localhost',
path: '/',
query: {}
}
Calling toString() on that object returns 'http://localhost/'
xhr-mock compares the URLs by doing req.url().toString() === url
'http://localhost/' === 'http://localhost' returns false so xhr-mock is returning an error that no handler returned a response.
I found I had some problems as well and using the following module was a better alternative for me:
https://github.com/berniegp/mock-xmlhttprequest
Usage is pretty straight forward:
const MockXMLHttpRequest = require('mock-xmlhttprequest');
const MockXhr = MockXMLHttpRequest.newMockXhr();
// Mock JSON response
MockXhr.onSend = (xhr) => {
const responseHeaders = { 'Content-Type': 'application/json' };
const response = '{ "message": "Success!" }';
xhr.respond(200, responseHeaders, response);
};
// Install in the global context so "new XMLHttpRequest()" uses the XMLHttpRequest mock
global.XMLHttpRequest = MockXhr;

How to replicate jQuery ajax method

The problem: I'm trying to replicate the jQuery ajax method since I'm using XMLHttpRequest more than once in a script. However, I do not think including jQuery as a dependency is necessary since I would only be using a maximum of 3 methods from the jQuery library. Therefor I need a good way of replicating the jQuery's ajax method and so far I've gotten this far but please see explanation of output below the code example:
function ajax(obj) {
/*
obj = {
type: 'GET',
url: 'my/url/',
success: function (response) {},
error: function (response) {},
isTrue: true
}
*/
var
response = null, // defaults to null
complete = function (resp) {
console.log(resp); // outputs the response
response = resp;
},
error = function (resp) {
response = resp;
},
request = new XMLHttpRequest();
request.open(obj.type || 'GET', obj.url, obj.isTrue || true);
request.onreadystatechange = function (e) {
if (request.readyState === 4) {
if (request.status >= 200 && request.status < 400) {
complete(request.responseText);
} else {
error(request.statusText);
}
}
}
request.send();
return {
done: function (callback) {
callback(response);
}
}
}
Then when I call the ajax function in another function:
var xhr = ajax({
url: 'js/routes.js',
}).done(function (resp) {
console.log(resp); // outputs 'null'
});
the response variable is null although the complete() function set the response variable to the value of the ajax .responseText.
Question: How can I return the value of .responseText from the request to the object the ajax function is returning so that I can do something with it in a callback function like I intend to do inside the .done() method of that object?
Thank you!
You have an error in your implementation. The 'done' function does not wait for response.
function ajax(obj) {
/*
obj = {
type: 'GET',
url: 'my/url/',
success: function (response) {},
error: function (response) {},
isTrue: true
}
*/
var _callback = null,
response = null, // defaults to null
complete = function (resp) {
if(_callback){
_callback(resp);
}
response = resp;
},
error = function (resp) {
if(_callback){
_callback(resp);
}
response = resp;
},
request = new XMLHttpRequest();
request.open(obj.type || 'GET', obj.url, obj.isTrue || true);
request.onreadystatechange = function (e) {
if (request.readyState === 4) {
if (request.status >= 200 && request.status < 400) {
complete(request.responseText);
} else {
error(request.statusText);
}
}
}
request.send();
return {
done: function (callback) {
if(response){
callback(response);
}else{
_callback = callback;
}
}
}
}
EDIT*
consider using a microlibrary instead of jQuery. Don't reinvent the wheel.
http://microjs.com/#ajax

Categories

Resources