Quick Start
Get a full GraphQL API running in under 2 minutes.
Prerequisites
- Docker and Docker Compose installed
Start with PostgreSQL
git clone https://github.com/excalibase/excalibase-graphql.git
cd excalibase-graphql
docker-compose up -d
This starts PostgreSQL, NATS, excalibase-watcher, the GraphQL server on port 10000, and GraphiQL on port 20000.
Open http://localhost:20000 for the GraphiQL playground, or send requests directly to http://localhost:10000/graphql.
Start with MySQL
docker-compose -f docker-compose.mysql.yml up -d
MySQL starts on the default port, GraphQL server on port 10001.
Your First Query
{
film(
where: { rating: { eq: "PG" } }
orderBy: { rental_rate: ASC }
limit: 5
) {
title
rental_rate
length
actor {
first_name
last_name
}
}
}
The actor field works automatically because film_actor links film and actor via foreign keys — no JOIN needed.
What Gets Generated
For every table, Excalibase generates a full set of operations. Given a table film:
type Query {
# List with filtering, ordering, pagination
film(where: FilmFilter, orderBy: FilmOrderBy, limit: Int, offset: Int): [Film]
# Cursor-based pagination (Relay-style connection)
filmConnection(first: Int, after: String): FilmConnection
# Aggregate functions (count, sum, avg, min, max)
film_aggregate(where: FilmFilter): FilmAggregate
}
type Mutation {
createFilm(input: FilmInput!): Film
updateFilm(input: FilmInput!): Film
deleteFilm(input: FilmPkInput!): Film
createManyFilms(inputs: [FilmInput!]!): [Film]
}
type Subscription {
# Real-time change events (via excalibase-watcher + NATS)
filmChanges: FilmChangeEvent
}
The filter input (FilmFilter) includes 15 operators per column — eq, neq, gt, lt, in, contains, isNull, and more. See Filtering for the full list.
CRUD Examples
Create
mutation {
createFilm(input: {
title: "The Excalibase Movie"
rental_rate: 2.99
rental_duration: 7
replacement_cost: 14.99
language_id: 1
}) {
film_id
title
}
}
Update
mutation {
updateFilm(input: {
film_id: 1001
rental_rate: 1.99
}) {
film_id
title
rental_rate
}
}
Delete
mutation {
deleteFilm(input: { film_id: 1001 }) {
film_id
title
}
}
Bulk Insert
mutation {
createManyFilms(inputs: [
{ title: "Film A", rental_rate: 0.99, rental_duration: 3, replacement_cost: 9.99, language_id: 1 }
{ title: "Film B", rental_rate: 4.99, rental_duration: 7, replacement_cost: 19.99, language_id: 1 }
]) {
film_id
title
}
}
Configuration
Docker / environment variables
SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/yourdb
SPRING_DATASOURCE_USERNAME=youruser
SPRING_DATASOURCE_PASSWORD=yourpass
APP_ALLOWED_SCHEMA=public
application.yaml
spring:
datasource:
url: jdbc:postgresql://localhost:5432/yourdb
username: youruser
password: yourpass
app:
allowed-schema: public
Configuration reference
| Key | Default | Description |
|---|---|---|
app.allowed-schema | public | PostgreSQL schema to expose (or MySQL database name) |
app.database-type | postgresql | postgresql or mysql |
server.port | 10000 | HTTP port |
All tables in allowed-schema are automatically exposed. There is no include/exclude list — control access at the database level with views or RLS policies.
Try the Playground
Want to explore a live schema without setting up a database?
→ Open Playground — pre-loaded with the DVD Rental schema