paradox-phoenix
Generate Phoenix applications with controller stubs and PostgreSQL backends from Paradox specifications — the Phoenix equivalent of paradox-express.
Define your types and URI endpoints in .dox, and paradox-phoenix generates a Phoenix project with stub controllers, Ecto schemas, database migrations, and optionally LiveView pages. You fill in the handler logic.
Usage
paradox-phoenix --title "My App" --uris createUser --uris listUsers --uris getUser
All flags:
| Flag | Default | Description |
|---|---|---|
|
(required) |
The name of your app (used as the Phoenix project name) |
|
(repeatable, required) |
URI constant name from the |
|
|
Port to run the Phoenix server on |
|
|
Also generate LiveView stub pages |
|
|
PostgreSQL connection URL |
Example
Given this .dox specification:
import std
type Pet
name: Text
species: Text
createPet: URI
http://localhost/pets POST (Pet. Pet)
getPet: URI
http://localhost/pets/${Integer} GET (Unit. Pet)
listPets: URI
http://localhost/pets GET (Unit. [Pet])
Run:
paradox-phoenix --title "PetShop" --uris createPet --uris getPet --uris listPets
This generates a Phoenix project at .dox/pet_shop/ with stub controllers you fill in.
How It Works
paradox-phoenix operates in six stages:
-
Generate specification — Runs
paradox generate --specto produce a JSON representation of the full.doxAST -
Generate Elixir modules — Runs
paradox generate --elixirto produce Elixir modules with types and validation functions -
Generate PostgreSQL DDL — Runs
paradox generate --postgresqlto produceCREATE TABLEstatements, concatenated intoschema.sql -
Scan Dox modules — Scans generated
.exfiles forvalid_<type>/1functions that can be bridged into Ecto changesets -
Resolve URIs — Looks up each
--urisname in the specification, extracts path, HTTP method, and input/output types -
Generate Phoenix project — Produces stub controllers, Ecto schemas (for URI-referenced types), router, migrations, and optionally LiveView pages
Generated Output
The generated project lives at .dox/<app_name>/:
.dox/<app_name>/
mix.exs
config/
config.exs
dev.exs
runtime.exs
lib/
<app_name>/
application.ex
repo.ex
schemas/
<type>.ex # Ecto schema for types in URI io fields
<app_name>_web/
router.ex # Routes from URI definitions
endpoint.ex
controllers/
<prefix>_controller.ex # Stub handlers grouped by path prefix
live/ # Only if --live
home_live.ex
<prefix>_live/
index.ex
components/ # Only if --live
core_components.ex
layouts.ex
dox/
*.ex # Copied Dox validation modules
priv/
repo/
migrations/
*_create_tables.exs
Stub Controllers
Each URI becomes a controller action with a 501 Not Implemented stub. Controllers are grouped by the first path segment:
defmodule PetShopWeb.PetsController do
use PetShopWeb, :controller
@doc "POST /pets\nInput: Pet, Output: Pet"
def create_pet(conn, _params) do
# TODO: Implement create_pet
conn
|> put_status(:not_implemented)
|> json(%{error: "create_pet not implemented"})
end
@doc "GET /pets/:integer\nOutput: Pet"
def get_pet(conn, %{"integer" => _integer}) do
# TODO: Implement get_pet
conn
|> put_status(:not_implemented)
|> json(%{error: "get_pet not implemented"})
end
end
Dox Validation Bridging
When a .dox specification defines valid rules for a type, paradox generate --elixir emits a valid_<type>/1 function in the corresponding Dox module. paradox-phoenix detects these functions and bridges them into Ecto changesets via a validate_with_dox/1 step:
-
After standard Ecto validations pass, the changeset fields are extracted into a Dox struct
-
The Dox
valid_<type>/1function is called -
If validation fails, error messages are split on
"; "and added to the changeset
See Also
-
Elixir Code Generation — The Elixir modules and validation functions used by the schemas
-
SQL Code Generation — The DDL that initializes the database
-
paradox-node — Node.js/Express equivalent with Pug templates
-
paradox-servant — Haskell Servant equivalent
-
paradox-express — Lighter-weight Express scaffold