graphql-python / flask-graphql Goto Github PK
View Code? Open in Web Editor NEWAdds GraphQL support to your Flask application.
License: MIT License
Adds GraphQL support to your Flask application.
License: MIT License
Hi !
It would be nice to be able to pass arbitrary variables to the graphiql template. I didn't found how to do it and looking at how render_graphiql.py
is called, it seems that this is not possible.
I found a workaround by pre-formatting my template before passing it to GraphQLView.as_view()
but it felt awkward.
Maybe something like this would look nicer:
view_func = GraphQLView.as_view(
url,
schema,
graphiql=True,
graphiql_template=my_custom_template,
graphiql_template_context={"username": username} # Now I can greet the user on my custom page !
)
If you guys are interested by this proposal let me know and I'll do a PR in the next few days.
I want to access query/mutation names from views so I can add the name to the logging system. How can I access it?
I am making an extension library flask-graphql-auth. and error handler by using flask's app.errorhandler is being planed for the 1.0 release. I checked that if my library caused an exception like JWTDecodeError, an GraphQLLocatedError occurred. However, the flask can not handle the error by app.errorhandler. Is this a bug?
@app.errorhandler(GraphQLLocatedError)
def handle(e):
return 401
I wrote this code. but stacktrace appears :(
...
Traceback (most recent call last):
File "C:\Users\Lewis\OneDrive\Documents\Development Repos\flask-graphql-auth\venv\lib\site-packages\graphql\execution\executor.py", line 330, in complete_value_catching_error
exe_context, return_type, field_asts, info, result)
File "C:\Users\Lewis\OneDrive\Documents\Development Repos\flask-graphql-auth\venv\lib\site-packages\graphql\execution\executor.py", line 383, in complete_value
raise GraphQLLocatedError(field_asts, original_error=result)
graphql.error.located_error.GraphQLLocatedError: Signature verification failed
127.0.0.1 - - [21/Jul/2018 12:48:30] "POST /graphql? HTTP/1.1" 200 -
I'm working on an example repo and was wondering, what would be the simplest way to implement that? This is what I tried without GraphQL:
@app.route('/upload', methods=['POST'])
def uploadFile():
for key in request.files:
file = request.files[key]
file.save(os.path.join(UPLOAD_FOLDER, file.filename))
return 'uploaded'
This is what I used in Node.js, would love to do something like that for Flask in Python.
If it's not supported by flask-graphql I'd be happy to work on a pull request. Also, how would you test this without a browser, using Graphiql, Postman or something like that?
With Django and Graphene users can do the following to exempt the graphql endpoint from CSRF authentication.
urlpatterns = [
path("admin/", admin.site.urls),
path("graphql", csrf_exempt(GraphQLView.as_view(graphiql=True, schema=schema))),
]
How can one do this with Flask-GraphQL?
app.add_url_rule(
'/graphql',
view_func=GraphQLView.as_view(
'graphql',
schema=schema,
graphiql=True
)
)```
The embedded GraphiQL version (0.11.11) is extremely outdated. The newest version is now 2.0.1.
We see the following errors when using nested lists:
Error: Decorated type deeper than introspection query.
at n (http://cdn.jsdelivr.net/graphiql/0.7.1/graphiql.min.js:15:23637)
at n (http://cdn.jsdelivr.net/graphiql/0.7.1/graphiql.min.js:15:23879)
at n (http://cdn.jsdelivr.net/graphiql/0.7.1/graphiql.min.js:15:23733)
at n (http://cdn.jsdelivr.net/graphiql/0.7.1/graphiql.min.js:15:23879)
at r (http://cdn.jsdelivr.net/graphiql/0.7.1/graphiql.min.js:15:24425)
at http://cdn.jsdelivr.net/graphiql/0.7.1/graphiql.min.js:15:26609
at http://cdn.jsdelivr.net/graphiql/0.7.1/graphiql.min.js:11:8480
at Array.reduce (native)
at keyValMap (http://cdn.jsdelivr.net/graphiql/0.7.1/graphiql.min.js:11:8444)
at f (http://cdn.jsdelivr.net/graphiql/0.7.1/graphiql.min.js:15:26484)
Here's the example code that can cause this issue. Graphene introspection doesn't report any errors.
import graphene, json
class Animal(graphene.Interface):
id = graphene.String()
class Dog(graphene.ObjectType):
class Meta:
interfaces = (Animal, )
breed = graphene.String()
class Cat(graphene.ObjectType):
class Meta:
interfaces = (Animal, )
category = graphene.String()
class Query(graphene.ObjectType):
animals = graphene.NonNull(graphene.List(graphene.NonNull(graphene.List(graphene.NonNull(Animal)))))
def resolve_animals(self, args, context, info):
return[[Dog(id=1, breed='Golden Retriever'),
Dog(id=2, breed='German Shepard')],
[Cat(id=11, category ='Tiger'),
Cat(id=12, category='House Cat')]]
schema = graphene.Schema(query=Query, types=[Dog, Cat, ])
Errors disappear if we remove the "required" or NonNull decorators. Any suggestions on how to fix these errors?
Hi, I'm currently looking at upgrading an application to graphql-core v3 (graphql-core-next) and I was wondering if there are any plans to create a version that would be compatible.
Besides this package there's graphene
as the main dependency and they have released a pre-release that is compatible with graphql-core v3
It's been almost 6 months since the last release of this project to PyPi. Can you push a new version? I would like to use #13.
Thanks!
In https://github.com/graphql-python/flask-graphql/blob/master/flask_graphql/render_graphiql.py#L24, the referrer is being sent on the static assets. This is problematic for large queries
Based on the tutorial setup and personal testing, it doesn't appear that these two methods work in tandem. Any examples of these interoperating? Or should I switch to raw SQLAlchemy to support GraphQL?
Cannot find much information about this and struggling to debug myself:
AttributeError: 'dict' object has no attribute 'decode'
Error appears when accessing the graphql IDE with a minimal setup:
class Query(graphene.ObjectType):
node = relay.Node.Field()
schema = graphene.Schema(query=Query)
app.add_url_rule(
"/graphql",
view_func=GraphQLView.as_view("graphql", schema=schema, graphiql=True),
)
All queries are faced with this error, without the graphql IDE the endpoint is fine.
https://github.com/graphql-python/flask-graphql/blob/master/flask_graphql/graphqlview.py#L50
Here you hardcode the context_value
to the request
object, instead of using the context
provided as option (if provided).
It appears I can only bind a single SQLAlchemy session to an app at once via the context variable:
from flask import Flask
from flask_graphql import GraphQLView
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, scoped_session
from schema import schema
# connect to database sources
engine1 = create_engine('sqlite:///db1.sqlite3')
engine2 = create_engine('sqlite:///db2.sqlite3')
session1 = scoped_session(sessionmaker(bind=engine1))
session2 = scoped_session(sessionmaker(bind=engine2))
# create app and add GraphiQL route
app = Flask(__name__)
app.add_url_rule('/graphql', view_func=GraphQLView.as_view(
'graphql',
schema=schema,
graphiql=True,
get_context=lambda: {'session': session1}
))
Is there any way to connect to more than one data source at once or is this not possible?
If not, Flask-SQLAlchemy handles this well by binding the data source name to the sqlalchemy model. I'd recommend doing something similar: http://flask-sqlalchemy.pocoo.org/2.3/binds/
I figured out a workaround by specifying the right session in the GraphQL query but this seems very hacky and prevents me from using nice extensions like Graphene-SQLAlchemy
class Query(ObjectType):
node = relay.Node.Field()
# requires session1 (both resolvers work because default session is session1)
all_employees = SQLAlchemyConnectionField(EmployeeConnections)
employees = graphene.List(EmployeeNode, name=graphene.String())
# requires session2
all_departments = SQLAlchemyConnectionField(DepartmentConnections) # can't do this because default session is session1
departments = graphene.List(DepartmentNode, name=graphene.String())
def resolve_departments(self, info, **kwargs):
name = kwargs.get('name')
if not name:
raise GraphQLError('Name argument is required.')
return session2.query(Department).filter_by({'name': kwargs.get('name')}).all()
I have Flask-GraphQL==2.0.1
installed and inside Chrome it is requiring dependencies like
http://cdn.jsdelivr.net/npm/[email protected]/graphiql.min.js
note: currently the latest version in jsdelivr is 1.0.6
however the github readme says
graphiql_version: The graphiql version to load. Defaults to "1.0.3".
reallly? If I set graphiql_version=1.0.3
explicitly, then Chrome throws error
Uncaught Error: GraphiQL 0.18.0 and after is not compatible with React 15 or below
I did not find anywhere the render_graphiql.py
set the variable to "1.0.3"
In my local drive is GRAPHIQL_VERSION = '0.11.11'
;
and gitlab GRAPHIQL_VERSION = '0.7.1'
Hello,
I've been doing some flask and graphql practices. I made mutations, the proof of concept went well until I had to validate the data entry by the user.
Usually in api rest, I release a
make_response(jsonify(error="my error"), 404)
but with graphql I haven't found a way to launch a 400. All codes are 200.
Someone can explain to me a little more and how I could launch an error 400 when the user's input is not valid.
Thanks
I posted about this on stackoverflow, but figured I'd ask about it directly here as well: https://stackoverflow.com/questions/53233291/python-flask-and-graphene-incorrect-request-causes-security-issue
Basically, the issue is that when I try to perform a high volume of mutations as one user while another user is making requests as well, some number of those mutations are made as the wrong user.
The issue seems to go away when I run with gunicorn
instead of FLASK_ENV=production flask run
I know the context is populated here: https://github.com/graphql-python/flask-graphql/blob/master/flask_graphql/graphqlview.py but the context for the query is incorrect in this case.
I was wondering if anyone had seen this issue before, or could point me in the right direction so I can figure out what's wrong.
No updates recently?
Hello guys,
I playing with GraphQL and I received this exception AttributeError str' object has no attribute 'decode' with python 3.
I'd like to propose distinction between 'str' and 'unicode' in GraphQLView class function parse_body()
Thanks
Martin
The current implementation catch all GraphQL execution exception and return as errors
in response. However, the detail information of exception like line number, file name, call stack are missing. It would be difficult to debug when not having these information.
I think it could be better to have a new member logger
, and when there is an execution exception, it can use logger.exception
to log this exception for debugging.
Hello,
We are using this library to add graphql support to our flask app. We used to have version 1.3.1 installed and the following view code was working correctly:
class AppGraphQLView(GraphQLView):
def execute_graphql_request(self, *args, **kwargs):
"""Extract any exceptions and send them to Raygun"""
result = super().execute_graphql_request(*args, **kwargs)
if result is not None and result.errors:
send_errors_to_raygun(result.errors)
return result
We've recently updated to version 2.0.0 of this library, and this caused our errors to not be sent to raygun, because our function is no longer called.. I discovered that the whole of GraphQLView has been refactored to not include execute_graphql_request
anymore so I tried using dispatch_request
instead.
However, dispatch_request
returns a json object and any errors have only the message, no stacktrace or any other important information we would need to send to raygun.
I have tried to replicate this functionality without overwriting GraphQLView's implementation of execute_graphql_request
, by using middleware instead:
def error_reporting_middleware(next, root, info, **kwargs):
result = next(root, info, **kwargs)
if result.is_rejected:
send_errors_to_raygun([result.reason])
return result
This kinda works, but I was wondering if there is a similar way to do it using the refactored GraphQLView in v2.0.0.
Thanks!
Now that the minimum version of graphql-core
was bumped to >=2.3
we're now seeing warnings returning when running tests that leverage Flask-GraphQL
.
Here's the relevant diff between graphql-core
2.2.1
and 2.3
:
graphql-python/graphql-core@v2.2.1...v2.3.0#diff-a2c439ae03cccc507934c1377530d14aL74-L87
In graphqlview.py
- arguments are being passed as root
and context
though it seems these arguments are getting deprecated in favor of root_value
and context_value
.
flask-graphql/flask_graphql/graphqlview.py
Lines 92 to 93 in 0137ca1
Here's the relevant DeprecationWarning
DeprecationWarning: The 'context' alias has been deprecated. Please use 'context_value' instead.
DeprecationWarning: The 'root' alias has been deprecated. Please use 'root_value' instead.
A 'headers' bar/tab can be added in the interface to support authentication tokens and other header functionality.
Currently, other external third-party clients like Insomnia have to be downloaded.
What's the right way to get request header when resolving a query/mutation? A related issue, #17, lead me to believe that info.context.headers
will work but I'm finding that doesn't exist when I try to print it:
❮❮❮ curl -i -H 'Content-Type: application/json' -H 'x-authorization-info: testing' -X POST -d '{"query": "query { latestSnapshot { url } }"}' http://localhost:5000/graphql
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 160
Server: Werkzeug/0.14.1 Python/3.6.7
Date: Thu, 18 Apr 2019 22:21:51 GMT
{"errors":[{"message":"'dict' object has no attribute 'headers'","locations":[{"line":1,"column":9}],"path":["latestSnapshot"]}],"data":{"latestSnapshot":null}}%
with a resolver of:
def resolve_latest_snapshot(self, info: ResolveInfo, org_id: Optional[int] = None) -> models.Snapshot:
print(info.context.headers)
# more stuff
I have flask-graphql version 2.0.0.
EDIT: other related packages I have:
graphene==2.1.3
graphql-core==2.1
graphql-relay==0.4.5
graphql-server-core==1.1.1
graphene-sqlalchemy==2.1.1
Using SQLAlchemy and my current process of creating database sessions revolve around a context manager and a session factory.
AKA in a RESTful API I would do something like this:
def someroute():
with session_factory() as session:
...do some controller stuff with the session...
return result
Since Graphene/GraphQL seems to wrap a lot of the magic around querying, how do I inject the session I create dynamically on a query/mutation request?
It seems like the model expected here is to have a persistent database session? Am I correct in assuming this?
P.S. I originally opted for this model since I wanted to contain all database side-effecty stuff in one python module instead of having to hook into my backend request teardown loop to handle cleaning up sessions.
GraphQL requests that contain unicode characters fails with the error message 'POST body sent invalid JSON.'
I was able to fix it by adding utf-8 parameter to decode method .
graphqlview.py L132:
request_json = json.loads(request.data.decode('utf-8'))
Hi,
graphql-core
2.3.0 contains a fix for the concurrency issues that have been reported in flask-graphql
(e.g. #43). Given Flask rely heavily on thread-scoped global variables, I would recommend you bump the minimum version for graphql-core
in setup.py
to completely prevent these security errors from happening.
See https://github.com/graphql-python/graphql-core/pull/260#issue-356659503 for more context.
Cheers,
J
Hi there, I'm using flask-graphql in a project and got into a question/issue I don't have many clues. I'm using middlewares; this is the minimum example:
from flask import Flask, request
from flask_graphql import GraphQLView
from graphene import Field, ObjectType, Schema, String, relay
class Hello(ObjectType):
message = String()
class Query(ObjectType):
hello = Field(Hello)
def resolve_hello(self, info):
return Hello(message="Hi there")
class DummyMiddleware(object):
def resolve(self, next, root, info, **kwargs):
print("DummyMiddleware")
return next(root, info, **kwargs)
dummy_middleware = DummyMiddleware()
schema = Schema(query=Query)
app = Flask(__name__)
app.add_url_rule('/graphql', view_func=GraphQLView.as_view('graphql',
schema=schema,
graphiql=True,
middleware=[dummy_middleware]))
if __name__ == "__main__":
app.run(host='0.0.0.0', threaded=True)
(The problem happens no matter the version; the problem also happens when launching the wsgi app with gunicorn).
If I query "hello()", the "DummyMiddleware" will appear twice. If I query a list of elements, the middleware is executed lots of time, twice per element it seems.
For a query this is just a problem of performance, but in a Logout() mutation what happens is:
Is there anything wrong in my approach to middlewares? I'm not sure which part is responsible (flask, graphql, my configuration...). Any hint would be appreciated.
@syrusakbary thank you for this great project! I noticed that there have been a lot of commits since the last release, of which the last one was 6 months ago. Are you still planning on working on this project?
Best regards
Hi and thanks for the geat job.
With 1.4.1 version I used to pass my DB session via the context
option of the GraphQLView as still mentioned in the README (which should be updated).
Below is an exemple of what I was doing:
# [...]
db_session = scoped_session(
sessionmaker(autocommit=False, autoflush=False, bind=engine))
# [...]
app.add_url_rule(
'/graphql', view_func=GraphQLView.as_view(
'graphql', schema=SCHEMA, graphiql=True,
context={'session': db_session}))
# [...]
It seems this is no more possible and I can't figure out how to pass the DB session to the GraphQLView. Any information and/or updated doc would be nice.
Any solution to continue passing DB session via the GraphQLView (or by any other way allowing to pass it at execution time) would be perfect.
EDIT: for an undocumented but working solution see @cockscomb 's comment
Can someone share the recommended way to create an update mutation? I only saw examples on mutations that create new objects, not update existing ones.
Awesome project you got going here, thanks for keeping this going. I've been using the batch option to allow for batch-GraphQL requests from ApolloClient, but it doesn't seem like there is an easy way to specify what shape I want the data to return in? Correct me if I'm wrong.
For example, currently when sending batch-requests, I get back a JSON array with the data I am interested in nested under a "data" key which is itself nested in a "payload" key.
[
{"payload":
{"data":
{<some_data_stuff_here}
}
},
{"payload":
{"data":
{<some_data_stuff_here}
}
},
{"payload":
{"data":
{<some_data_stuff_here}
}
}
]
I'm hoping I can just get these objects sent back without the data nested in the payload key. Any suggestions? Thanks in advance.
Detailed explanation of the problem is written here:
https://stackoverflow.com/questions/57557517/how-to-get-json-response-in-flask-graphql-response
graphql
returns JSON as a string. Is it possible to return JSON object instead of a string?
I am trying to figure out the best way to authenticate a request before my schema executes the query/mutation. I was thinking I could use the @app.resolver('url') tag and create a function that would authenticate the request and then pass it to the graphqlview. Something like this:
@app.route('/graphql/')
def graphql():
print request.headers #AUTHENTICATE HERE
print request.data
return GraphQLView.as_view('/graphql/', schema=schema, graphiql=True)
But this doesn't work, can someone either show me what I am doing wrong here or give me a different way to authenticate the request? Thanks!
graphql-core 3.0.0 was just released 3 days ago and now my builds are breaking. I have had to specify graphql-core==2.2.1 in my requirements.txt to fix this. I'm guessing that the Flask-Graphql module dependencies need updated to prevent graqhql-core>=3.
Python: 3.7.5
Flask-Graphql: 2.0.0
graphql-core: 3.0.0
Truncated stack trace:
...
File "/opt/python3.7/lib/python3.7/site-packages/flask_graphql/__init__.py", line 1, in <module>
from .blueprint import GraphQL
File "/opt/python3.7/lib/python3.7/site-packages/flask_graphql/blueprint.py", line 5, in <module>
from .graphqlview import GraphQLView
File "/opt/python3.7/lib/python3.7/site-packages/flask_graphql/graphqlview.py", line 7, in <module>
from graphql_server import (HttpQueryError, default_format_error,
File "/opt/python3.7/lib/python3.7/site-packages/graphql_server/__init__.py", line 5, in <module>
from graphql import get_default_backend
ImportError: cannot import name 'get_default_backend' from 'graphql' (/opt/python3.7/lib/python3.7/site-packages/graphql/__init__.py)
File "flask_graphql/graphqlview.py", line 102, in dispatch_request
status=status_code,
UnboundLocalError: local variable 'status_code' referenced before assignment
Is there an easy way to override the serializer to return YAML instead of JSON?
You haven't made reference to a package manager or resource manager, like pip.
Please include it so developers can easily look-up flask-graphql
This is more of a query: How do I return a list of objects as response? So let's say, I have defined a field
using Graphene.Field
in my query. Now depending on the incoming query, the result may be a single field
element or a list of field
elements.
Thank you.
link: https://github.com/graphql-python/graphene/blob/master/UPGRADE-v2.0.md#simpler-resolvers
The new resolver has changed, Now, resolver args are passed as keyword arguments to the function, and context argument disappeared in favor of info.context.
Is there a way to enable the GraphiQL explorer for a Python (flask-graphql
) backend?
Hi,
wouldn't it make sense to have separate endpoints for GraphQL and GraphiQL? As per README, there should be two endpoints (/graphql
and /graphiql
), however only /graphql
gets exposed. Let's say I would like to publish GraphiQL only to selected group of people (e.g. frontend developers) and protect it by authentication. Having a separate endpoint would make whole thing much easier.
Hi there! Beginner at graphql, I'm slowly discovering the power or graphql and I was wondering how do you add doc to your mutations etc? I'm using PynamoDB and I can't find a way to add doc to the graphiql
🤔
Any idea ?
I would love to be able to use Altair GraphQL Client as a view like the GraphiQL view, especially since it provides several extra features than the normal graphiql (like file uploading, setting headers, etc). Would it be possible to include a view for Altair?
Ps: I'm also open to making a contribution myself as well, if you guys agree for that. 🙂
Hard to demonstrate, but with version 1.4 I set a conect value as a dictionary and this gets past to my resolver (graphene 2.1.1) but with rc2 the context passed is a proxy that does not contain any of my passed context values.
the interaction between this library, graphql-core, and promise appears to allow execution to hop threads especially (only?) when using a middleware and nested resolvers. this is inconsistent with flasks threading model and the ability to access the request/g thread locals
with the attached (very contrived) example, when submitting the query with concurrent requests the requests frequently fail because the key created in get_context doesn't exist on the threadlocal flask.g object in the resolvers. This happens when a thread accesses the promise.async_instance which isn't thread local, and resolves a promise that was created on a different thread.
query.txt
from flask import Flask
from flask_graphql import GraphQLView
app = Flask(__name__)
import graphene
import threading
import time
from flask import g
def get_user(info):
return g.get(info.context['key'])
class User(graphene.ObjectType):
id = graphene.ID()
name = graphene.String()
friend = graphene.Field(lambda: User)
age = graphene.Int()
apple = graphene.String()
@classmethod
def resolve_friend(cls, root, info):
time.sleep(.1)
x = get_user(info)
return User(id=id(root), name=':'.join([x.name, threading.current_thread().name]))
@classmethod
def resolve_age(cls, root, info):
time.sleep(.1)
return 5
@classmethod
def resolve_apple(cls, root, info):
time.sleep(.1)
return "Apple"
class Query(graphene.ObjectType):
me = graphene.Field(User)
def resolve_me(self, info):
time.sleep(.1)
return get_user(info)
schema = graphene.Schema(query=Query)
ahh = {}
def dummy_middleware(next, root, info, **args):
return_value = next(root, info, **args)
return return_value
import random
random.seed()
class TestQLView(GraphQLView):
def get_context(self, request):
# set a random key in g to be used by resolvers
key = str(random.randint(0,50))
name = threading.current_thread().name
user = User(id=key, name=name)
setattr(g, key, user)
return {
'key': key
}
app.add_url_rule('/graphql', view_func=TestQLView.as_view('graphql', schema=schema, graphiql=True, middleware=[dummy_middleware]))
Is there any plan to implement this / are you accepting pull requests?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.