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
{
publicFilm(
where: { rating: { eq: "PG" } }
orderBy: { rental_rate: ASC }
limit: 5
) {
title
rental_rate
length
publicActor {
first_name
last_name
}
}
}
The publicActor field works automatically because film_actor links film and actor via foreign keys — no JOIN needed.
Schema prefix convention: All GraphQL types and fields are prefixed with the schema name. Since the default PostgreSQL schema is
public, the prefix ispublic— e.g.,filmbecomespublicFilm,FilmbecomesPublicFilm. For MySQL, the prefix is the database name.
What Gets Generated
For every table, Excalibase generates a full set of operations. Given a table film:
type Query {
# List with filtering, ordering, pagination
publicFilm(where: PublicFilmFilter, orderBy: PublicFilmOrderBy, limit: Int, offset: Int): [PublicFilm]
# Cursor-based pagination (Relay-style connection)
publicFilmConnection(first: Int, after: String): PublicFilmConnection
# Aggregate functions (count, sum, avg, min, max)
publicFilmAggregate(where: PublicFilmFilter): PublicFilmAggregate
}
type Mutation {
createPublicFilm(input: PublicFilmInput!): PublicFilm
updatePublicFilm(input: PublicFilmInput!): PublicFilm
deletePublicFilm(input: PublicFilmPkInput!): PublicFilm
createManyPublicFilm(inputs: [PublicFilmInput!]!): [PublicFilm]
}
type Subscription {
# Real-time change events (via excalibase-watcher + NATS)
publicFilmChanges: PublicFilmChangeEvent
}
The filter input (PublicFilmFilter) includes 15 operators per column — eq, neq, gt, lt, in, contains, isNull, and more. See Filtering for the full list.
CRUD Examples
Create
mutation {
createPublicFilm(input: {
title: "The Excalibase Movie"
rental_rate: 2.99
rental_duration: 7
replacement_cost: 14.99
language_id: 1
}) {
film_id
title
}
}
Update
mutation {
updatePublicFilm(input: {
film_id: 1001
rental_rate: 1.99
}) {
film_id
title
rental_rate
}
}
Delete
mutation {
deletePublicFilm(input: { film_id: 1001 }) {
film_id
title
}
}
Bulk Insert
mutation {
createManyPublicFilm(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_SCHEMAS=public
application.yaml
spring:
datasource:
url: jdbc:postgresql://localhost:5432/yourdb
username: youruser
password: yourpass
app:
schemas: public
Configuration reference
| Key | Default | Description |
|---|---|---|
app.schemas | public | Comma-separated list of schemas to expose, or ALL for auto-discovery |
app.database-type | postgresql | postgresql or mysql |
server.port | 10000 | HTTP port |
All tables in the configured schemas 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