I'm struggling a bit within a small project for fetching and creating (via POST) an entry, where I have on one side:
A GraphQL server (apollo)
A react app, using useQuery hook
A rest API, where the resolvers of the Apollo project is fetching data with async JS functions
I have the following obstacles:
I'm not able to post an entry for the rest API via GraphQl query or Mutation.
I have success in this post request:
POST https://technologytalents.io/space-cats/index.php/openapi/create_channel_entry
Accept: application/json
Content-Type: application/x-www-form-urlencoded
User-Agent: axios/0.21.1
channel_id=1&url_title=Blas&entry_date=12345678&title=Dooom&session_id=b288ea559b20c584a3a793685ceb20c240c26569
The success response of this is:
{entry_id: 2}
In my graphQL schema:
input entryIntput {
url_title: String
title: String
channel_id: Int
entry_date: Int
}
type postEntrySuccess {
entry_id: Int
}
type Mutation {
createEntry(input: entryIntput): postEntrySuccess
}
and in the resolvers:
Mutation: {
createEntry: async (_, entry) => await channelEntriesService.postEntry(entry)
}
my ChannelEntriesSerives looks like:
const axios = require('axios')
const authenticate = require('./authenticate')
class ChannelEntries {
constructor(options) {
this._options = options
}
async getEntries() {
const auth = await authenticate.auth()
const patch = {
...options,
url: `${options.url}/get_channel_entries?channel_id=1&where[status]=open&session_id=${auth.session_id}`
}
const response = await axios(patch)
return response.data
}
async postEntry(entry = { url_title: 'Blas', title: 'Dooom', entry_date: Date.now(), channel_id: 1 }) {
const auth = await authenticate.auth()
const patch = {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded'
},
url: `${this._options.url}/create_channel_entry?channel_id=${entry.channel_id}&url_title=${entry.url_title}&title=${entry.title}&entry_date=${entry.entry_date}_id=${auth.session_id}`
}
const response = await axios.request(patch)
return response.data
}
}
const options = {
method: 'GET',
url: 'https://technologytalents.io/space-cats/index.php/openapi',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
}
module.exports = instance = new ChannelEntries(options)
When I try to execute the mutation on the GraphQl studio:
mutation CreateEntry($createEntryInput: entryIntput) {
createEntry(input: $createEntryInput) {
entry_id
}
}
I've got an error:
{
"errors": [
{
"message": "Request failed with status code 400",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"createEntry"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"config": {
"url": "https://technologytalents.io/space-cats/index.php/openapi/create_channel_entry?channel_id=undefined&url_title=undefined&title=undefined&entry_date=undefined_id=b3c77d7c74b0cc10de61c90f8e1a34b30e454f7a",
"method": "post",
"headers": {
"Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded",
"User-Agent": "axios/0.21.1"
},
"transformRequest": [
null
],
"transformResponse": [
null
],
"timeout": 0,
"xsrfCookieName": "XSRF-TOKEN",
"xsrfHeaderName": "X-XSRF-TOKEN",
"maxContentLength": -1,
"maxBodyLength": -1
}
}
}
}
],
"data": {
"createEntry": null
}
}
What I'm doing wrong?
I found the reason for the error, and this is due to my rusty Axios basics. The config of an Axios request should have "data" property, so changing it to
const patch = {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded'
},
url: `${this._options.url}/create_channel_entry`,
data: `channel_id=${entry.channel_id}&url_title=${entry.url_title}&title=${entry.title}&entry_date=${entry.entry_date}&session_id=${auth.session_id}`
}
returns the correct response.
The other issue is just a correct mapping of the response with graphql schema.
Related
So I first integrated Amadeus for flight booking and everything went well but problem arrived when I started integrating hotel booking. If I use nodejs library of Amadeus, I get a response that my access token is invalid. This is my code of nestjs service and response.
async hotelSearch(data) {
try {
var amadeus = new Amadeus({
clientId: process.env.API_KEY,
clientSecret: process.env.API_SECRET
});
return await amadeus.shopping.hotelOffers.get(data)
} catch (error) {
return error;
}
}
And this is the response.result -
"result": {
"errors": [
{
"code": 38190,
"title": "Invalid access token",
"detail": "The access token provided in the Authorization header is invalid",
"status": 401
}
]
},
"parsed": true
},
"description": [
{
"code": 38190,
"title": "Invalid access token",
"detail": "The access token provided in the Authorization header is invalid",
"status": 401
}
],
"code": "AuthenticationError"
}
How can I get Invalid Access Token error when I am using the library for it?? Anyway, after facing this issue I decided to use axios instead but still got no success.
async getToken(): Promise<{access_token: string}> {
try {
const data = qs.stringify({
client_id: process.env.API_KEY,
client_secret: process.env.API_SECRET,
grant_type: 'client_credentials'
});
const config:AxiosRequestConfig = {
method: 'post',
maxBodyLength: Infinity,
url: 'https://test.api.amadeus.com/v1/security/oauth2/token',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: data
};
return await axios(config)
.then((response) => {
return((response.data));
})
.catch((error) => {
console.log(error);
});
} catch (error) {
return error;
}
}
async hotelSearch(data) {
try {
const tokenData=await this.getToken()
const refreshToken='Bearer '+ ( tokenData).access_token
console.log('token', refreshToken)
const config:AxiosRequestConfig = {
method: 'get',
maxBodyLength: Infinity,
url: 'https://test.api.amadeus.com/v1/reference-data/locations/hotels/by-city',
data: data,
headers: {'Authorization':refreshToken},
};
return await axios(config).then((response) => {
return(JSON.stringify(response.data));
})
.catch((error) => {
return(error);
});
// var amadeus = new Amadeus({
// clientId: process.env.API_KEY,
// clientSecret: process.env.API_SECRET
// });
// return await amadeus.shopping.hotelOffers.get(data)
} catch (error) {
return error;
}
}
And this is the response I got this time.
{
"message": "Request failed with status code 400",
"name": "Error",
"stack": "Error: Request failed with status code 400\n at createError (E:\\travel-portal\\travel-portal\\node_modules\\axios\\lib\\core\\createError.js:16:15)\n at settle (E:\\travel-portal\\travel-portal\\node_modules\\axios\\lib\\core\\settle.js:17:12)\n at IncomingMessage.handleStreamEnd (E:\\travel-portal\\travel-portal\\node_modules\\axios\\lib\\adapters\\http.js:322:11)\n at IncomingMessage.emit (node:events:525:35)\n at endReadableNT (node:internal/streams/readable:1359:12)\n at processTicksAndRejections (node:internal/process/task_queues:82:21)",
"config": {
"transitional": {
"silentJSONParsing": true,
"forcedJSONParsing": true,
"clarifyTimeoutError": false
},
"transformRequest": [
null
],
"transformResponse": [
null
],
"timeout": 0,
"xsrfCookieName": "XSRF-TOKEN",
"xsrfHeaderName": "X-XSRF-TOKEN",
"maxContentLength": -1,
"maxBodyLength": null,
"headers": {
"Accept": "application/json, text/plain, */*",
"Authorization": "Bearer CMHEjXBrpzE7YxF9O7GKygCtzCxO",
"Content-Type": "application/json",
"User-Agent": "axios/0.26.1",
"Content-Length": 117
},
"method": "get",
"url": "https://test.api.amadeus.com/v1/reference-data/locations/hotels/by-city",
"data": "{\"cityCode\":\"DEL\",\"radius\":\"5\",\"radiusUnit\":\"KM\",\"checkInDate\":\"2023-03-10\",\"checkOutDate\":\"2023-03-11\",\"adults\":\"2\"}"
},
"status": 400
}
I have cross-checked the payload. The bearer token is all good when I console it and even I checked the request with fiddler and there too header and data are getting passed. Any help to get this work through either of the method is really appreciated.
The amadeus.shopping.hotelOffers.get() endpoint has been decommissioned so you won't be able to use it. Install the latest version of the Node library and use the new Hotel Search endpoint as below:
var Amadeus = require(amadeus);
var amadeus = new Amadeus({
clientId: 'YOUR_API_KEY',
clientSecret: 'YOUR_API_SECRET'
});
// Get list of available offers in specific hotels by hotel ids
amadeus.shopping.hotelOffersSearch.get({
hotelIds: 'RTPAR001',
adults: '2'
}).then(function (response) {
console.log(response);
}).catch(function (response) {
console.error(response);
});
You can also check the migration guide for more details and how to use the new Hotel Search version.
The following Axios request made via a local server on Redux does not work, giving a CORS error:
axios.post('server_url', qs.stringify({
"username": "123",
"password": "123",
"repassword": "123"
}, {
headers: {
"Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded",
},
}))
But the request is made through Postman, and even the following python code:
import requests
from requests.structures import CaseInsensitiveDict
url = "server url"
headers = CaseInsensitiveDict()
headers["Accept"] = "application/json"
headers["Content-Type"] = "application/x-www-form-urlencoded"
data = "username='123'&password='123'&repassword='123'"
resp = requests.post(url, headers=headers, data=data)
print(resp.content)
There is no access to the server from the word at all. Maybe it's some kind of headings or something like that?
Error in console
Error in network
A message or any request through axios must return a promise because the request to the server is an asynchronous operation.
For example:
const url = "http://somedomen.org";
axios.post(
url,
{ name: "John", pass: 1, repass: 1 },
{
headers: {
Accept: "application/json",
"Content-Type": "application/x-www-form-urlencoded",
},
},
).then(res => {
return res.data
})
Also you can use async/await sintaxis
async function func() {
const url = "http://somedomen.org";
const response = await axios.post(
url,
{ name: "John", pass: 1, repass: 1 },
{
headers: {
Accept: "application/json",
"Content-Type": "application/x-www-form-urlencoded",
},
},
)
return response.data
}
Or to destructure the response variable
async function func() {
const { data, status, headers } = await axios.post(
//your condition...
);
return {
data,
status,
headers,
};
}
Until you have returned the promise of a result, the request cannot be completed.
I hope I helped you
I have an Elasticsearch instance that I can successfully query from Postman. I'm now trying to execute that same query from JavaScript via Axios. However, when I send my Axios request, I receive a 400 error. Currently, my request looks like this:
try {
let authorizationToken = getAuthToken();
let parameters = {
headers: {
"cache-control": "no-cache",
"Content-Type": "application/json",
"Authorization": "Basic " + authorizationToken
},
body: {
"size": 100,
"query": {
"bool": {
"filter": [
{ "range": {
"created_at": {"gte":"now-10m"}
} }
]
}
}
}
};
let url = 'https://my-cluster-address/my-index/_search?scroll=10m';
let res = await axios.post(url, parameters);
console.log('all good');
} catch (ex) {
console.log(ex);
}
What is wrong with my query? Why am I getting a 400 error?
This is a simple Post request using Axios inside Vue:
import axios from 'axios'
export default {
name: 'HelloWorld',
props: {
msg: String
},
mounted () {
const code = 'test'
const url = 'http://localhost:3456/'
axios.post(url, code, { headers: {'Content-type': 'application/x-www-form-urlencoded', } }).then(this.successHandler).catch(this.errorHandler)
},
methods: {
successHandler (res) {
console.log(res.data)
},
errorHandler (error) {
console.log(error)
}
}
}
The Get method works fine. But Post stay as "Pending" on Network tab. I can confirm that there is a Post method on my webservice and it return something (tested on Postman).
UPDATE
Sending code as a param:
axios(url, {
method: 'POST',
headers: {
'content-type': 'application/json',
},
params: {
code : 'test'
},
}).then(this.successHandler).catch(this.errorHandler)
WEBSERVICE
server.post('/', (req, res, next) => {
const { code } = req.params
const options = {
validate: 'soft',
cheerio: {},
juice: {},
beautify: {},
elements: []
}
heml(code, options).then(
({ html, metadata, errors }) => {
res.send({metadata, html, errors})
next()
})
})
I think there's issue with your axios request structure.
Try this:
const URL = *YOUR_URL*;
axios(URL, {
method: 'POST',
headers: {
'content-type': 'application/json',
},
data: *YOUR_PAYLOAD*,
})
.then(response => response.data)
.catch(error => {
throw error;
});
If you're sending a query param:
axios(URL, {
method: 'POST',
headers: {
'content-type': 'application/json',
},
params: {
code: 'your_string'
},
})
if it is path variable you can set your url:
const url = `http://localhost:3456/${code}`
Let me know if the issue still persists
I also was facing the same. Network call was pending all the time and Mitigated it by passing the response back from server.js(route file) e.g(res.json(1);) and it resolved the issue
I will try to describe my problem as the best I can. I have a method who (1)get all Grafana datasources via the API (2)create 2 JSON (3)post them to Grafana API.
The thing is sometimes one of my JSON is not finish when the code make the 3rd step so I got an error and the result is not what I want.
updateDashboard = Meteor.bindEnvironment(function() {
console.log("called updateDashboard()");
new Promise(Meteor.bindEnvironment(function(resolve) {
// get all the datasources of Grafana
HTTP.call("GET", 'http://localhost:3000/api/datasources', {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': APIKEY,
},
},
function(error, result) {
if (!error) {
allDataSources = result.data;
resolve(allDataSources);
} else {
console.error(error);
}
});
})).then(function(allDataSources) {
// create the dashboard
return new Promise(function(resolve) {
//ANCHOR
var dataJSON = {
//create the dashboard
"annotations": {
"list": []
},
"description": "Containers metrics",
"editable": true,
"gnetId": null,
"graphTooltip": 1,
"hideControls": false,
"id": null,
"links": [],
"refresh": "1s",
//create the lines
"rows": _.map(allDataSources, function(ds, index) {
return newGraphOverview(ds, index);
}),
//dashboard things
"schemaVersion": 14,
"style": "dark",
"tags": [
"docker"
],
"time": {
"from": "now-15m",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"1s",
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
]
},
"timezone": "browser",
"title": "Docker Containers _custom_from_js",
"version": 1
}
dataJSONDetails = newGraphDetails(allDataSources);
resolve(dataJSON);
});
}).then(Meteor.bindEnvironment(function(dataJSON) {
// send the dashboard
HTTP.call("POST", "http://localhost:3000/api/dashboards/db", {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': APIKEY,
},
data: {
dashboard: dataJSON,
overwrite: true
}
},
function(error, result) {
if (!error) {
console.log("result post " + dataJSON.title + " ----------------------------------")
console.log(result);
} else {
//HERE I WANT TO DO IF ERROR GO TO ANCHOR
console.log("error post " + dataJSON.title + " ----------------------------------")
console.error(error);
}
});
//send the dashboard for details view
HTTP.call("POST", "http://localhost:3000/api/dashboards/db", {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': APIKEY,
},
data: {
dashboard: dataJSONDetails,
overwrite: true
}
},
function(error, result) {
if (!error) {
console.log("result post " + dataJSONDetails.title + " ----------------------------------")
console.log(result);
} else {
//HERE I WANT TO DO IF ERROR GO TO ANCHOR
console.log("error post " + dataJSONDetails.title + " ----------------------------------")
console.error(error);
}
});
}));
});
I know the code snipped doesn't work but it was easier for me to make it readable.
So someone could help me to make a thing like "if error try to create again" ? I have seen Meteor retries but it don't think it's what I need
You shouldn't use promises or callbacks. Write normal, synchronous-looking code as you've seen in Meteor examples.
var datasources = null;
try {
var request1 = HTTP.call("GET", 'http://localhost:3000/api/datasources', {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': APIKEY,
}
});
// From http://docs.meteor.com/api/http.html#HTTP-call
datasources = request.data;
} catch (e) {
console.error(e);
return;
}
// Do all the other steps you keep wanting to do...
Repeat a similar statement for your other HTTP calls. Generally, you will not be throwing errors unless localhost is unreachable, in which case everything is unreachable. So don't bother with try-catch. Let the exception be thrown and handled by the client (the caller of the method).
You shouldn't generally have to use Meteor.bindEnvironment.