Metadata-Version: 2.4
Name: hayate-graphql
Version: 0.1.0
Summary: GraphQL over HTTP for Hayate, powered directly by graphql-core
Keywords: hayate,graphql,graphql-core,workers
Author: Yusuke Hayashi
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Typing :: Typed
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
Requires-Dist: graphql-core>=3.2.11,<3.3
Requires-Dist: hayate>=0.13.0
Requires-Python: >=3.12
Project-URL: Repository, https://github.com/hayatepy/hayate-graphql
Project-URL: Documentation, https://github.com/hayatepy/hayate-graphql#readme
Project-URL: Changelog, https://github.com/hayatepy/hayate-graphql/blob/main/CHANGELOG.md
Description-Content-Type: text/markdown

# hayate-graphql

> **Hayate ecosystem:** [Start here](https://hayatepy.dev/)
> · [Production golden app](https://github.com/hayatepy/golden-app)
> · [Tested compatibility](https://hayatepy.dev/evidence/compatibility/)

GraphQL over HTTP for [Hayate](https://github.com/hayatepy/hayate), powered directly by
[`graphql-core`](https://github.com/graphql-python/graphql-core).

`hayate-graphql` is deliberately a small hosting layer. Hayate owns HTTP and request context;
`graphql-core` owns the GraphQL language, schema, validation, coercion, execution, and
introspection. The package does not introduce another schema DSL.

> **Status: alpha (0.1.x), typed.** GET and JSON POST, media negotiation, Hayate context,
> bounded execution, the official GraphQL-over-HTTP audit, and Workerd/Pyodide execution are
> covered. See [DESIGN.md](DESIGN.md) for the package boundary and [CHANGELOG.md](CHANGELOG.md)
> for release history.

## Install

```bash
uv add hayate-graphql
```

## Usage

```python
from graphql import GraphQLField, GraphQLObjectType, GraphQLSchema, GraphQLString
from hayate import Hayate
from hayate_graphql import GraphQL

schema = GraphQLSchema(
    query=GraphQLObjectType(
        "Query",
        {"hello": GraphQLField(GraphQLString, resolve=lambda *_: "world")},
    )
)

app = Hayate()
GraphQL(schema, path="/graphql").mount(app)
```

Resolvers receive the Hayate `Context` as GraphQL's context value by default:

```python
def resolve_viewer(root, info):
    principal = info.context.get("principal")
    return {"name": principal.name}
```

An async context factory can create a different value and inspect validated request extensions:

```python
async def context_value(c, request):
    return {"request": c.req, "principal": c.get("principal")}


GraphQL(schema, context_value=context_value).mount(app)
```

Operational limits are enabled by default and can be tuned or disabled explicitly:

```python
GraphQL(
    schema,
    max_body_size=1024 * 1024,
    max_tokens=10_000,  # None disables the parser token limit
    max_depth=20,  # None disables the operation depth limit
    allow_introspection=False,
).mount(app)
```

## HTTP behavior

- GET queries and JSON POST requests
- `application/graphql-response+json` and legacy `application/json` negotiation
- correct separation of transport, request, and execution errors
- mutations rejected over GET
- body, token, and operation-depth limits
- optional introspection disabling and custom validation rules

Multipart uploads, a schema DSL, federation, UI assets, and subscription transports are outside
the initial package boundary.

## Verification

```bash
uv run pytest
uv run mypy src tests
uv run ruff check .
npm ci
npm run audit
uv build
scripts/check_workerd.sh dist/hayate_graphql-0.1.0-py3-none-any.whl
```

The Workerd check requires Node.js 24, builds a portable Pyodide bundle, starts a local Workerd
instance, and executes a real GraphQL request through Hayate's Workers adapter.
