Returning Data from express server | function call? - javascript

I am trying to return a response from a backend server, of technologies that match a specific url which is searched on the front end.
My form will submit, and the URL will change, but no results will come through, and no errors appear in the console.
My front end script tag is as follows:
function Submit () {
e.preventDefault();
const formResult = new FormData(form);
const url = '/' + encodeURIComponent(formResult.get('search'));
const button = document.getElementById('search');
const sendHttpsRequest = (method, url, data) => {
return fetch(url, {
method: method,
body: JSON.stringify(data),
headers: data ? {'Content-Type': 'application/json'} : {}
}).then(response => {
if (response.status >= 400) { //response okay
return response.json().then(errResData => {
const error = new Error('Something went wrong');
error.data = errResData;
throw error;
});
}
return response.json();
});
};
const getData = () => {
sendHttpsRequest('GET', '/:url').then(responseData => {
console.log(responseData);
});
};
button.addEventListener('search', getData);
}
Is there something here I am missing? I think it might be a function call, but do I also need to include a function call when I am sending an HTTP request? Where would the function call go in this case? What would it look like?

You have lots of problems with this.
You call getData when a button is clicked, but only if that button is clicked after Search is called. You never call Search.
The first thing Search does is call e.preventDefault, but e isn't defined anywhere.
You create formResult from a variable called form which you never define
You create formResult when Submit is called but it looks more like something you want to do when getData is called
You set the body of the request with JSON.stringify(data), but you've never defined data … and if you intended to say formResult then that would be a FormData object which won't convert to JSON.
When you send the request you sent it to '/:url' which uses Express parameter syntax … but this is the client-side code so you need to put the actual data there.
You define a variable url in Submit but then you never use it (probably you intended to use it in 6 but forgot and hardcoded a string that didn't make sense instead).
You are trying to set a body on a GET request
You seem to have thrown a lot of code together without testing it as you went along.
I recommend starting from scratch.
Write a function to be called when you click the button. Have it just prevent the default behaviour and log something to the console.
Then fetch the form data you want and log that.
Continue to work from there, testing each stage as you go along so you can detect the mistakes like these.

Related

Connect to an API with URL Login and Password in Typescript / Javascript

I'm new to Web programming, and I wanted to know how to make easy requests to connect to an API if the only information I have are the URL, a login and password using pure Typescript or Javascript.
The goal is to retrieve an access Token.
I would advise using the browsers fetch API which uses promises.
let us begin here. In the past browsers offered AJAX calls but ever since modern JS came through with promises, everything got really easy. You can find out more about promises here.
let us consider an example similar to your case where you have a url endpoint, and some data you want to send to the url. we expect that the url with respond with a JSON payload containing a token.
// so we will define our constants here
const url = 'http://localhost/login';
const username = 'username';
const password = 'password';
// now we configure the fetch request to the url endpoint.
// we should probably put it inside a separate function since
// you're using a browser, you probably will bind this request
// to a click event or something.
function login() {
return fetch(url, {
// in the case of a login request most APIs use the POST method offered by
// RESTful APIs
method: 'post', // can be 'get', 'put', 'delete', and many more
// now we set any needed headers specified by the API
headers: {
// most APIs I have worked with use
'Content-Type': 'application/json',
// but some might need more, they will specify anyway.
},
// because we are using the 'post' method then we will need to add
// a body to the request with all our data, body excepts a string so
// we do the following
body: JSON.stringify({
username: username,
password: password,
}),
})
// Now we handle the response because the function returns a promise
.then((response) => {
// An important thing to note is that an error response will not throw
// an error so if the result is not okay we should throw the error
if(!response.ok) {
throw response;
}
// since we expect a json response we will return a json call
return response.json();
})
}
now since you are using a browser you will have to bind the function to
an element to trigger the call
// will define a self calling arrow function that will do the event binding
((button) => {
button.addEventListener('click', (event) => {
// we then call the function here.
login()
.then((response) => {
// side note, you could destructure the response argument as { token }
// then just reference token instead.
// recall that we expect this function to have a 'token' key in
// the response payload...so let us log it just to make sure
console.log(result.token);
})
});
// we add the button reference as the argument
})(document.querySelector('#submit'));
References:
Promises
RESTful
I hope this helps give a better idea on the task you have, good luck
u can use axios for js/ts
like this example :
getToken = () => {
axios.post('http://localhost/login',{
username: username,
password: password,
}).then((response) => {
let data = response.data;
//do whatever u want here eg :set token to local storage
localStorage.set('token',data.token);
}).catch((error) => {
console.log(error);
});
};
getToken();

JavaScript post Fetch API

I want to post with the Fetch API and call an action from my controller but the action is not being loaded like when I would do it with submitting a post form.
function postQuery() {
let query = document.getElementById("query").value;
fetch('/actionName', {
method: 'POST',
body: query,
headers:
{
"Content-Type": "application/x-www-form-urlencoded"
}
})
.then(response => {
console.log(response);
})
.then(data => {
console.log('Success:', data);
})
}
/actionName is not being loaded, I am supposed to be directed to a different page.
When I would submit a form like that:
<form action="/actionName" method="post">
the public function actionName would be called but with fetch its not working.
When i try to see the $_POST with var_dump($_POST) inside of actionName, I am getting an empty array...I dont understand this
I see two questions here:
Why is the data not accessible to the server
Why is the brower not redirected to /actionName
Answer to #1:
Make sure the content type header matches the data you are sending, if it is raw json, you should use application/json rather then application/x-www-form-urlencoded. If you want to send a form using fetch API, you would need to either serialize to form to a URL encoded format, or use FormData, for example:
var fd = new FormData(document.getElementById('myForm'))
fetch('/actionName', {
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data;'
},
body: fd
})
Answer to #2:
Submitting HTML Forms will direct the browser to the forms action, so if I submit a form to /actionName, I will end up seeing the HTML that is returned by the server for that route. Using Fetch API to submit a form is a type of AJAX, which means that it is capable of communicating with the server without needing to load a new page.
With that in mind, you have a few options:
Use a regular form so that the desired default behavior happens
Manually redirect the user somewhere after the fetch promise resolves, something like:
fetch(/*..*/).then(data => {
console.log('Success:', data);
window.location.href = '/otherPage'
})
Render the response HTML without redirecting the user, something like:
fetch(/*..*/).then(data => {
console.log('Success:', data);
data.text().then(rawHTML => {
document.body.parentElement.innerHTML = rawHTML
})
})
My personal intuition would be to go with the first option, as it suits your requirements and is the simplest.

Getting None values for POST request (via the Axios library) sent to Python/Django

I am building a web app with Django/Python and trying to send data to a controller via a POST request using the Axios library (within Vue.js code).
The POST QueryDict seems to be empty and I can't see why that is happening:
changeCountry: function(e, id){
console.log("Let's change the country")
console.log(e.target.value) // is printing correctly
console.log(id) // also printing correctly
axios({
method: 'post',
url: '/template/country',
data: {
id: id,
country: e.target.value
},
headers: {
'X-CSRFToken': "{{csrf_token}}"
}
})
.then(function (response) {
alert(response.data); // this is returning what I expect
})
.catch(function (error) {
console.log(error);
})
},
The Python method looks like this:
def update_template_country(request):
pprint(request.POST) # prints an empty QueryDict
id = request.POST.get('id')
country = request.POST.get('country')
print(id, country) #prints None None
return HttpResponse("The country is changed") # this is being returned back to the client
The console.log messages at the top print what I expect and since there is no error I am assuming the CSRF header token is fine. Have I missed something obvious or misunderstood how this is working?
EDIT: looking at the Chrome Network tab, it seems the data is being 'POSTed' correctly:
It shows this:
{"id":"593ff2270098e6e8d3292b60","country":"US"}
and that's what I expect, so I suspect the issue is with Django. But I can't see what that might be.
Write your python POST request like this:
def update_template_country(request):
data = json.loads(request.body)
id = data["id"]
country = data["country"]
'''Any other function you want to perform'''
return HttpResponse(json.dumps({'message':'The country is changed'},status=200)
Basically the problem is with the format of POST request, Django is not able to parse it properly that's why when you print the POST request it return an empty dictionary.

Change query string parametesr of JavaScript requests

Is there a way to change the query string of JavaScript-induced requests? I want to add "&myParam=myValue" to any request sent by my HTML/JS application.
I don't think there's anything built in that lets you do that.
In my apps, I always have a central function XHR goes through so I have a single point to do things like this. If you don't have that or need to intercept calls from 3rd party libs:
You could wrap XMLHttpRequest.open to handle the XHR ones:
var originalOpen = XMLHttpRequest.open;
XMLHttpRequest.open = function() {
var args = Array.prototype.slice.call(arguments);
args[0] += (args[0].indexOf("?") == -1 ? "?" : "&") + "myParam=" + encodeURIComponent("myValue");
return originalOpen.apply(this, args);
};
...and then similar for fetch. But it seems brittle.
Alternately, you might look at using a cookie for the parameter, as the browser will add the cookie to the requests. (That assumes the requests are going to an origina you can add cookies for in your code.)
You could use partial application to lock in defaults when you declare your fetch function and essentially decorate the standard call that will merge your defaults and the passed params.
const fetchFactory = defaults => (url, data) => {
// make a copy of the defaults
const params = Object.assign({}, defaults)
// assign the passed in data with the defaults
params.body = JSON.stringify(Object.assign(params.body, data))
// call fetch with the params
return fetch(url, params)
}
// create a default for POST using the factory
const postFetch = fetchFactory({
method: 'post',
headers: {
'x-requested-with': 'fetch',
'Authorization': 'basic:' + btoa('a secret')
},
body: {
myParam: 'value'
}
})
// now you can call your function
postFetch('http://somewhere.com', {
one: 1,
two: 2
})
.then(respone => response.json())
It seems to me that you are asking how to set/edit URL parameters in http requests. Something quite similar has been asked here: here
If you are using XMLHttpRequest then the accepted answer in the link should work perfectly. The two key things the note are
the url parameters are simply a javascript object that you convert
into a JSON string. This happens through JSON.stringify({ myParam:
'hi'});
the question/answer linked are making post requests but you
may not want to make that request as well, I suggest doing some
research about which HTTP request method you want -
https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html

JS - Getting either text or JSON with Fetch API

I am moving over from jQuery AJAX requests to the new Fetch API (nothing against jQuery, I still have it in my site, but Fetch looks - according to Jake Archibald and David Walsh and also IMHO - to be the new way of sending async requests).
As such, with jQuery, I had the following function (more or less):
function ajaxCall(type, url, data) {
return $.ajax({
type: type,
url: url,
data: data,
})
.fail(function(xhr, status, errorThrown) {
// Do fail stuff
})
.always(function(xhr, status) {
// Do always stuff
});
}
// Later...
var myAjax = ajaxCall(myType, myUrl, myData);
myAjax.done(function(xhr) {
// Do done stuff
});
This way, I could have one function be called to handle any and all ajax requests I could ever need (for the most part at least...). Note that I do not declare a dataType, as I use jQuery's intelligent guess. This way my server can send me whatever response and I could handle it (probably a smarter way to do this would be to pass another parameter with the data type - in the case the "intelligent guess" goes wrong, but this was the way I set it up).
I am now trying to recreate the above with the new Fetch API. What I have so far currently looks like this:
function fetchCall(url, method, body) {
// This if statement is supposed to handle
// query selectors (which in GET requests go in the url)
// on GET requests - as opposed to POST req's which go in the body
if (method === 'GET') {
var data = body;
url = new URL(url, location.protocol + '//' + location.host + '/');
Object.keys(data).forEach(key => url.searchParams.append(key, data[key]));
body = undefined;
}
return fetch(url, {
method: method,
body: body
}).then(function(res) {
if (res.ok) return res;
throw new Error('Server error. Status code: ', res.status);
}).catch(function(err) {
console.log(err);
});
}
// Later...
var myFetch = fetchCall(myUrl, myMethod, myBody);
myFetch.then(function(res) {
console.log(res);
});
The problem I am running into is that if res.ok return res; does not state what type of response it is (i.e. res.json(), res.blob(), res.text(), etc.).
Thus, I am wondering how to set up a dynamic way of setting the type of response body. Is this even possible at the Fetch API's current state of development? Is it just that there is something I am not duplicating in MDN?
After messing around with this, I also realized I could make it always set to return res.text(); and the if the call is supposed to be JSON, use JSON.parse(response);, but I do want it to be dynamic. What if I end up wanting to return a blob()?
So, as far as the conversation has reached, there is a way to understand what type of content has been received, with two remarks:
Typically you have to always know and expect exact content type, and a universal solution is rather odd in case of fetching from a certain remote endpoint, and
The Content-Type header is what will tell you the type of content received, but the server may send a wrong header, which is very unusual to happen and therefore is negligible.
The Response object has header property that is (kind of) a Map, so you can use its get method to get a value by key.
The easiest and cleanest way to check if the returned value is a certain MIME type you expect is by using a regular expression:
// replace url with the actual API endpoint URL
fetch(url).then(response => {
const contentType = response.headers.get('Content-Type'); // -> "text/html; charset=utf-8"
if (/text\/html/i.test(contentType)) {
// do something when the Content-Type is text/html
} else if (/application\/json/.test(contentType)) {
// do something when the Content-Type is application/json
}
// and so on, for every Content-Type you need.
}).catch(error => {
// do something when error happens
});

Categories

Resources