Skip to main content

GraphQL SDL generation and query optimization for SQLModel

Project description

nexusx

Write SQLModel classes. Get a complete API.

pypi PyPI Downloads

Most projects repeat the same data model three or four times — once for the database, once for the API response, once for GraphQL. nexusx eliminates that. Define your entities and relationships in SQLModel, and you get:

  • GraphQL — auto-generated schema, relationships resolve automatically, no N+1
  • REST — typed response DTOs, pick fields like GraphQL but in Python
  • MCP — your business logic exposed as tools for AI agents

One model, multiple surfaces — and more protocols on the way.

flowchart LR
    sqlmodel["SQLModel"]

    sqlmodel --> graphql["GraphQL"]
    graphql --> mcp1["MCP"]

    sqlmodel --> usecase["UseCaseService"]
    usecase --> rest["REST"]
    usecase --> mcp2["MCP"]
    usecase -.-> jsonrpc["JSON-RPC"]
    usecase -.-> ws["WebSocket"]

Install

pip install nexusx
pip install nexusx[fastmcp]  # with MCP support

Requires Python ≥ 3.10.

Quick Start

Step 1: Define entities and relationships

from sqlmodel import SQLModel, Field, Relationship, select
from nexusx import query, mutation

class User(SQLModel, table=True):
    id: int | None = Field(default=None, primary_key=True)
    name: str
    posts: list["Post"] = Relationship(back_populates="author")

    @query
    async def get_users(cls, limit: int = 10) -> list["User"]:
        """Get all users."""
        async with get_session() as session:
            return (await session.exec(select(cls).limit(limit))).all()

class Post(SQLModel, table=True):
    id: int | None = Field(default=None, primary_key=True)
    title: str
    author_id: int = Field(foreign_key="user.id")
    author: User | None = Relationship(back_populates="posts")

    @mutation
    async def create_post(cls, title: str, author_id: int) -> "Post":
        """Create a post."""
        async with get_session() as session:
            post = cls(title=title, author_id=author_id)
            session.add(post)
            await session.commit()
            return post

Step 2: Start GraphQL

from nexusx import GraphQLHandler

handler = GraphQLHandler(base=SQLModel, session_factory=async_session)

Query relationships — they resolve automatically via DataLoader, one query per level:

{
  userGetUsers(limit: 5) {
    name
    posts { title }
  }
}

Step 3: Add typed REST endpoints

When you're ready for production, add DefineSubset DTOs on the same entities. DefineSubset is the Python equivalent of GraphQL field selection — instead of writing { id name } in a query string, you declare ("id", "name") in a Python class and get a typed, validated DTO:

from nexusx import DefineSubset, ErManager

class UserDTO(DefineSubset):
    __subset__ = (User, ("id", "name"))

class PostDTO(DefineSubset):
    __subset__ = (Post, ("id", "title", "author_id"))
    author: UserDTO | None = None   # auto-loaded — name matches Post.author

er = ErManager(base=SQLModel, session_factory=async_session)
Resolver = er.create_resolver()

# Per request
dtos = await Resolver().resolve(posts)

Relationship fields auto-load when the field name matches a registered relationship. Add post_* methods for derived fields, resolve_* for custom loading logic.

Step 4: Expose to AI agents

Package business logic as UseCaseService — same class serves both MCP and REST:

from nexusx import UseCaseService, UseCaseAppConfig, create_use_case_mcp_server, create_use_case_router

class SprintService(UseCaseService):
    @query
    async def list_sprints(cls) -> list[SprintSummary]:
        """Get all sprints with task counts."""
        ...

# MCP (AI agents)
mcp = create_use_case_mcp_server(
    apps=[UseCaseAppConfig(name="project", services=[SprintService])],
)
mcp.run()

# REST (FastAPI)
app.include_router(create_use_case_router(
    UseCaseAppConfig(name="project", services=[SprintService])
))

Recap

From a single set of entity definitions, you get:

  • GraphQL — auto-generated schema with DataLoader relationship resolution
  • REST — typed DTOs with implicit auto-loading, OpenAPI docs at /docs
  • MCP — four-layer progressive disclosure for AI agents

All three share the same SQLModel entities and the same DataLoader infrastructure.

How It Compares

Tool GraphQL auto-gen REST + OpenAPI MCP N+1 prevention Relationship auto-loading
nexusx yes yes yes yes (DataLoader) yes (implicit)
Strawberry yes no no manual manual loader
FastAPI + SQLModel no yes (manual) no no no
Ariadne yes no no manual no
FastMCP no no yes no no

Choosing a Mode

If you want to... Start with
Validate a data model quickly with flexible queries GraphQL Mode
Ship typed REST endpoints for a frontend team Core API Mode
Expose business capabilities to AI agents UseCase Services
Do all three from one model UseCase Services → embed DTOs inside methods

The modes compose: a UseCaseService method can internally use Resolver().resolve(dtos) for Core API data assembly. They share the same DataLoader engine and the same entities.

What the Framework Handles

Your responsibility Framework's responsibility
Define SQLModel entities + relationships Auto-generate GraphQL SDL
Write @query/@mutation methods Resolve relationships via DataLoader (one query per level)
Declare DefineSubset DTOs Implicit auto-loading of matching relationship fields
Write post_* methods for derived fields Execute them after the subtree is fully resolved
Declare ExposeAs/SendTo/Collector Route cross-layer data flow automatically
Define UseCaseService subclasses Discover methods, generate MCP tools + FastAPI routes

Demos

git clone https://github.com/allmonday/nexusx.git
cd nexusx
bash start_all.sh
Service Port What it shows
GraphQL playground 8000 Auto-generated Schema + DataLoader relationship resolution
Core API (REST) 8001 DefineSubset DTOs with resolve_/post_/cross-layer flow
Auth GraphQL 8002 Multi-entity auth model with queries + mutations
Auth MCP 8003 Same auth model exposed as MCP tools
Multi-app MCP 8004 Two apps sharing one MCP server
Paginated GraphQL 8005 Relationship pagination (limit/offset)
UseCase MCP 8006 4-layer progressive disclosure MCP
UseCase FastAPI 8007 Same UseCaseService served as OpenAPI-documented REST
Voyager 8008 Visual entity-relationship map

AI Agent Skill

A 4-phase skill guides AI coding agents through the full nexusx workflow: clarify requirements → build POC model → add queries → productize.

ln -s $(pwd)/skill ~/.claude/skills/nexusx-4phase

Development

./scripts/check-ci.sh       # Run full CI checks (lint + type-check + tests)
uv run pytest               # Run tests only
uv run ruff check src/ tests/  # Lint only
uv run mypy src/            # Type-check only

Documentation

License

MIT

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

nexusx-2.6.0.tar.gz (1.1 MB view details)

Uploaded Source

Built Distribution

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

nexusx-2.6.0-py3-none-any.whl (684.0 kB view details)

Uploaded Python 3

File details

Details for the file nexusx-2.6.0.tar.gz.

File metadata

  • Download URL: nexusx-2.6.0.tar.gz
  • Upload date:
  • Size: 1.1 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","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 nexusx-2.6.0.tar.gz
Algorithm Hash digest
SHA256 ba195aa0ef85defc97ebe695f64149c953e2178f6e0668d4817d80edfe55155a
MD5 e15e05ae37bb664710619c72d378b6e4
BLAKE2b-256 901d042242129028988be8da0f3066c8692fa1f89977bfb3f8f68121bdd51664

See more details on using hashes here.

File details

Details for the file nexusx-2.6.0-py3-none-any.whl.

File metadata

  • Download URL: nexusx-2.6.0-py3-none-any.whl
  • Upload date:
  • Size: 684.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","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 nexusx-2.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c904e4ff6235a6cf12065352bb69c6c38c9f6c0478196eb98897e7710a8d756f
MD5 d9fadcc80b782a571f88325d3ee75498
BLAKE2b-256 7bfb772513834ac640d514f37b3823238ac91b01103fec59e04d5dfb7b9b7b1b

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 Pingdom Monitoring Sentry Error logging StatusPage Status page