Skip to content

API & Clients

The backend exposes a REST API built with Django REST Framework. This page covers the endpoints, authentication, the OpenAPI schema, and the generated SDKs.

Exploring the API

With the server running (see Getting Started):

  • http://localhost:8000/ — the browsable API root
  • http://localhost:8000/schema/swagger/ — Swagger UI
  • http://localhost:8000/schema/redoc/ — ReDoc
  • http://localhost:8000/schema/ — the raw OpenAPI document

Responses use camelCase keys (a middleware converts Django's snake_case), which is what the generated clients and the frontend expect.

Endpoints

Routes are wired in backend/spellbook/urls.py, backend/website/urls.py, and the project urls.py.

Core (spellbook)

Endpoint Description
GET /variants/ The generated variants — the main read endpoint. Supports the search query language.
GET /cards/ Cards.
GET /features/ Features.
GET /templates/ Templates.
GET/POST /find-my-combos Given a decklist, returns the combos it can assemble (the engine's up phase).
GET/POST /estimate-bracket Estimates the power bracket of a decklist.
… /variant-suggestions/ Community-submitted combos awaiting review.
… /variant-update-suggestions/ Suggested edits to existing variants.
… /variant-aliases/ Redirects from alternative ids to canonical variants.

Site support (website)

Endpoint Description
GET /properties/ Site-wide configurable properties.
GET /card-list-from-url Parse a decklist from a supported deckbuilder URL (Moxfield, Archidekt, Deckstats, TappedOut).
GET/POST /card-list-from-text Parse a decklist from pasted text.

Users & auth

/users/, plus the authentication endpoints below.

Authentication

Two mechanisms, both configured in the project urls.py:

  • JWT (simplejwt):
  • POST /token/ — obtain an access/refresh pair
  • POST /token/refresh/ — refresh an access token
  • POST /token/verify/ — verify a token

Send the access token as Authorization: Bearer <token>.
- Social login (social-auth) — Discord OAuth, enabled when DISCORD_CLIENTID / DISCORD_CLIENTSECRET are set.

Most read endpoints are public; writing and reviewing require authentication and the appropriate permissions. Editors work primarily through the admin panel (/admin), not the API.

The search query language

variants (and template matching) accept a Scryfall-style search query — e.g. ci:temur mana result:"infinite mana". The grammar is defined with Lark in spellbook/parsers/ and turned into ORM filters by the transformers in spellbook/transformers/. Extend the query language by editing the .lark grammar and its transformer together.

OpenAPI schema

The schema is generated from the code by drf-spectacular. It is the contract the clients and frontend depend on, so keep it accurate: add serializer annotations and @extend_schema hints when you add or change an endpoint.

Regenerate the committed schema with:

cd client
./generate-openapi.sh   # writes client/openapi.yaml

The script runs manage.py spectacular … --fail-on-warn --validate, so a schema warning is treated as an error — the CI does the same.

Generated clients

The SDKs are generated from openapi.yaml with openapi-generator (run via Docker, so Docker must be running):

cd client
./generate-openapi.sh              # 1. refresh the schema
./generate-client-python.sh        # 2a. Python client  -> client/python/
./generate-client-typescript.sh    # 2b. TypeScript client -> client/typescript/

The CI regenerates and publishes both on release; you only need to run these locally when changing the API and testing a client against it.

Authors: ldeluigi