quickstart
graphql

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

KeyDefaultDescription
app.allowed-schemapublicPostgreSQL schema to expose (or MySQL database name)
app.database-typepostgresqlpostgresql or mysql
server.port10000HTTP 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