Skip to content

Repository files navigation

nexusx

pypi PyPI Downloads

nexusx turns a SQLModel database into two things: a GraphQL query interface that's friendlier than writing SQL, and business logic that ships as REST, GraphQL, MCP, and CLI from a single signature.

flowchart LR
    subgraph Logic["Business logic — one signature, many transports"]
        s["UseCaseService<br/>methods"]
        s --> rest["REST / OpenAPI"]
        s --> gql2["GraphQL"]
        s --> mcp2["MCP (AI agents)"]
        s --> cli["CLI"]
    end
    subgraph Query["Query surface — friendlier than SQL"]
        e["SQLModel entities<br/>+ relationships"]
        e --> gql1["GraphQL"]
        e --> mcp1["MCP"]
        e --> er["ER diagrams (Voyager)"]
    end
Loading

What it does for you

1. A query interface over your database — not another query writer.

GraphQLHandler reflects your entities and relationships into a read surface where you declare the shape you want — users { posts { comments } } — and nexusx compiles it to optimal SQL: one batched round-trip per level, columns pruned to what you selected, per-parent pagination. N+1 and over-fetching aren't pitfalls to avoid; they're structurally impossible. Turn on auto_query_config for by_id and equality by_filter; richer predicates (range, like, ordering) are one @query method that rejoins the same surface. Voyager renders the schema as an interactive ER diagram, so the query interface is self-documenting.

2. Business logic, on every transport.

A UseCaseService method is plain async Python. One signature becomes a FastAPI route (with OpenAPI), an MCP tool for AI agents, a CLI command — and a GraphQL field. Note this GraphQL is different from the one above: it projects business operations, not your raw data graph, and it's built AI-first (compact describe_* discovery, no 50K-token introspection dump). The same codebase serves a web frontend, power integrations, and an AI agent without rewriting the logic three times.

Both pillars speak "GraphQL," but they are different surfaces:

SQLModel GraphQL (GraphQLHandler) UseCaseService GraphQL (compose_query)
What it is A query interface over your DB A projection of business methods
Source Auto-reflected from entities + relations Hand-written @query / @mutation
Built for Browsing / slicing your data graph Invoking operations (app + AI)
Introspection Full (GraphiQL-friendly) Rejected (AI-first, compact describe_*)

In 30 seconds

The query surface — entities become a GraphQL and MCP query interface:

from sqlmodel import SQLModel, Field, Relationship, select
from nexusx import query, GraphQLHandler
from nexusx.mcp import create_simple_mcp_server

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

    @query
    async def users(cls, limit: int = 10) -> list["User"]:
        async with session() as s:
            return (await s.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")

# GraphQL — { users { posts { title } } } is 2 SQL round-trips, not 1+N
GraphQLHandler(base=SQLModel, session_factory=session)

# MCP — Claude / Cursor call get_schema + graphql_query, fetching SDL on demand
create_simple_mcp_server(base=SQLModel, name="Blog", session_factory=session)

The business-logic surface — one service class becomes REST + MCP:

from nexusx import (
    query, UseCaseService, UseCaseAppConfig,
    create_use_case_router, create_use_case_graphql_mcp_server,
)

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

cfg = UseCaseAppConfig(name="project", services=[SprintService])
app.include_router(create_use_case_router(cfg))        # REST + OpenAPI
create_use_case_graphql_mcp_server(apps=[cfg]).run()   # MCP for AI agents

When to reach for it

  • You want a friendlier query interface over a SQLModel database than writing SQL — graph-shaped reads, N+1-proof, selection-driven.
  • You need more than one transport from one codebase — REST + GraphQL, or app + AI agent.
  • You have non-ORM relations (Redis, search, external APIs) that should flow through the same loader / DTO / diagram plumbing as native ones.

When not to

  • You only ever need one REST handler per endpoint and are happy writing them by hand — plain FastAPI is simpler.
  • You want fine-grained resolver control over a large GraphQL schema — Strawberry gives you more knobs.

Install

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

Requires Python ≥ 3.10.

Learn more

Status

Stable — follows semantic versioning. Bug reports and PRs welcome. MIT.

About

Declare SqlModel then get RESTful, GraphQL and MCP at the same time

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages