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.

Related Projects

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.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

graphql_http-2.4.0.tar.gz (211.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

graphql_http-2.4.0-py3-none-any.whl (99.4 kB view details)

Uploaded Python 3

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

Hashes for graphql_http-2.4.0.tar.gz
Algorithm Hash digest
SHA256 16ad162615ddde47bec8164f06b0010d5db03a8c24a981d6f76ce83d2f27ec4d
MD5 3b97019482c91efe5bff01a2d0bf3810
BLAKE2b-256 9eb178264e5d22aeb95370fcbd6c0405e11198a2aa20ac49ec1406671ef408fa

See more details on using hashes here.

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

Hashes for graphql_http-2.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d98eeabe4d76d36532f5fdf051e7b4a494b7e486a1a4babfc2d5cc033167cdec
MD5 81274492d8033bc4f35540a9ab00f3be
BLAKE2b-256 a5469812c19be78f985266674866b7a8516a2e3c0e06b7722865fc118af733d1

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page