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 executor_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 3.0.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 3.0.0
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)

Table of built distributions (wheels) for graphql-http 3.0.0
File Interpreter ABI Platform Actions
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.

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