ciscorn / starlette-graphene3 Goto Github PK
View Code? Open in Web Editor NEWAn ASGI app for using Graphene v3 with Starlette / FastAPI
License: MIT License
An ASGI app for using Graphene v3 with Starlette / FastAPI
License: MIT License
@ciscorn can i merge the automated pydantic v2 field to graphene field ? which been avoid the duplication of code
Hey, I've been using starlette-graphene3
and I've got into a small issue.
When I want to signal an error (i.e. an entity not found) I raise a Python exception. The exact exception type depends on the type of error. I then catch all these errors in a middleware to log them, and re-raise them as GraphQLError's to send an appropriate error response to the client. This package then logs the error too, so it's logged twice. I would like these errors not to be logged again by the package.
I think that a possible solution is for you to implement an optional error handler, such that only the errors that I don't catch are logged. That could be in the form of a callback, passed to the app's constructor.
Recently switched over to running Starlette to get working subscriptions, but I've run into a very strange bug.
Versions:
Running our app as follows
app = Starlette()
schema = graphene.Schema(
query=Query,
mutation=Mutation,
subscription=Subscription,
auto_camelcase=False,
)
app.mount("/", GraphQLApp(schema, on_get=make_graphiql_handler()))
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)
Running the following in GraphiQL works:
{
star {
id
}
}
This works as well:
query {
star {
id
}
}
This fails:
query name1 {
star {
id
}
}
query name2 {
star {
id
}
}
With the following error:
Syntax Error GraphQL (1:1) Unexpected <EOF>
1:
^
I can also see similar errors given this input:
query {
star {
id
}
}
query name2 {
star {
id
}
}
Which results in
{
"data": null,
"errors": [
{
"message": "This anonymous operation must be the only defined operation.",
"locations": [
{
"line": 1,
"column": 1
}
],
"path": null
}
]
}
I do note a few odd behaviors here.
Great project! I tried to use the websocket functionality, which works when i run the tests, but when i try to do so from a simple html page, the websocket endpoint this error:
WebSocket connection to 'ws://127.0.0.1:3000/graphql-ws' failed: Error during WebSocket handshake: Response must not include 'Sec-WebSocket-Protocol' header if not present in request: graphql-ws.
import graphene
from graphene import String
#from starlette.graphql import GraphQLApp
from starlette_graphene3 import GraphQLApp
from app.main import app
html = '''
<!DOCTYPE html>
<html>
<head>
<title>Websocket test</title>
</head>
<body>
<form action="" onsubmit="sendMessage(event)">
<input type="text" id="messageText" autocomplete="off"/>
<button>Send</button>
</form>
<ul id='messages'>
</ul>
<script>
var GQL_CONNECTION_ACK = "connection_ack";
var GQL_CONNECTION_ERROR = "connection_error";
var GQL_CONNECTION_INIT = "connection_init";
var GQL_CONNECTION_TERMINATE = "connection_terminate";
var GQL_COMPLETE = "complete";
var GQL_DATA = "data";
var GQL_ERROR = "error";
var GQL_START = "start";
var GQL_STOP = "stop";
var ws = new WebSocket("ws://127.0.0.1:3000/graphql-ws");
ws.onconnect = function(event) {
ws.send('{"type": ' + GQL_CONNECTION_INIT+ '}')
}
ws.onmessage = function(event) {
console.log("RECEIVED MESSAGE: ", event.data);
};
</script>
</body>
</html>
'''
@app.get("/")
def get() -> Any:
return HTMLResponse(html)
class GraphQ(graphene.ObjectType):
echo = graphene.String(msg=graphene.String())
def resolve_echo(self, info, msg):
return f'Message was: {msg}'
gapp = GraphQLApp(schema=graphene.Schema(query=GraphQLQueries))
app.add_route("/graphql", gapp)
app.add_websocket_route("/graphql-ws", gapp)
I can see starlette.test_client.py adds some headers:
def websocket_connect(
self, url: str, subprotocols: typing.Sequence[str] = None, **kwargs: typing.Any
) -> typing.Any:
url = urljoin("ws://testserver", url)
headers = kwargs.get("headers", {})
headers.setdefault("connection", "upgrade")
headers.setdefault("sec-websocket-key", "testserver==")
headers.setdefault("sec-websocket-version", "13")
if subprotocols is not None:
headers.setdefault("sec-websocket-protocol", ", ".join(subprotocols))
kwargs["headers"] = headers
try:
super().request("GET", url, **kwargs)
except _Upgrade as exc:
session = exc.session
else:
raise RuntimeError("Expected WebSocket upgrade") # pragma: no cover
return session
But i dont think i can/should add these when adding the websocket route?
No headers get added to the request from the Request Headers
pane in GraphiQL interface.
The issue does not occur with GraphQL Playground.
Unfortunately starlette is going to deprecate graphql support, so starlette-graphene3 looks like the only viable sol... unfortunately, pipenv can't lock beta this is using a beta graphene v....
why is this using a beta v of graphene which is 3.0b8?
I installed the latest version, but it appears that some of the required frontend libraries are missing for the graphiql frontend:
graphql_app = GraphQLApp(schema=graphene.Schema(query=GraphQLQueries, subscription=Subscription), on_get=make_playground_handler())
app.mount("/graphql", graphql_app)
127.0.0.1/:15 GET https://unpkg.com/graphiql/graphiql.css net::ERR_ABORTED 404
127.0.0.1/:17 GET https://unpkg.com/react-dom@16/umd/react-dom.production.min.js net::ERR_ABORTED 404
127.0.0.1/:22 GET https://unpkg.com/graphiql/graphiql.min.js net::ERR_ABORTED 404
127.0.0.1/:18 GET https://unpkg.com/[email protected]/browser/client.js net::ERR_ABORTED 404
127.0.0.1/:16 GET https://unpkg.com/react@16/umd/react.production.min.js net::ERR_ABORTED 404
127.0.0.1/:17 GET https://unpkg.com/react-dom@16/umd/react-dom.production.min.js net::ERR_ABORTED 404
127.0.0.1/:18 GET https://unpkg.com/[email protected]/browser/client.js net::ERR_ABORTED 404
127.0.0.1/:22 GET https://unpkg.com/graphiql/graphiql.min.js net::ERR_ABORTED 404
Maybe it would also be nice if there is an option to provide custom urls for these libraries, so you could host them yourself or point to another cdn?
PS: there are no problems when using the make_playground_handler
I'm trying to understand the best way to inject the database as a dependency for my graphql queries/mutations.
It looks like context is the appropriate way to do so, and based on reviewing other issues raised on the starlette repo encode/starlette#591, it sounds like the problem was never really solved. Given that starlette is deprecating graphql support and this repo appears to be filling in the gaps of that connection, it felt right to ask the question here.
The workaround described in issue 591 mentions adding the db session to the request via injection on the route, however, that appears to require calling execute on the GraphQL app directly, rather than the app.mount()
pattern described in ythe README. I wasn't able to find another way attach the GraphQL app to appropriately, so I'm wondering if I'm missing something or if db dependency injection just isn't possible at the moment.
Is this functionality currently possible to manage or is the expectation that the db will be accessed via things like the SQLAlchemy Graphene connection?
Im trying to import "from starlette_graphene3 import GraphQLApp" but this error throws me.
Traceback (most recent call last):
File "/usr/local/lib/python3.8/multiprocessing/process.py", line 315, in _bootstrap
self.run()
File "/usr/local/lib/python3.8/multiprocessing/process.py", line 108, in run
self._target(*self._args, **self._kwargs)
File "/usr/local/lib/python3.8/site-packages/uvicorn/subprocess.py", line 61, in subprocess_started
target(sockets=sockets)
File "/usr/local/lib/python3.8/site-packages/uvicorn/server.py", line 49, in run
loop.run_until_complete(self.serve(sockets=sockets))
File "/usr/local/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
return future.result()
File "/usr/local/lib/python3.8/site-packages/uvicorn/server.py", line 56, in serve
config.load()
File "/usr/local/lib/python3.8/site-packages/uvicorn/config.py", line 308, in load
self.loaded_app = import_from_string(self.app)
File "/usr/local/lib/python3.8/site-packages/uvicorn/importer.py", line 23, in import_from_string
raise exc from None
File "/usr/local/lib/python3.8/site-packages/uvicorn/importer.py", line 20, in import_from_string
module = importlib.import_module(module_str)
File "/usr/local/lib/python3.8/importlib/init.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "", line 1014, in _gcd_import
File "", line 991, in _find_and_load
File "", line 975, in _find_and_load_unlocked
File "", line 671, in _load_unlocked
File "", line 848, in exec_module
File "", line 219, in _call_with_frames_removed
File "/app/./src/main.py", line 3, in
from starlette_graphene3 import GraphQLApp
File "/usr/local/lib/python3.8/site-packages/starlette_graphene3.py", line 17, in
from graphql import (
ImportError: cannot import name 'ExecutionResult' from 'graphql' (/usr/local/lib/python3.8/site-packages/graphql/init.py)
GraphQLApp
Class has context_value
parameter of type ContextValue
which is defined as:
ContextValue = Union[Any, Callable[[HTTPConnection], Any]]
It leads to conclusion that I can set some function responsible for generating values per each connection, but actually it doesn't work, function is not evaluated and directly passed as value to resolver.
There is some problem with starlette-graphene3 dependencies
I was using it with https://pypi.org/project/graphql-relay/3.1.5/
and in the meantime they released:
https://pypi.org/project/graphql-relay/3.2.0/
and after starlette-graphene3 installation from scratch I get
ImportError: cannot import name 'resolve_thunk' from 'graphql' (/usr/local/lib/python3.8/dist-packages/graphql/init.py)
Hi There,
I'm using the following code to run a websocket GraphQL endpoint:
"""Main server application."""
import asyncio
import graphene
from starlette.applications import Starlette
from starlette_graphene3 import GraphQLApp
from starlette.middleware import Middleware
from starlette.middleware.cors import CORSMiddleware
from .schema import schema_basic
middleware = [
Middleware(
CORSMiddleware,
allow_origins=['*'],
allow_methods=['POST', 'GET'],
allow_headers=['access-control-allow-origin', 'authorization', 'content-type']
)
]
app = Starlette(debug=True, middleware=middleware)
gapp = GraphQLApp(schema_basic(), playground=True)
app.add_route("/graphql", gapp)
app.add_websocket_route("/graphql-ws", gapp)
How do I now debug the new websocket route in the playground?
Opening up playground with localhost:5000/graphql-ws
doesn't work
Opening up playground with localhost:5000/graphql
works but then when running the subcription, it's attempting to connect to the server on the incorrect route (/graphql
).
Any thoughts on how to figure out if the websocket endpoint is working?
It catches exceptions over http now #13 is resolved, but it is still swallows exceptions when subscribing / sending the query over a websocket:
app.mount("/graphql", graphql_app)
app.add_websocket_route("/graphql-ws", graphql_app)
Another suggestion would be to be able to mask the error details in the graphql response, so using logging getting the full error message, but return a generic error message over the graphql connection, so sensitive data cannot leak that way?
As seen in encode/starlette#953 + encode/starlette#954
It's a bit weird but it looks like the tarball of 0.2.1 that can be found on PyPI does not contain commit ae328c, even though it should be according to the commit history. Not sure how that could happen, maybe I'm missing something too obvious.
How to disable websockets in Graphql endpoint?
WARNING: Unsupported upgrade request.
WARNING: No supported WebSocket library detected. Please use 'pip install uvicorn[standard]', or install 'websockets' or 'wsproto' manually.
I recently switched my Graphene application to a FastAPI-based stack.
When testing my file uploads, I got the error Request body is not a valid multipart/form-data
, thrown here:
starlette-graphene3/starlette_graphene3.py
Line 416 in e18aa25
The underlying exception was The python-multipart library must be installed to use form parsing.
, which was not displayed to me. I think the ValueError raised in starlette-graphene should be changed to include the message of the underlying exception.
Currently all exceptions are catched and returned in a formatted form. This is fine for invalid formatted queries, but for programming errors in my code i'd like these to be reraised, so i can catch them with Sentry for example. I could not find a way to achieve this currently, any ideas?
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.