Skip to main content

A code-first, decorator-driven GraphQL framework for Python with a hand-built engine and a web-framework-agnostic core.

Project description

FastQL

A code-first, decorator-driven GraphQL framework for Python with a hand-built engine (lexer → parser → validator → executor), a built-in dependency-injection / context layer, and a web-framework-agnostic core — zero runtime dependencies, Python 3.11+.

Status: early development. The core engine (parse → build → validate → execute, with dependency injection and introspection) is in place.

Documentation: Start at fastql.vachagan.dev, then use the capability catalog to trace documented behavior to its canonical OpenSpec requirements. Documentation sources and publishing instructions live under docs/.

Quickstart

Define types and operations with decorators — field and argument types come from your Python type hints. Resolvers are plain functions; the executor injects arguments, the parent object, resolve info, and the Context based on each resolver's signature.

import asyncio
from typing import Annotated
from fastql import Argument, Context, Field, Query, Schema, Type, execute


@Type
class User:                  # just fields — constructor/repr/eq are auto-generated
    id: int
    full_name: str

    @Field
    def loud_name(self) -> str:   # exposed as loudName by default
        return self.full_name.upper()


class AppContext(Context):
    def __init__(self, users):
        self.users = users


@Query                       # group related queries on a class…
class Queries:
    @Field
    async def user(
        self,
        user_id: Annotated[int, Argument(name="id")],
        ctx: Context,
    ) -> "User | None":
        return ctx.users.get(user_id)

    @Field
    def ping(self) -> str:    # sync resolvers work alongside async ones
        return "pong"


schema = Schema(query=Queries)


async def main():
    ctx = AppContext(users={1: User(1, "Ada Lovelace")})
    result = await execute(schema, "{ user(id: 1) { id fullName loudName } ping }", context=ctx)
    print(result.data)       # {'user': {'id': 1, 'fullName': 'Ada Lovelace', 'loudName': 'ADA LOVELACE'}, 'ping': 'pong'}


asyncio.run(main())

@Type and @Input classes get generated constructors, repr, and equality unless they define their own methods. Python snake_case fields and arguments become GraphQL camelCase by default; pass SchemaConfig(auto_camel_case=False) to Schema to preserve Python names. Explicit name= metadata always wins. build_schema() remains available for applications that intentionally merge multiple globally decorated root classes.

execute returns an ExecutionResult with data, errors, and extensions, and a .formatted() helper that produces the GraphQL-over-HTTP response shape. Introspection (__schema, __type, __typename) is built in.

A fuller, runnable version — covering every type kind, mutations, subscriptions, DataLoaders, permissions, and extensions — lives in examples/app, the showcase schema that the per-framework projects under examples/projects all reuse.

The documentation quickstart and first-schema examples are also executed by the test suite from docs/snippets.

Dev server & playground

Try a schema in the browser with the built-in, zero-dependency dev server:

python -m fastql serve examples.app:schema      # http://127.0.0.1:7691

It serves, on the default port 7691:

Route Description
GET / GraphiQL IDE (loaded from CDN)
POST/GET /graphql the GraphQL endpoint ({data, errors} JSON)
GET /schema.graphql the schema as SDL
GET /schema.json the schema as an introspection result

Override the binding with --host / --port. If your resolvers need a Context, point --context at a value or zero-arg factory:

python -m fastql serve examples.app:schema --context examples.app:make_context

Or call it programmatically:

import fastql
from examples.app import schema, make_context

fastql.serve(schema, port=7691, context_factory=make_context)  # blocking; Ctrl-C to stop

The dev server lives outside the agnostic core (in fastql.server) and only consumes build_schema / execute — it is a developer convenience, not a production transport (no TLS, auth, or subscriptions).

Design at a glance

@Type / @Input / root class decorators  ← unified type-hint-driven authoring
        ▼
Schema(query=...) / build_schema()       ← compiles decorators into the type-system IR
        ▼
Type-system IR (Schema, ObjectType, Field, scalars, wrappers)
        ▼
execute() ── validation ── coercion ── async resolution + DI/context
        ▲
language: Source → Lexer → Parser → AST  ← hand-built front-end

The core never imports an HTTP framework. Transports (an optional built-in dev server, plus FastAPI/Django/Flask/ASGI adapters) plug in on top and consume build_schema / execute.

Web framework integrations

Install only the framework adapter an application uses:

pip install mygenx-fastql[fastapi]   # or starlette, flask, django
from fastapi import FastAPI
from fastql.integrations.fastapi import create_fastapi_router

app = FastAPI()
app.include_router(create_fastapi_router(schema, graphiql=True))

The base installation includes the dependency-free GraphQLASGI adapter. See the integration documentation for mounting, request context, endpoint configuration, and supported versions.

Runnable per-framework projects — FastAPI, Starlette, Flask, Django, and raw ASGI, each mounting the same examples/app schema — live under examples/projects. Reusing one schema across every adapter is the proof that the core is framework-agnostic; each project differs only in a few lines of glue.

Development

pip install -e ".[dev]"
pytest

Project details


Download files

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

Source Distribution

mygenx_fastql-1.0.0.tar.gz (80.5 kB view details)

Uploaded Source

Built Distribution

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

mygenx_fastql-1.0.0-py3-none-any.whl (106.9 kB view details)

Uploaded Python 3

File details

Details for the file mygenx_fastql-1.0.0.tar.gz.

File metadata

  • Download URL: mygenx_fastql-1.0.0.tar.gz
  • Upload date:
  • Size: 80.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for mygenx_fastql-1.0.0.tar.gz
Algorithm Hash digest
SHA256 7065466f32ca12067bce50fafd044c641374280b2600a2a8a9d6a35354ef0847
MD5 7077a37bc1a44c7b56f9d54cbc4dbdd7
BLAKE2b-256 191e3976ee1477128e705d6bed2b5c3dbdec360197546a3369e848db834763d4

See more details on using hashes here.

Provenance

The following attestation bundles were made for mygenx_fastql-1.0.0.tar.gz:

Publisher: publish.yml on MyGenX/FastQL

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mygenx_fastql-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: mygenx_fastql-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 106.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for mygenx_fastql-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6cfd846e6ee9fa63fa11283ac65fb32f843ca745a7446843953a449285e9fcf1
MD5 bb1192fe22a1319009820c6c107a9a64
BLAKE2b-256 75e0598a0efa96bf54e2c92034a804ef1b2dc31b07dada510364f9f322f75a83

See more details on using hashes here.

Provenance

The following attestation bundles were made for mygenx_fastql-1.0.0-py3-none-any.whl:

Publisher: publish.yml on MyGenX/FastQL

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

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