Graphene - sgml/signature GitHub Wiki
Middleware
import graphene
# Define a logging middleware
class LoggingMiddleware:
def resolve(self, next_, root, info, **args):
field = info.field_name
print(f"[⏳] Resolving field: {field}")
result = next_(root, info, **args)
print(f"[✅] Resolved field: {field}")
return result
# Sample schema
class Query(graphene.ObjectType):
hello = graphene.String()
def resolve_hello(self, info):
return "Hello from Graphene"
schema = graphene.Schema(query=Query, middleware=[LoggingMiddleware()])
Explanation
Absolutely! In Graphene, you can wrap a resolver using custom middleware to add cross-cutting behavior—like logging, authorization checks, or even performance monitoring—around your field resolution.
Here’s a minimal but practical example of **wrapping a resolver** with middleware:
---
### 🧩 Example: Logging Resolver Middleware
```python
import graphene
# Define a logging middleware
class LoggingMiddleware:
def resolve(self, next_, root, info, **args):
field = info.field_name
print(f"[⏳] Resolving field: {field}")
result = next_(root, info, **args)
print(f"[✅] Resolved field: {field}")
return result
# Sample schema
class Query(graphene.ObjectType):
hello = graphene.String()
def resolve_hello(self, info):
return "Hello from Graphene"
schema = graphene.Schema(query=Query, middleware=[LoggingMiddleware()])
resolve()
wraps every resolver call.- You can inspect the field name, arguments, context (
info.context
), etc. - It allows injection of behavior before and after resolver execution.
Graphene supports composing them via MiddlewareManager
.
## Query Validators
Standard query validators can be used to test enforcement of security best practices such as the enforcement of a maximum depth for any operation in a GraphQL document or verifying that your schema cannot be introspected.
* Create a function:
def resolve_bar(
* Create a field:
bar = graphene.Field(schema.foo)
Translates to
foo{ bar{} }
* Create variables
baz=graphene.String(required=True)
Translates to
baz:String!
```term=graphene.String(required=False)```
Translates to
```baz:String```
## SQLAlchemy => Flask => Pytest Process Map
steps:
-
name: "Set Up Your Environment" description: "Install necessary packages: graphene, graphene-sqlalchemy, and SQLAlchemy." commands:
- "pip install graphene graphene-sqlalchemy sqlalchemy"
-
name: "Define SQLAlchemy Model for Foo" description: "Create an SQLAlchemy model corresponding to the table 'foo'." code: |
models.py
from sqlalchemy import Column, Integer, String from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class FooModel(Base): tablename = 'foo' id = Column(Integer, primary_key=True) name = Column(String) value = Column(Integer)
-
name: "Create Graphene SQLAlchemy Object Type" description: "Define a Graphene type for Foo using SQLAlchemyObjectType based on FooModel." code: |
schema.py (part 1)
import graphene from graphene_sqlalchemy import SQLAlchemyObjectType from models import FooModel
class Foo(SQLAlchemyObjectType): class Meta: model = FooModel
-
name: "Extend GraphQL Schema with 'paginate_foo'" description: > Add a query field 'paginate_foo' to the Query type that accepts 'limit' and 'offset' as required arguments, and implement its resolver to execute the SQLAlchemy query with LIMIT and OFFSET. code: |
schema.py (continued)
class Query(graphene.ObjectType): paginate_foo = graphene.List( Foo, limit=graphene.Int(required=True), offset=graphene.Int(required=True) )
def resolve_paginate_foo(self, info, limit, offset): # Retrieve the SQLAlchemy session from the context session = info.context.get("session") # Execute the SQL query with pagination results = session.query(FooModel).limit(limit).offset(offset).all() return results
Create the Graphene schema
schema = graphene.Schema(query=Query)
-
name: "Integrate with GraphQL Server using Flask" description: > Set up a Flask-based GraphQL server that wires in the Graphene schema and passes the SQLAlchemy session into the GraphQL context. This ensures that your resolver can access the database. code: |
app.py
from flask import Flask, request from flask_graphql import GraphQLView from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from schema import schema # the schema defined above
app = Flask(name)
Configure the database engine and session factory
engine = create_engine('sqlite:///mydatabase.db') # Replace with your actual DB URI SessionLocal = sessionmaker(bind=engine)
@app.before_request def create_session(): request.session = SessionLocal()
@app.teardown_request def remove_session(exception=None): session = getattr(request, 'session', None) if session: session.close()
app.add_url_rule( '/graphql', view_func=GraphQLView.as_view( 'graphql', schema=schema, graphiql=True, get_context=lambda: {"session": request.session} ) )
if name == 'main': app.run(debug=True)
-
name: "Test GraphQL Query using GraphiQL" description: > Verify your GraphQL endpoint by running a query in GraphiQL (or another GraphQL client) to ensure that pagination is working as expected. example_query: | query { paginate_foo(limit: 10, offset: 0) { id name value } }
-
name: "Pytest Mocking of Resolver" description: > Create a pytest unit test that mocks the SQLAlchemy session to test the 'paginate_foo' resolver. This step verifies that the resolver correctly processes the 'limit' and 'offset' parameters and returns an expected list of Foo objects. code: |
test_resolvers.py
import pytest from schema import Query from models import FooModel
class DummySession: def init(self, results): self.results = results
def query(self, model): assert model == FooModel return self def limit(self, limit): self._limit = limit return self def offset(self, offset): self._offset = offset return self def all(self): return self.results
@pytest.fixture def dummy_session(): # Create dummy FooModel objects simulating database rows foo1 = FooModel(id=1, name="Foo 1", value=100) foo2 = FooModel(id=2, name="Foo 2", value=200) return DummySession(results=[foo1, foo2])
def test_paginate_foo(dummy_session): context = {"session": dummy_session} # Dummy info object with a context attribute class DummyInfo: context = context
query = Query() result = query.resolve_paginate_foo(info=DummyInfo(), limit=10, offset=0) # Assert the correct number of Foo objects and their values assert len(result) == 2 assert result[0].id == 1 assert result[0].name == "Foo 1" assert result[1].id == 2 assert result[1].name == "Foo 2"
## Graphene vs Apollo
graphene: contributors: 180 releases: 60 open_issues: 200 pull_requests: 1500 commits: 3000 tests: 42 number_of_licenses: 1 number_of_repositories_tagged_with_this_topic: 31 known_bugs: 200 forks: 823 readme_size_bytes: 5120 number_of_original_authors: 1 number_of_unimplemented_specification_items: 3 number_of_files_in_repo: 320
apollo: contributors: 400 releases: 100 open_issues: 1000 pull_requests: 5000 commits: 10000 tests: 210 number_of_licenses: 2 number_of_repositories_tagged_with_this_topic: 460 known_bugs: 1000 forks: 2500 readme_size_bytes: 8192 number_of_original_authors: 4 number_of_unimplemented_specification_items: 1 number_of_files_in_repo: 980
## Tools
| Tool | Description | Link |
|------|-------------|------|
| **GraphQL Inspector** | A dedicated GraphQL validation tool for schema changes, breaking changes detection, and security analysis. | [GraphQL Inspector](https://www.scrumlaunch.com/blog/best-graphql-tools-for-2025/) |
| **GraphQL Editor** | A visual GraphQL schema builder and testing tool, designed for API visualization and debugging. | [GraphQL Editor](https://dev.to/requestly/best-tools-for-graphql-development-in-2025-dba) |
| **GraphQL Faker** | A tool for generating mock GraphQL data, useful for testing and prototyping GraphQL APIs. | [GraphQL Faker](https://apidog.com/blog/best-graphql-tools/) |
## References
https://github.com/graphql/graphql-spec
https://docs.graphene-python.org/en/latest/types/interfaces/
https://medium.com/@ryk.kiel/graphql-and-fastapi-the-ultimate-combination-for-building-apis-with-python-f4391bf5505c
https://docs.graphene-python.org/en/latest/_modules/graphene/types/scalars/#Boolean
https://github.com/graphql-python/swapi-graphene/blob/master/starwars/schema.py
https://github.com/graphql-python/graphene/issues/268
https://buildmedia.readthedocs.org/media/pdf/graphene-python/stable/graphene-python.pdf
https://readthedocs.org/projects/graphene-python/downloads/pdf/stable/
https://docs.graphene-python.org/en/latest/types/mutations/
https://github.com/graphql-python/graphene
https://vincenttechblog.com/building-web-api-with-python-flask-graphql-sqlalchemy-and-postgresql/
https://stackoverflow.com/questions/57313080/perform-nested-query-in-python-graphene-with-distinct-types-in-schema
https://matthewgladney.com/blog/data/graphql/adding-to-a-graphene-schema-to-execute-a-graphql-query/
https://github.com/graphql-python/graphene-django/issues/142
https://pypi.org/project/graphene/
https://docs.graphene-python.org/projects/sqlalchemy/en/latest/
https://shopify.dev/docs/api/usage/pagination-graphql
https://shopify.dev/docs/apps/build/graphql
https://shopify.dev/docs/api/admin-graphql
https://serverless.com/blog/running-scalable-reliable-graphql-endpoint-with-serverless/
https://jeffersonheard.github.io/python/graphql/2018/12/08/graphene-python.html
https://docs.graphene-python.org/en/latest/quickstart/
https://github.com/graphql-python/graphene/issues/110
https://itnext.io/python-graphql-tips-tricks-and-performance-improvements-beede1f4adb6
https://github.com/graphql-python/graphene-sqlalchemy/blob/master/docs/tutorial.rst
https://medium.com/free-code-camp/how-to-develop-a-flask-graphql-graphene-mysql-and-docker-starter-kit-4d475f24ee76
https://stackoverflow.com/questions/46415795/how-to-place-a-multi-line-single-string-json-in-postman/60083076#60083076
https://stackoverflow.com/questions/60115681/python-multiline-graphql-mutation-with-variables-keyerror
https://stackoverflow.com/questions/62384215/best-way-to-construct-a-graphql-query-string-in-python
https://stackoverflow.com/search?q=graphql+python+%22multiline%22
https://www.youtube.com/watch?v=iDqgMbPSUYs