Skip to content

GraphQL#

A real tokenizer, recursive-descent parser, and executor — not a regex matcher — supporting arguments, variables, nested selections, mutations, and configurable depth/field limits.

Defining a schema#

from hayavega.graphql import Schema, graphql_view


def get_post(request, id):
    return {"id": id, "title": "Hello", "author": {"name": "Alice"}}


schema = Schema(
    query={"post": get_post},
    mutation={"createPost": create_post},
    max_depth=10,  # default
    max_fields=200,  # default
    introspection=False,  # default: no __schema exposed
)

urlpatterns = [
    path("graphql", graphql_view(schema), methods=("POST",)),
]

Querying#

query {
  post(id: "1") {
    title
    author { name }
  }
}

Field arguments (string/int/float/boolean/null/enum/list/object literals), variables ($id: ID! required, $active: Boolean = true defaulted), and nested selections on a resolver returning a mapping (or list of mappings) all work — an unknown sub-field is a per-field error, not a crash. A resolver exception becomes a per-field GraphQL error ({"data": {...: null}, "errors": [...]}), never an unhandled exception reaching the WSGI layer.

Mutations#

mutation {
  createPost(title: "Hello") {
    id
  }
}

Limits and introspection#

max_depth/max_fields are checked before any resolver runs, plus a hard structural parse-depth cap independent of configuration so a maliciously deep query can't overflow the parser itself. Introspection is off by default (__typename always works, since it reveals no schema shape); Schema(introspection=True) opts into a minimal __schema listing root field names.

What's deliberately not supported#

Fragments and directives are explicitly rejected with a clear parse error, not silently mis-parsed — kept out to avoid the real complexity they'd add for a framework this size. Revisit only if a concrete need emerges.

Error disclosure#

Like REST, a resolver exception never leaks its raw message to the client (Schema(debug=False), the default, exposes only error_type) — see Security for the full standard.

Rust-accelerated parsing#

Tokenizing and parsing a query (not field resolution, which always calls your own Python resolvers) runs through a Rust port of the same grammar when hayavega_native is built — a faithful port, not a reinterpretation, with an identical pure-Python fallback otherwise. Measured (benchmarks/native_graphql_parser.py) at a real 2.7-3.9x speedup over the pure-Python lexer/parser, including the cost of decoding the result back into Python objects. No configuration needed either way, and Schema.execute()'s behavior (including error messages for malformed queries) is identical on both paths.