Skip to main content

GraphQL HTTP

PyPI version Python versions License: MIT

📚 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 accepted 200 text/event-stream response as a next event carrying the errors, followed by complete (a 400 would leave e.g. a browser EventSource with no error detail). Resolver errors during the stream ride inside next payloads as standard GraphQL errors; a fatal source error emits a final next carrying the error, then complete.
  • Middleware & execution context: subscription events resolve through the same middleware chain and execution_context_class as 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 : ping SSE comments every 15 seconds so intermediary proxies don't drop the connection. Configure with GraphQLHTTP(..., sse_keepalive_interval=30.0) (must be positive; None disables pings).
  • Concurrency limit: at most sse_max_streams subscription streams (default 100) may be open concurrently per server; further subscription requests are rejected with 429 Too Many Requests until a slot frees up. Pass sse_max_streams=None to remove the limit.
  • Disconnects: when the client closes the connection the underlying subscription generator is closed promptly — including await-based cleanup in its finally block — with no leaked tasks.

See the documentation for configuration, authentication, and advanced features.

Documentation

Visit the official documentation for comprehensive guides, examples, and API reference.

Key Topics

License

MIT License - see LICENSE file for details.

Metadata

Release files for graphql-http 2.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for graphql-http 2.5.0
File Size Uploaded Provenance Actions
graphql_http-2.5.0.tar.gz 267.5 kB Without provenance Details for graphql_http-2.5.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for graphql-http 2.5.0
File Interpreter ABI Platform Actions
graphql_http-2.5.0-py3-none-any.whl Python 3 none any Details for graphql_http-2.5.0-py3-none-any.whl

Total release size: 366.9 kB

Release files / graphql_http-2.5.0.tar.gz

Download URL graphql_http-2.5.0.tar.gz
Size 267.5 kB
Tags Source
SHA-256 checksum
How to use checksums
bfbe4709fb430843ef6ecac02644ed0053df9dbbbc0cffef2792b5903d29211e
BLAKE2b-256 checksum
How to use checksums
e61680d9c19575b1310a2c4e088df2dbd738c6440de6372c80d7b07e2155a1f4
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-2.5.0-py3-none-any.whl

Download URL graphql_http-2.5.0-py3-none-any.whl
Size 99.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1557524c86af05c78de4a45bf803bff9d68970abe8790688ae83b023021cd8df
BLAKE2b-256 checksum
How to use checksums
555bd1ed1f4717d6ff14250e0a4ab42c8b6c9c5d96aacaf580d351ff09dfb7f4
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 2.5.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.

Release history Release notifications | RSS feed

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page