I found that React Native does not give HTTP_USER_AGENT value to Django Graphene. On Garaphene, I receive the header by:
def resolve(cls, root, info, **kwargs):
info.context.META['HTTP_USER_AGENT']
It works when I send a query through a browser. However, the HTTP_USER_AGENT only has "okhttp/3.6.0" value when I send a query through my React Native app. So I tried to change the HTTP_USER_AGENT value by setting headers of axios.
onSubmit = async () => {
if (!this.state.isSubmitting) {
this.setState({isSubmitting: true});
await axios({
url: 'http://192.168.0.6:8000/graphql/',
method: 'post',
headers: {
HTTP_USER_AGENT: 'CCC'
},
data: {
query: `
It does not work. HTTP_USER_AGENT does not change and only shows "okhttp/3.6.0". I tried other custom headers and found that they do not work either. I cannot just set my own custom-named-header. Why is this the case? The only header I was available to change was AUTHORIZATION. Django Graphene received the header value when I set
await axios({
url: 'http://192.168.0.6:8000/graphql/',
method: 'post',
headers: {
AUTHORIZATION: 'JWT CCC'
},
and the value was available from
info.context.META['HTTP_AUTHORIZATION']
I had no idea if my assumptions were wrong.
Solved it luckily.
You have to set 'USER-AGENT' header on your client side(React Native)
await axios({
url: 'http://192.168.0.6:8000/graphql/',
method: 'post',
timeout: 5000,
headers: {
'USER-AGENT': await Constants.getWebViewUserAgentAsync(),
},
And receive the value as HTTP_USER_AGENT on your server side (Django Graphene)
ua_string = info.context.META['HTTP_USER_AGENT']
user_agent = parse(ua_string)
I do not know why their names are different (it took me half a day) but this is how it is.
Related
Been working on a script to execute in Google Apps Scripts to pull some data from an external API and post that information into a Google Sheet. I have a script that works client side (running from the console in chrome) that is able to leverage promises and return HTTP responses correctly to execute more code on.
However, in Apps Scripts I cannot figure out how to return a native JSON object representation from the API. In normal JS, I would return the .json() method of the response and would be good to go. Since Apps Script is essentially executing a .gs file they have different classes and methods that are not specific to JS. This help doc https://developers.google.com/apps-script/guides/services/external provides the below example for working with JSON
var json = response.getContentText();
var data = JSON.parse(json);
Logger.log(data.title);
If I try to leverage that getContextText() method by itself I get a TypeError: Cannot read property '0' of undefined error. If I combine it with JSON.parse like return JSON.parse(response.getContentText()); I get a SyntaxError: Unexpected token M in JSON at position 0. Am I missing something wildly obvious? Any help would be greatly appreciated! Additionally, happy to provide more specifics from my script as well.
EDIT
Below is a snippet of script that works client side.
async function postData(url = '', data = {}) {
const response = await fetch(url, {
method: 'POST',
headers: {
'Authorization': "Basic" + ' ' + gongCreds,
'Accept': "*/*",
'Connection': "keep-alive",
'Content-Type': "application/json"
},
body: gongRequestBody,
});
return response.json();
}
Here is the returned promise object data that I want to leverage for future execution
[[PromiseResult]]: Object
records: {totalRecords: 1, currentPageSize: 1, currentPageNumber: 0}
requestId: "6w83fpcbo5ka2evast7"
usersDetailedActivities: Array(1)
0:
userDailyActivityStats: Array(1)
0:
callsAsHost: []
callsAttended: (6) ["432806286570218902", "1825323793748204011", "3193437184015561879", "4172384470445855263", "5128172192322468435", "5808052479141116583"]
callsCommentsGiven: []
callsCommentsReceived: []
callsGaveFeedback: []
callsMarkedAsFeedbackGiven: []
callsMarkedAsFeedbackReceived: []
callsReceivedFeedback: []
callsRequestedFeedback: []
callsScorecardsFilled: []
callsScorecardsReceived: []
callsSharedExternally: []
callsSharedInternally: []
fromDate: "2021-01-20T05:00:00Z"
othersCallsListenedTo: (2) ["3401282086024720458", "8098199458721511977"]
When your following Javascript is converted to Google Apps Script,
async function postData(url = '', data = {}) {
const response = await fetch(url, {
method: 'POST',
headers: {
'Authorization': "Basic" + ' ' + gongCreds,
'Accept': "*/*",
'Connection': "keep-alive",
'Content-Type': "application/json"
},
body: gongRequestBody,
});
return response.json();
}
it becomes as follows.
const response = UrlFetchApp.fetch(url, {
method: 'POST',
headers: {
'Authorization': "Basic" + ' ' + gongCreds,
'Accept': "*/*",
'Connection': "keep-alive",
},
muteHttpExceptions: true,
contentType: "application/json",
payload: gongRequestBody,
});
console.log(response.getContentText())
// I think that if above request works and the returned value is the correct value you expected, you can use console.log(JSON.parse(response.getContentText()).title)
But, there are several important points.
From your script, I cannot see the value of gongRequestBody. When 'Content-Type': "application/json" is used, JSON.stringify() is required to be used for the JSON object. So if gongRequestBody is the JSON object, please convert it to the string using JSON.stringify().
From your question, I cannot see your script for requesting to the URL. So I cannot point out the modification points of your script even when your script has the modification points.
I asked to show the sample value of response.getContentText() in your Google Apps Script. But unfortunately, I cannot find the sample value of it. So when you use console.log(JSON.parse(response.getContentText()).title) to the above sample script of Google Apps Script and an error occurs, can you provide the sample value of console.log(response.getContentText())? By this, I would like to confirm it.
Note:
In this sample script, it supposes that your Javascript works and the variables of gongCreds, gongCreds and gongRequestBody are the valid values for requesting to your URL. Please be careful this. So when above sample script didn't work as you expected, can you provide the sample value of console.log(response.getContentText())? By this, I would like to confirm your situation.
Reference:
fetch(url, params)
Im use to the traditional REST API:
axios({
headers: {
Accept: 'application/json',
},
method: 'GET',
url: 'http://localhost:4000/GetUsers',
}).then(function(response) {
// Array of objects containing users
console.log('done', response.data);
});
In graphql:
axios({
headers: {
Accept: 'application/json',
},
method: 'post',
url: 'http://localhost:4000/graphql',
data: {
query: `{ users { Email }}`,
},
}).then(function(response) {
// notice the doubble data call
console.log('done', response.data.data.users);
});
In graphql im forced to call .data.data.users to get my data and im wondering is there
a way to get it through response.data as in a REST API call so that I dont need the call to .data and .users ?
Not, it's standard behaviour - response format defined in specs.
not needed as usually [react] components works on data prop or useQuery (apollo) returns data
response can contain error property beside to data (sibling)
You can always assign shortcut
const data=response.data.data;
... and later use only data.users or
const users=response.data.data.users;
... if you really need this.
When I'm sending a POST request to my backend express server, the req.body contains only the key part where the entire body is the key and the value part is empty
This is the frontend fetch request
let data = {
videoUrl: "dummy text"
}
fetch("/api/getinfo", {
method:"POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"
},
body: JSON.stringify(data)
})
This is how I handle it in backend (NOTE: I'm using body-parser)
app.post("/api/getinfo", (req,res) => {
console.log(req.body);
}
I expect the output to be
'{ "videoUrl":"dummy text" }'
But what I get is
{ '{"videoUrl":"dummy text"}': '' }
The entire requests body is the key, and the value is empty.
What am I doing wrong?
You are using the wrong Content-Type to send json
Try
"Content-Type": "application/json;charset=UTF-8"
I noticed an issue in your header;
fetch("/api/getinfo", {
method:"POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8" //this very line
},
I guess what you meant is
fetch("/api/getinfo", {
method:"POST",
headers: {
'Content-type': 'application/json; charset=utf-8'
},
Note: Your header denotes what the content is encoded in. It is not necessarily possible to deduce the type of the content from the content itself, i.e. you can't necessarily just look at the content and know what to do with it. So you need to be sure of what you're writing in your header else you will end up with an error.
I will suggest you get to read more about What does “Content-type: application/json; charset=utf-8” really mean?
The problem is that you are stringifying the data:
body: JSON.stringify(data)
should be
body: data
That should fix it
This is my sample request:
var header = new Headers({
'Platform-Version': 1,
'App-Version': 1,
'Platform': 'FrontEnd'
});
var myInit = {
method : 'GET',
headers: header,
mode : 'no-cors',
cache : 'default'
}
fetch('http://localhost:3000/api/front_end/v1/login', myInit)
.then(res => {
console.log(res.text())
})
When I debug, I see that this request is sent successfully to server, but server hasn't received header params (in this case is Platform-Version, App-Version and Platform). Please tell me which part do I config wrong.
thanks
You are using it correctly, but you have to tell your backend service to allow custom headers (X-). For example, in PHP:
header("Access-Control-Allow-Headers: X-Requested-With");
Also, your custom headers should be prefixed with X-. So you should have:
'X-Platform-Version': '1'
And one last thing, your mode needs to be cors.
You can see that standard headers are being sent with the following code. take a look at the network tab to see the standard request headers.
var header = new Headers();
// Your server does not currently allow this one
header.append('X-Platform-Version', 1);
// You will see this one in the log in the network tab
header.append("Content-Type", "text/plain");
var myInit = {
method: 'GET',
headers: header,
mode: 'cors',
cache: 'default'
}
fetch('http://localhost:3000/api/front_end/v1/login', myInit)
.then(res => {
console.log(res.text())
});
The instagram "server side workflow" for authenticating a user and giving them a session access token doesn't work. First part works in that I can get a code back from here:
https://api.instagram.com/oauth/authorize/?client_id=CLIENT-ID&redirect_uri=REDIRECT-URI&response_type=code
However, when posting this code to
https://api.instagram.com/oauth/access_token
in order to obtain the access token, it just response with "YOU MUST PROVIDE A CLIENT ID", even though I have provided this as part of the form data - the same client id I used to get the code in the first place!
Here is the code I am using:
getIgToken: function (igCode) {
let data = {
client_id: config.imported.instagram.client_id,
client_secret: config.imported.instagram.client_secret,
grant_type: 'authorization_code',
redirect_uri: 'http://localhost:5000/app/scrape',
code: igCode
}
return $http({
method: 'POST',
url: 'https://api.instagram.com/oauth/access_token',
data: data,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
})
}
Apparently others have reported problems with posting the data as json, which have then been resolved by using "application/x-www-form-urlencoded" - however this doesn't seem to work either now.
Here is the exact error message returned:
{error_type: "OAuthException", code: 400, error_message: "You must provide a
client_id"}
code:400
error_message:"You must provide a client_id"
error_type:"OAuthException"
grant_type should be 'authorization_code'
convert the data object to json format , try
data: JSON.stringify(data),
your code will look like this
getIgToken: function (igCode) {
let data = {
client_id: config.imported.instagram.client_id,
client_secret: config.imported.instagram.client_secret,
grant_type: 'authorisation_code',
redirect_uri: 'http://localhost:5000/app/scrape',
code: igCode
}
var jsonData= JSON.stringify(data)
return $http({
method: 'POST',
url: 'https://api.instagram.com/oauth/access_token',
data: jsonData,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
})
}