I am just calling the api get using reactJS and axios.
The api call is going but I'm unable to get the response from the server.
Here is my code:
getProjectdetails(details) {
alert("coming")
details.map(function(project, i) {
var projectId = project.projectId
axios.get('http://workpresso.rankworld.io/api/v1/project?query={"projectId":"' + projectId + '"}', {
params: {},
headers: {
"x-access-token": sessionStorage.token
},
})
.then(function(response1) {}.bind(this))
.catch(function(error) {
console.log(error);
});
})
}
You'll need to return something from the then().
If you want to avoid binding 'this' you can use an arrow function (if es6 is available, assuming you're using Node, it probably is).
Lastly, a map function transforms the array elements, so you need to return something in that function too.
Related
I need to pass an id obtained from an api call to invoke another api call, cant get it to work!
can anyone help?
The second api which will return and image call does not work and is greyed out in vs code
if anyone can help with an example, i would be greatful
currentResult: any;
getData(){
this.showLoading();
const headers = {
"x-api-key":'',
'Content-Type': 'application/json',
"Access-Control-Allow-Origin":"*",
"x-requested-with": "xmlhttprequest",
/* 'Authorization': `Bearer ${this.sygicBearerToken}` */
}
return this.http.get(
this.ProxyUrl1+'https://api.sygictravelapi.com/1.2/en/places/list?parents=city:2&categories=discovering&limit=10', { headers: headers },
)
.pipe(tap (value => {
this.loadingController.dismiss();
console.log(value);
}))
this.http.get(
this.ProxyUrl1+'https://api.sygictravelapi.com/1.2/en/places/{id}/media',{ headers: headers},)
.pipe(tap (value => {
this.loadingController.dismiss();
console.log(value);
})
);
}
Since you have a return statement with the first this.http.get, anything after the return statement will not run, so it is grayed out.
First: the second API call is greyed out because its written after a return call.
in order to call an additional API call using the result of the first call,
you can use RXJS switchMap
this will help you get a sequential requests, one after the other.
for exmaple example:
get data() {
return this.http.get('http://firstAPI').pipe(
switchMap(id => this.http.get(`http://secondAPI/${id}`))
);
}
the first API call results "id" is passed to the second http call.
read more: RXJS switchMap
I am using mithril.js in frontend application and backend application is running on ipv6 environment.
Calling post ajax request to backend using mithril.js.
async post(url, body = {}) {
return new Promise((resolve, reject) => {
m.request({method: 'POST', url, body}).then((data) => {
resolve(data);
}).catch((err) => {
reject(err.message);
});
});
}
Backed url is like this: http://[340f:c0e0:1d1:5gc0:g4fs:2::]:22923/backend.
But getting this error Template parameter names *must* be separated while calling backend api.
Explanation of the error
Based on the documentation of m.request(), you can specify dynamic URLs:
Request URLs may contain interpolations:
m.request({
method: "GET",
url: "/api/v1/users/:id",
params: {id: 123},
}).then(function(user) {
console.log(user.id) // logs 123
})
In the code above, :id is populated with the data from the params object, and the request becomes GET /api/v1/users/123.
Interpolations are ignored if no matching data exists in the params property.
m.request({
method: "GET",
url: "/api/v1/users/foo:bar",
params: {id: 123},
})
In the code above, the request becomes GET /api/v1/users/foo:bar?id=123
Since your backend URL contains colons, it's interpreted as being a dynamic URL.
According to the documentation of m.buildPathname(), m.request() uses m.buildPathname() internally to process dynamic URLs.
The beginning of m.buildPathname() contains the following check regarding parameters of a path template (dynamic URL = path template populated with path parameters):
if ((/:([^\/\.-]+)(\.{3})?:/).test(template)) {
throw new SyntaxError("Template parameter names *must* be separated")
}
(Source: https://github.com/MithrilJS/mithril.js/blob/v2.0.4/mithril.js#L1288-L1292)
And, again, since your backend URL contains colons, this is where you are getting the error. (You can verify this by trying to run m.buildPathname('http://[340f:c0e0:1d1:5gc0:g4fs:2::]:22923/backend') – you'll get the same error.)
How to fix it
Since you can't get away from that regex check at the beginning of m.buildPathname(), your best bet might be to use a dynamic URL. Like so:
m.buildPathname(':url...', { url: 'http://[340f:c0e0:1d1:5gc0:g4fs:2::]:22923/backend' })
// => http://[340f:c0e0:1d1:5gc0:g4fs:2::]:22923/backend
Or when applied to your code:
async post(url, body = {}) {
return new Promise((resolve, reject) => {
m.request({method: 'POST', url: ':url...', body, params: {url}}).then((data) => {
resolve(data);
}).catch((err) => {
reject(err.message);
});
});
}
Or alternatively you can specify the (dynamic) URL as the first argument of m.request():
async post(url, body = {}) {
return new Promise((resolve, reject) => {
m.request(':url...', {method: 'POST', body, params: {url}}).then((data) => {
resolve(data);
}).catch((err) => {
reject(err.message);
});
});
}
Notice that there are three dots after the path parameter :url. Otherwise its value would be escaped/encoded. This is mentioned in the documentation of path handling. Example:
m.buildPathname(':url', { url: 'http://[340f:c0e0:1d1:5gc0:g4fs:2::]:22923/backend' })
// => http%3A%2F%2F%5B340f%3Ac0e0%3A1d1%3A5gc0%3Ag4fs%3A2%3A%3A%5D%3A22923%2Fbackend
Handling URL parameters
As mentioned in the other answer, if the URL contains parameters, the question mark will be duplicated:
m.buildPathname(':url...', { url: 'https://example.com/foo?bar=baz' })
// => https://example.com/foo??bar=baz
// ^^
One way to solve that would be to include the parameters in the path template:
const url = 'https://example.com/foo?bar=baz'
const [baseUrl, params] = url.split('?')
const template = ':baseUrl...' + (params ? `?${params}` : '')
m.buildPathname(template, { baseUrl })
// => https://example.com/foo?bar=baz
However, if there are colons in the URL parameters, there's a possibility that you'll get the same error as originally ("Template parameter names *must* be separated").
There might be a way to solve this, but the previous code sample is already quite complex for this relatively simple use case. Which leads us to:
Alternative solution: don't use m.request()
m.request() is just "a thin wrapper around XMLHttpRequest." It "returns a promise and triggers a redraw upon completion of its promise chain."
If m.request() is difficult to work with due to using IPv6 URLs (or for other reasons), it can be easier to use something else for doing XHR requests. You could for example use fetch() – just remember to call m.redraw() at the end (m.request() does this automatically).
Sure, m.request() does more than just calls m.redraw() at the end (see the docs), but it's also okay to use something else.
Thanks mts knn for the reply. We have implemented your solution however we faced below issues.
Question mark is passing two times in http url of api. Please find attached below screenshot.
In order to fix this problem, please find the updated code below
async post(url, body = {}) {
var queryIndex = url.indexOf('?');
var httpPart = url.slice(0,queryIndex);
var finalUrl = url.replace(httpPart,":url...");
return new Promise((resolve, reject) => {
m.request({method: 'POST', url: finalUrl, body, params: {url: httpPart}}).then((data) => {
resolve(data);
}).catch((err) => {
reject(err.message);
});
});
}
You can also provide efficient solution If any.
I'm finding a solution to async computed method in Components:
Currently, my component is:
<div class="msg_content">
{{messages}}
</div>
<script>
export default {
computed: {
messages: {
get () {
return api.get(`/users/${this.value.username}/message/`, {'headers': { 'Authorization': 'JWT ...' }})
.then(response => response.data)
}
}
},
}
</script>
Result:
{}
How to rewrite it in Promise mode? Because I think we can async computed by writing into Promise mode.
Computed properties are basically functions that cache their results so that they don't have to be calculated every time they are needed. They updated automatically based on the reactive values they use.
Your computed does not use any reactive items, so there's no point in its being a computed. It returns a Promise now (assuming the usual behavior of then).
It's not entirely clear what you want to achieve, but my best guess is that you should create a data item to hold response.data, and make your api.get call in the created hook. Something like
export default {
data() {
return {
//...
messages: []
};
},
created() {
api.get(`/users/${this.value.username}/message/`, {
'headers': {
'Authorization': 'JWT ...'
}
})
.then(response => this.messages = response.data);
}
}
es7 makes doing this quite trivial by using async and await in conjunction with axios' returned promise. You'll need the vue-async-computed package.
export default {
asyncComputed: {
async myResolvedValue() {
return await api.get(`/users/${this.value.username}/message/`, {'headers': { 'Authorization': 'JWT ...' }})
.then(response => response.data)
}
}
}
I bumped on a similar case where I need to re-run the computed function to fetch from a server every time a data or a props changes.
Without installing any extra package (vue-async-computed or vue3-async-computed as pointed by other answers), you can force a data to reload by creating a "virtual" computed method.
Lets say you want to fetch data from the server every time the user types their username, and depending on what was typed, you want to show a given message from the server.
From the example below, username and messages in this case are both reactive data, but there is no direct connection between them, so lets create a computed that depends on username by returning its value, which will force it to be called every time username is changed. Now you just need to call a function that can be async and will update messages after fetching from the server.
In the example below, I use ":dummy" just to force a call to my computed function.
<template>
<input v-model="username">
<div class="msg_content" :dummy="force_react">
{{messages}}
</div>
</template>
<script>
export default {
data: function () {
return {
messages: "",
username: "",
};
},
computed: {
force_react: function() {
this.get(); // called every time that this.username updates
return this.username; // becase its result depends on username
}
},
methods: {
async get() { // get's called every time that this.username updates
console.log("Got called");
let response = await api.get(`/users/${this.username}/message/`, {'headers': { 'Authorization': 'JWT ...' }});
this.messages = response.data;
}
},
}
</script>
You can see a working example here in Vue SFC playground
Why not using a watcher? Vue Documentation
You can use async function in the callback of the watcher.
I am having trouble adding a header to a request-promise (npm) request using a variable (headersTest). If I hard-code the value in options, I receive the expected API response. If I create the header in a variable and add that to options, the API rejects the request (the header key is not recognised). When I log the headersTest variable it would appear identical to the hard-coded value, but doesn't work.
Here is the relevant code section:
const headersTest = "'x-custom-date':'Fri, 27 Oct 2017 09:45:18 EST'";
console.log(headersTest);
const options = {
method: "GET",
uri: 'http://' + whatEvz,
qs: {
queryString
},
headers: {
//'x-custom-date':'Fri, 27 Oct 2017 09:45:18 EST'
headersTest
},
json: true
};
rp(options)
.then(function(results){
res.send(results);
})
.catch(function (err) {
res.send("Shite! That didn't work! " + err.message);
});
It seems I'm missing something in my understanding as to how variables are interpreted within options. Any guidance would be much appreciated.
I solved this by using object properties, rather than trying to pass on object into options.headers. I actually had an array of headers and used lodash to add the headers like so:
_.each(myHeaders, function (val, key) {
_.each(val, function (val, key) {
options.headers[key] = val;
});
})
I have functions like the getData function below.
I understand that $http returns a promise. In my current set up I am using $q so that I can do some processing of the results and then return another promise:
var getData = function (controller) {
var defer = $q.defer();
$http.get('/api/' + controller + '/GetData')
.success(function (data) {
var dataPlus = [{ id: 0, name: '*' }].concat(data);
defer.resolve({
data: data,
dataPlus: dataPlus
});
})
.error(function (error) {
defer.reject({
data: error
});
});
return defer.promise;
}
Is there any way that I can do this without needing to use the AngularJS $q (or any other $q implementation) or is the code above the only way to do this? Note that I am not looking for a solution where I pass in an onSuccess and an onError to the getData as parameters.
Thanks
As you say $http.get already returns a promise. One of the best things about promises is that they compose nicely. Adding more success, then, or done simply runs them sequentially.
var getData = function (controller) {
return $http.get('/api/' + controller + '/GetData')
.success(function (data) {
var dataPlus = [{ id: 0, name: '*' }].concat(data);
return {
data: data,
dataPlus: dataPlus
};
})
.error(function (error) {
return {
data: error
};
});
}
This means that using getData(controller).then(function (obj) { console.log(obj) });, will print the object returned by your success handler.
If you want you can keep composing it, adding more functionality. Lets say you want to always log results and errors.
var loggingGetData = getData(controller).then(function (obj) {
console.log(obj);
return obj;
}, function (err) {
console.log(err);
return err;
});
You can then use your logging getData like so:
loggingGetData(controller).then(function (obj) {
var data = obj.data;
var dataPlus = obj.dataPlus;
// do stuff with the results from the http request
});
If the $http request resolves, the result will first go through your initial success handler, and then through the logging one, finally ending up in the final function here.
If it does not resolve, it will go through the initial error handler to the error handler defined by loggingGetData and print to console. You could keep adding promises this way and build really advanced stuff.
You can try:
Using an interceptor which provides the response method. However I don't like it, as it moves the code handling the response to another place, making it harder to understand and debug the code.
Using $q would be the best in that case IMO.
Another (better ?) option is locally augmented transformResponse transformer for the $http.get() call, and just return the $http promise.