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 andexecution_context_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.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file graphql_http-2.4.0.tar.gz.
File metadata
- Download URL: graphql_http-2.4.0.tar.gz
- Upload date:
- Size: 211.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","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}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
16ad162615ddde47bec8164f06b0010d5db03a8c24a981d6f76ce83d2f27ec4d
|
|
| MD5 |
3b97019482c91efe5bff01a2d0bf3810
|
|
| BLAKE2b-256 |
9eb178264e5d22aeb95370fcbd6c0405e11198a2aa20ac49ec1406671ef408fa
|
File details
Details for the file graphql_http-2.4.0-py3-none-any.whl.
File metadata
- Download URL: graphql_http-2.4.0-py3-none-any.whl
- Upload date:
- Size: 99.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","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}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d98eeabe4d76d36532f5fdf051e7b4a494b7e486a1a4babfc2d5cc033167cdec
|
|
| MD5 |
81274492d8033bc4f35540a9ab00f3be
|
|
| BLAKE2b-256 |
a5469812c19be78f985266674866b7a8516a2e3c0e06b7722865fc118af733d1
|