Graphene Django "Must provide query string" - django

I have setup a Graphene server using Django. When I run my queries through GraphiQL (the web client), everything works fine. However, when I run from anywhere else, I get the error: "Must provide query string."
I did some troubleshooting. GraphiQL sends POST data to the GraphQL server with Content-Type: application/json. Here is the body of the request that I copied from Chrome network tab for GraphiQL:
{"query":"query PartnersQuery {\n partners{\n name\n url\n logo\n }\n}","variables":"null","operationName":"PartnersQuery"}
When I copy it to Postman with Content-Type: application/json, I get the following response:
{
"errors": [
{
"message": "Must provide query string."
}
]
}
What can be the cause of this problem? I have not done anything crazy with the schema. Just followed the tutorials from graphene's docs. What else can cause an issue like this?

This error is raised when parse_body is unable to parse the incoming data. I'd start there by looking at the data passed into this method and ensuring it's of the correct type.
For example, the multipart/form-data section naively returns request.POST, which may need to be overwritten to handle, for example, the request that apollo-upload-client sends for file upload handling.
In our case we created a view to both require a login and to support the apollo-upload-client use case and it works fine.

Here's how I was able to get a successful response from Postman using a graphene Django backend with a simple mutation:
Set method to POST
Add the URL to your graphQL endpoint, e.g. http://localhost:8000/api/
Add one header -- key: "Content-Type" , value: "application/json"
Set the body to "raw"
Paste in your query into the body window, e.g. {"query":"{myModels {id}}","variables":"null","operationName":null}
This sounds pretty much like what you did, so you must be close.

I faced the same problem when I try to used graphQl query using POSTMAN,
In POSTMAN send data in row with json type.
You have to make json data grapQl query and mutations data like this
Query Command:
{"query":"{user(id:902){id,username,DOB}}"}
Mutations Command:
{ "query": "mutation {createMutations(reviewer:36, comments:\"hello\",loan: 1659, approved: true ){id}}" }
#commnent: String Type
#data_id:Int Type
#approved:Boolean Type

Checkout sample apps and see how they do things,
e.g.
https://github.com/mjtamlyn/graphene-tutorial
they do the following:
from django.views.decorators.csrf import csrf_exempt
from graphene_django.views import GraphQLView
url(r'^explore', GraphQLView.as_view(graphiql=True)),
url(r'^graphql', csrf_exempt(GraphQLView.as_view())),

I encountered exactly the same problem as the original poster, Gasim. Studying the code in 'graphiql.html' I see that they're converting the query string, that goes into the body, into the query parameter in the URL. Thus you end up with this URL being sent via Postman:
http://127.0.0.1:8000/graphql?query=%7B%0A%20%20allCategories%20%7B%0A%20%20%20%20edges%20%7B%0A%20%20%20%20%20%20node%20%7B%0A%20%20%20%20%20%20%20%20name%0A%20%20%20%20%20%20%20%20ingredients%20%7B%0A%20%20%20%20%20%20%20%20%20%20edges%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20node%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20name%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D%0A
It seems nonsensical to me to duplicate precisely what's in the body in the query string in the URL too but that appears to be the only way to get the Graphene server to return a valid response.
Surely this is a bug/shortcoming that will be fixed?
Robert

Enable graphine on django
url(r'^graphql', csrf_exempt(GraphQLView.as_view(graphiql=settings.DEBUG))),
Execute some query and see it is working
On Chrome browser, go to graphiQL endpoint: http://localhost:8000/graphql? open "Developer Tools" in browser and go to "Network" tab.
Execute your query again. Now it appears on list of requests. Now right mouse click on it and copy it "copy as CURL". Now you can strait copy paste it to linux terminal with curl installed. Or like in your case you can try to deduct what is what there, and try to reuse it in your IDE like client like Insomnia or Postman. For instance you may discover that authorisation that works with session on graphiQL enpoint, is not what you want at the end...
curl 'http://localhost:8000/graphql?' -H 'Origin: http://localhost:8000' -H 'Accept-Encoding: gzip, deflate, br' -H 'Accept-Language: en-US,en;q=0.9,pl;q=0.8,de;q=0.7' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36' -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'Cookie: _ga=GA1.1.1578283610.1528109563; _gid=GA1.1.920024733.1541592686; csrftoken=EGBeegFoyMVl8j1fQbuEBG587nOFP2INwv7Q0Ee6HeHHmsLOPUwRonzun9Y6pOjV; sessionid=4u9vngcnmjh927a9avpssvc4oq9qyqoe' -H 'Connection: keep-alive' -H 'X-CSRFToken: EGBeegFoyMVl8j1fQbuEBG587nOFP2INwv7Q0Ee6HeHHmsLOPUwRonzun9Y6pOjV' --data-binary '{"query":"{\n allStatistics(projectId: 413581, first:25) {\n pageInfo {\n startCursor\n endCursor\n hasPreviousPage\n hasNextPage\n }\n edges {\n cursor\n node {\n id\n clickouts\n commissionCanc\n commissionConf\n commissionLeads\n commissionOpen\n eventDate\n extractTstamp\n hash\n leads\n pageviews\n projectId\n transactionsCanc\n transactionsConf\n transactionsOpen\n }\n }\n }\n}\n","variables":null,"operationName":null}' --compressed

The problem in my code was that I had the URL improperly setup for graphQL. I had the following:
url(r'^graphql/', GraphQLView.as_view())
The forward slash was a huge difference. Removing it fixed the problem. The proper way to do it would be:
url(r'^graphql', GraphQLView.as_view())

Related

Failed to initialize a glossary. 404 Glossary not found - While running the Google translation

I'm trying to use Google translation with glossary. The Glossary is created, I can see it in activity dashboard:
But when I try to get_glossary (just a simple script from google) server responce.
name = client.glossary_path( project_id, "us-central1", glossary_id)
print(name)
response = client.get_glossary(name)
-------- output:
NotFound: 404 Glossary not found.
Trying use list_glossaries, but it return noting. Can't figured out where mistake is?
Based from your screenshot you were able to create the glossary. Another way to check glossary if it is existing is to use the Long Running Operation ID (Underlined in Red.)
Send a request to GET the status of the operation. Refer to this document for a better explanation on using long running operations.
curl -X GET \
-H "Authorization: Bearer "$(gcloud auth application-default print-access-token) \
https://translation.googleapis.com/v3/projects/your-project-id-here/locations/us-central1/operations/your-opperation-id-here
It will return this response that contains the status of your operation. Compare the returned "name" versus the returned "name" in your code name = client.glossary_path( project_id, "us-central1", glossary_id) and check if there are just wrong parameters.
Also just a note, the proper way to use client.get_glossary is to pass a request object.
name = client.glossary_path( project_id, "us-central1", glossary_id)
print(name) # projects/your-project-id/locations/us-central1/glossaries/your-glossary-id
request = {"name" : name}
response = client.get_glossary(request) # pass the request object

How do I format the response body of a request to the predict endpoint of a Google Cloud Platform API request

I'm working off of the tutorial that is premade on GCP when working with the AI Platform component. In short it involves using Kubeflow and Tensorflow Extended to build and deploy a completed ML model for predicting who will be a big tipper off of the Chicago Taxi dataset. Everything has gone well even up to deploying and hitting the predict endpoint of my model however, I can't seem to get the request body correct or find good documentation on how to know what the request body should look. Below I have:
The model from SchemaGen in Kubeflow
The header from the data.csv I used for training and the row I extracted from it in which I want to test
The curl Im using in postman and it's error.
Of note, The error talks about expected a float and getting a string but the model says it should be a float. I'd like to know if anyone can help me determine the datatypes,ordering of the requestBody so I can get a successful prediction back. Thanks in advance!
SchemaGen from Kubeflow:
copy of csv header and data row:
pickup_community_area,fare,trip_start_month,trip_start_hour,trip_start_day,trip_start_timestamp,pickup_latitude,pickup_longitude,dropoff_latitude,dropoff_longitude,trip_miles,pickup_census_tract,dropoff_census_tract,payment_type,company,trip_seconds,dropoff_community_area,tips,big_tipper
60,27.05,10,2,3,1380593700,41.836150155,-87.648787952,,,12.6,,,Cash,Taxi Affiliation Services,1380,,0,0
Curl:
curl --location --request POST 'https://ml.googleapis.com/v1/projects/<<project-name-here/models/tfxmodel:predict'
--header 'Authorization: Bearer <<TOKEN HERE'
--header 'Accept: application/json'
--header 'Content-Type: application/json'
--data-raw '{"instances":["Taxi Affiliation Services","","","","","27.05","Cash","",60,41.836150155,-87.648787952,0,12.6,1380,3,2,10,1380593700]}'
Response:
{"error": "Prediction failed: Error processing input: Expected string, got 27.05 of type 'float' instead."}
Of note if I start converting all the floats and ints to strings it ends up giving me an invalid requestbody error which doesn't suprise me.
To some of the comments: If I add single qoutes into double and also update the empty values to have a zero:
RequestBody:
{"instances":["Taxi Affiliation Services","'0'","'0'","'0'","'0'","'27.05'","Cash","'0'","'60,41.836150155'","'-87.648787952'","'0'","'12.6'","'1380'","'3'","'2'","'10'","'1380593700'"]}
Respose:
{
"error": "Prediction failed: Error during model execution: <_MultiThreadedRendezvous of RPC that terminated with:\n\tstatus = StatusCode.INVALID_ARGUMENT\n\tdetails = \"Could not parse example input, value: 'Taxi Affiliation Services'\n\t [[{{node ParseExample/ParseExampleV2}}]]\"\n\tdebug_error_string = \"{\"created\":\"#1611579449.396545283\",\"description\":\"Error received from peer ipv4:127.0.0.1:8081\",\"file\":\"src/core/lib/surface/call.cc\",\"file_line\":1056,\"grpc_message\":\"Could not parse example input, value: 'Taxi Affiliation Services'\\n\\t [[{{node ParseExample/ParseExampleV2}}]]\",\"grpc_status\":3}\"\n>"
}
Please give a try with the below format :-
{"instances":["\\”Taxi Affiliation Services\\”, , , , ,27.05,\\”Cash\\”, ,60,41.836150155,-87.648787952,0,12.6,1380,3,2,10,1380593700"]}
You can check this link for CSV data with each row encoded as a string value:- https://cloud.google.com/ai-platform/prediction/docs/reference/rest/v1/projects/predict#request-body-details

category_list param for test page creation request

Having created a test user for my app, I intend to create a test page by sending the following POST request to the Facebook API (some parts obviously replaced with dummies):
https://graph.facebook.com/v7.0/<TEST_USER_ID>/accounts?access_token=<APP_TOKEN>&name=Dummypage&category_enum=BANK&about="Text"&picture=<URL_TO_IMAGE>&cover_photo={"url": "<URL_TO_OTHER_IMAGE>"}&location={"city": "SomeCity","state": "SomeState","country": "DE"}&address="<ADDRESS>"&phone="<PHONE>"&category_list=[{"id": "133576170041936"} ,{"id": "145988682478380"}]
The problematic part of this is the category_list parameter, which I have attempted to pass in many forms already. Arriving at
category_list=[{"id": "133576170041936"} ,{"id": "145988682478380"}]
I finally no longer get the error that the param has to be an array - instead I get the following error: (#100) Param category_list[0] must be a valid ID string (e.g., \"123\") .
This is fairly confusing, as the IDs are taken from the response of an API response containing the page categories:
https://graph.facebook.com/v7.0/fb_page_categories?access_token=<TOKEN>
How should the parameter be correctly passed?
What I tried so far:
category_list=["145988682478380"]
category_list=[145988682478380]
Result: (#100) Invalid parameter
category_list=[{"id": "145988682478380"}]
category_list=[{"id": "145988682478380", "name": "Kreditgenossenschaft", "api_enum": "CREDIT_UNION"}] #full entry as listed in page categories response
Result: (#100) Param category_list[0] must be a valid ID string (e.g., "123")
Documentation references
Page category
Creating a test page via POST request
This curl command worked by me:
curl -i -X POST -H "Content-Type: application/json" -d "{ \"category_list\": [192803624072087, 145988682478380]}" "https://graph.facebook.com/v8.0/me?access_token=[page_access_token]"
So with the following JSON Body:
{
"category_list": [192803624072087, 145988682478380]
}

Return data as json from odoo 9

I want get data in JSON format from odoo controllery.py
Example:
import openerp.http as http
from openerp.http import request
class MyController(http.Controller):
#http.route('/test_html', type="http", auth="public")
def some_html(self):
return "<h1>Test</h1>"
#Work fine when open http://localhost:8069/test.html
#http.route('/test_json', type="json", website=True, auth="public")
def some_json(self):
return [{"name": "Odoo", 'website': 'www.123.com'}]
How get data in json format, I want data from json read in other app with ajax.
Is it possible view json after open url http://localhost:8069/test_json ???
The important part is to define the contentType of your request properly.
import json
#http.route('/test_json', type="json", auth="public")
def some_json(self):
return json.dumps({"name": "Odoo", 'website': 'www.123.com'})
In your client using javascript you can request the json like this.
$.ajax({
type: "POST",
url: "/test_json",
async: false,
data: JSON.stringify({}),
contentType: "application/json",
complete: function (data) {
console.log(data);
}
});
Or using requests in python
import requests,json
res = requests.post("http://localhost:8069/test_json",data=json.dumps({}),headers={"Content-Type":"application/json"})
To access the response body
body = res.text
As to whether you can simply open a browser and view the json. No, not by default.
Here is what I get
Bad Request
<function some_json at 0x7f48386ceb90>, /test_json: Function declared as capable of handling request of type 'json' but called with a request of type 'http'
You could probably do something pretty fancy with a controller if you really wanted to be able to view it in a browser as well as make json requests. I would post a second question though.
Your controller endpoint looks ok and should function correctly, so I guess your main question is how to test it.
Once you declare that the endpoint type is json, Odoo will check that the request content type header is in fact JSON, so in order to test it your requests will need to have Content-Type: application/json header set. This is a bit difficult using a regular browser, unless you edit the request headers before seinding or call your JSON endpoint from JavaScript via Ajax.
Alternatively, you can test your API from command line using a tool like curl:
curl 'http://localhost:8069/test_json' -H 'Content-Type: application/json' --data "{}"
--data "{}" here indicates an empty JSON structure which will be passed to your endpoint as request parameters.
Please note that you might also have to pass an additional header containing your session_id cookie if you are using more than one Odoo database.

How to make a POST simple JSON using Django REST Framework? CSRF token missing or incorrect

Would appreciate someone showing me how to make a simple POST request using JSON with Django REST framework. I do not see any examples of this in the tutorial anywhere?
Here is my Role model object that I'd like to POST. This will be a brand new Role that I'd like to add to the database but I'm getting a 500 error.
{
"name": "Manager",
"description": "someone who manages"
}
Here is my curl request at a bash terminal prompt:
curl -X POST -H "Content-Type: application/json" -d '[
{
"name": "Manager",
"description": "someone who manages"
}]'
http://localhost:8000/lakesShoreProperties/role
The URL
http://localhost:8000/lakesShoreProperties/roles
DOES work with a GET request, and I can pull down all the roles in the database, but I can not seem to create any new Roles. I have no permissions set. I'm using a standard view in views.py
class RoleDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Role.objects.all()
serializer_class = RoleSerializer
format = None
class RoleList(generics.ListCreateAPIView):
queryset = Role.objects.all()
serializer_class = RoleSerializer
format = None
And in my urls.py for this app, the relevant url - view mappings are correct:
url(r'^roles/$', views.RoleList.as_view()),
url(r'^role/(?P<pk>[0-9]+)/$', views.RoleDetail.as_view()),
Error message is:
{
"detail": "CSRF Failed: CSRF token missing or incorrect."
}
What is going on here and what is the fix for this? Is localhost a cross site request? I have added #csrf_exempt to RoleDetail and RoleList but it doesn't seem to change anything. Can this decorator even be added to a class, or does it have to be added to a method?
Adding the #csrf_exempt decorate, my error becomes:
Request Method: POST
Request URL: http://127.0.0.1:8000/lakeshoreProperties/roles/
Django Version: 1.5.1
Exception Type: AttributeError
Exception Value:
'function' object has no attribute 'as_view'
Then I disabled CSRF throughtout the entire app, and I now get this message:
{"non_field_errors": ["Invalid data"]} when my JSON object I know is valid json. It's a non-field error, but I'm stuck right here.
Well, it turns out that my json was not valid?
{
"name": "admin",
"description": "someone who administrates"
}
vs
[
{
"name": "admin",
"description": "someone who administrates"
}
]
Having the enclosing brackets [], causes the POST request to fail. But using the jsonlint.com validator, both of my json objects validate.
Update: The issue was with sending the POST with PostMan, not in the backend. See https://stackoverflow.com/a/17508420/203312
CSRF is exempted by default in Django REST Framework. Therefore, curl POST request works fine. POSTMAN request call returned CSRF incorrect because POSTMAN included csrf token if it is found in Cookies. You can solve this by cleaning up Cookies.
It's from your REST Framework settings. in your settings.py file, your REST_FRAMEWORK should have the following.
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.AllowAny',
),
}
This will set your REST Framework to use token authentication instead of csrf authentication. And by setting the permission to AllowAny, you can authenticate only where you want to.
You probably need to send along the CSRF token with your request. Check out https://docs.djangoproject.com/en/1.7/ref/contrib/csrf/#csrf-ajax
Update: Because you've already tried exempting CSRF, maybe this could help (depending on which version of Django you're using): https://stackoverflow.com/a/14379073/977931
OK, well now of course I take back what I said. CSRF does work as intended.
I was making a POST request using a chrome plugin called POSTMAN.
My POST request fails with CSRF enabled.
But a curl POST request using
curl -X POST -H "Content-Type: application/json" -d '
{
"name": "Manager",
"description": "someone who manages"
}' http://127.0.0.1:8000/lakeshoreProperties/roles/
works fine...
I had to take off the braces, i.e., [], and make sure there is a slash after the 's' in roles, i.e., roles/, and csrf enabled did not throw any errors.
I'm not sure what the difference between calling using POSTMAN is vs using curl, but POSTMAN is run in the web browser which is the biggest difference. That said, I disabled csrf for the entire class RoleList but one identical request works with Curl, but fails with POSTMAN.
To give an update on current status, and sum up a few answers:
AJAX requests that are made within the same context as the API they are interacting with will typically use SessionAuthentication. This ensures that once a user has logged in, any AJAX requests made can be authenticated using the same session-based authentication that is used for the rest of the website.
AJAX requests that are made on a different site from the API they are communicating with will typically need to use a non-session-based authentication scheme, such as TokenAuthentication.
Therefore, answers recommending to replace SessionAuthentication with TokenAuthentication may solve the issue, but are not necessarily totally correct.
To guard against these type of attacks, you need to do two things:
Ensure that the 'safe' HTTP operations, such as GET, HEAD and OPTIONS cannot be used to alter any server-side state.
Ensure that any 'unsafe' HTTP operations, such as POST, PUT, PATCH and DELETE, always require a valid CSRF token.
If you're using SessionAuthentication you'll need to include valid CSRF tokens for any POST, PUT, PATCH or DELETE operations.
In order to make AJAX requests, you need to include CSRF token in the HTTP header, as described in the Django documentation.
Therefore, it is important that csrf is included in header, as for instance this answer suggests.
Reference: Working with AJAX, CSRF & CORS, Django REST framework documentation.
As you said your URL was
http://localhost:8000/lakesShoreProperties/roles
Postman has some issues with localhost.
Sending the POST to 127.0.0.1:8000/your-api/endpoint instead did the trick for me.
the old Postman is having a problem with csrf tokens because it does not working with cookies.
I suggest for you to switch to the new version of postman, it works with cookies and you will not face this problem again.
if you have set AllowAny permission and you facing with csrf issue
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.AllowAny'
]
}
then placing following in the settings.py will resolve the issue
REST_SESSION_LOGIN = False