GraphQL HTTP
📚 Documentation | 📦 PyPI | 🔧 GitHub
A lightweight, production-ready HTTP server for GraphQL APIs built on top of Starlette/FastAPI. This server provides a simple yet powerful way to serve GraphQL schemas over HTTP with built-in support for authentication, CORS, GraphiQL integration, and more.
Features
- 🚀 High Performance: Built on Starlette/ASGI for excellent async performance
- 🔐 JWT Authentication: Built-in JWT authentication with JWKS support
- 🌐 CORS Support: Configurable CORS middleware for cross-origin requests
- 🎨 GraphiQL Integration: Interactive GraphQL IDE for development
- 📊 Health Checks: Built-in health check endpoints
- 🔄 Batch Queries: Support for batched GraphQL operations
- 📡 Subscriptions: GraphQL subscriptions streamed over Server-Sent Events (graphql-sse compatible)
Installation
uv add graphql_http
Or with pip:
pip install graphql_http
Quick Start
Basic Usage
from graphql import GraphQLSchema, GraphQLObjectType, GraphQLField, GraphQLString
from graphql_http import GraphQLHTTP
# Define your GraphQL schema
schema = GraphQLSchema(
query=GraphQLObjectType(
name="Query",
fields={
"hello": GraphQLField(
GraphQLString,
resolve=lambda obj, info: "Hello, World!"
)
}
)
)
# Create the HTTP server
app = GraphQLHTTP(schema=schema)
# Run the server
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)
Using with graphql-api
For building GraphQL schemas, use graphql-api:
from graphql_api import GraphQLAPI
from graphql_http import GraphQLHTTP
api = GraphQLAPI()
@api.type(is_root_type=True)
class Query:
@api.field
def hello(self, name: str = "World") -> str:
return f"Hello, {name}!"
server = GraphQLHTTP.from_api(api)
server.run()
Subscriptions (Server-Sent Events)
GraphQL subscriptions are served over Server-Sent Events, following the
GraphQL over SSE protocol
in distinct connections mode: each operation gets its own SSE connection, results
stream as next events, and a final complete event signals the end of the stream.
Any request whose Accept header includes text/event-stream (with a non-zero
q-value) is answered over SSE — subscriptions stream one next event per result,
while queries and mutations respond with a single next followed by complete.
A valid subscription sent without Accept: text/event-stream is rejected with
406 Not Acceptable.
Defining a subscription with graphql-api
Any field returning an AsyncGenerator becomes a subscription:
import asyncio
from typing import AsyncGenerator
from graphql_api import GraphQLAPI
from graphql_http import GraphQLHTTP
api = GraphQLAPI()
@api.type(is_root_type=True)
class Root:
@api.field
def hello(self) -> str:
return "world"
@api.field
async def countdown(self, start: int = 3) -> AsyncGenerator[int, None]:
while start >= 0:
yield start
start -= 1
await asyncio.sleep(1)
server = GraphQLHTTP.from_api(api)
server.run()
Consuming with curl
curl -N \
-H "Accept: text/event-stream" \
-H "Content-Type: application/json" \
-d '{"query": "subscription { countdown(start: 3) }"}' \
http://localhost:5000/graphql
event: next
data: {"data":{"countdown":3}}
event: next
data: {"data":{"countdown":2}}
event: next
data: {"data":{"countdown":1}}
event: next
data: {"data":{"countdown":0}}
event: complete
data:
Consuming with the graphql-sse JavaScript client
The graphql-sse client uses distinct
connections mode by default (singleConnection: false):
import { createClient } from 'graphql-sse';
const client = createClient({
url: 'http://localhost:5000/graphql',
});
const unsubscribe = client.subscribe(
{ query: 'subscription { countdown(start: 3) }' },
{
next: (result) => console.log(result), // { data: { countdown: 3 } } ...
error: (error) => console.error(error),
complete: () => console.log('done'),
},
);
Behavior notes
- Auth: SSE requests go through the same JWT/auth enforcement as regular requests. Authentication failures are returned as HTTP-level JSON errors (401/403) before any stream is opened. The introspection auth-bypass never applies to subscription operations.
- Errors: per the graphql-sse protocol, errors raised before execution
starts — missing query, parse errors, validation errors, and
subscribe()failures — are delivered over the accepted200 text/event-streamresponse as anextevent carrying the errors, followed bycomplete(a400would leave e.g. a browserEventSourcewith no error detail). Resolver errors during the stream ride insidenextpayloads as standard GraphQL errors; a fatal source error emits a finalnextcarrying the error, thencomplete. - Middleware & execution context: subscription events resolve through the
same
middlewarechain andexecutor_classas queries and mutations, so field-authorization or error-masking middleware applies to streamed results too. - Keep-alive: while a stream is idle the server emits
: pingSSE comments every 15 seconds so intermediary proxies don't drop the connection. Configure withGraphQLHTTP(..., sse_keepalive_interval=30.0)(must be positive;Nonedisables pings). - Concurrency limit: at most
sse_max_streamssubscription streams (default 100) may be open concurrently per server; further subscription requests are rejected with429 Too Many Requestsuntil a slot frees up. Passsse_max_streams=Noneto remove the limit. - Disconnects: when the client closes the connection the underlying
subscription generator is closed promptly — including
await-based cleanup in itsfinallyblock — with no leaked tasks.
Related Projects
- graphql-api - Build GraphQL schemas with decorators
- graphql-db - SQLAlchemy integration for database-backed APIs
- graphql-mcp - Expose GraphQL as MCP tools
See the documentation for configuration, authentication, and advanced features.
Documentation
Visit the official documentation for comprehensive guides, examples, and API reference.
Key Topics
- Getting Started - Quick introduction and basic usage
- Configuration - Configure your HTTP server
- Authentication - JWT and auth setup
- Testing - Test your GraphQL endpoints
- Examples - Real-world usage examples
- API Reference - Complete API documentation
License
MIT License - see LICENSE file for details.
Metadata
Release files for graphql-http 3.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| graphql_http-3.0.0.tar.gz | 267.1 kB | Without provenance | Details for graphql_http-3.0.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| graphql_http-3.0.0-py3-none-any.whl | Python 3 | none | any | Details for graphql_http-3.0.0-py3-none-any.whl |
Total release size: 366.3 kB
Release files / graphql_http-3.0.0.tar.gz
| Download URL | graphql_http-3.0.0.tar.gz |
|---|---|
| Size | 267.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
51e5e5a966925121592adb5e2d48fa62f7ae447206af627e71cdf44be826c98e
|
|
BLAKE2b-256 checksum How to use checksums |
f54a85325a0025fb088e77b590979ca0660f29affa7a3647a41ea4b04572c109
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / graphql_http-3.0.0-py3-none-any.whl
| Download URL | graphql_http-3.0.0-py3-none-any.whl |
|---|---|
| Size | 99.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6aff0e798f2d2df42fed6937a2275a1ff9dfe023e97c7b967e2225dcca6e7eef
|
|
BLAKE2b-256 checksum How to use checksums |
459825b6388fd96199ad9b6047c86f746428b73a7249ae3da6a2ea685277f2d0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for graphql-http 3.0.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.