Skip to content

Rapidly build your API by just describing it.

Frontend developers, write your backend API servers yourself!
No need to write resolver functions or even know SQL.

“When compliance and cyber security are a requirement, basebox is a very good choice.”

Prof. Dr. Christian Johner
Johner Institut

“With basebox, our backend was ready faster than the frontend.”

Anina Langhans
LipoCheck

3 Simple Steps

Step #1

Describe your data.

Write a simple GraphQL schema doc to describe your data, e.g. object types, their properties, and their relations to each other. basebox' compiler writes the SQL statements to create the database. No need to know SQL!

See the Docs
You provide a type definition:
graphql
# The user type.
type User @bb_user {
  username: String! @bb_primaryKey
  name: String
}

# UserInput definition; standard GraphQL
input UserInput {
  username: String!
  name: String
}
# The user type.
type User @bb_user {
  username: String! @bb_primaryKey
  name: String
}

# UserInput definition; standard GraphQL
input UserInput {
  username: String!
  name: String
}
... and basebox creates this SQL script for you:
sql
-- This creates a table for the User type
CREATE TABLE "User" (
  "username" VARCHAR NOT NULL,
  "name" VARCHAR 
);
-- This creates a table for the User type
CREATE TABLE "User" (
  "username" VARCHAR NOT NULL,
  "name" VARCHAR 
);
This is how you describe a relation between types:
graphql
# The user type. Now owner of lists.
type User @bb_user {
  username: String! @bb_primaryKey
  name: String
}

# Each task is owned by a user.
type Task @bb_owned {
  id: ID!
  title: String!
  description: String,
  completed: Boolean!
  user: User!
}
# The user type. Now owner of lists.
type User @bb_user {
  username: String! @bb_primaryKey
  name: String
}

# Each task is owned by a user.
type Task @bb_owned {
  id: ID!
  title: String!
  description: String,
  completed: Boolean!
  user: User!
}
... and basebox implements the relation in for you:
sql
-- This creates a table for the `User` type.
CREATE TABLE "User" (
  "username" VARCHAR NOT NULL,
  "name" VARCHAR 
);

-- The `List` table, relating to its owner.
CREATE TABLE "List" (
  "id" UUID DEFAULT gen_random_uuid() NOT NULL,
  "title" VARCHAR NOT NULL,
  "user_username" VARCHAR NOT NULL 
);
-- This creates a table for the `User` type.
CREATE TABLE "User" (
  "username" VARCHAR NOT NULL,
  "name" VARCHAR 
);

-- The `List` table, relating to its owner.
CREATE TABLE "List" (
  "id" UUID DEFAULT gen_random_uuid() NOT NULL,
  "title" VARCHAR NOT NULL,
  "user_username" VARCHAR NOT NULL 
);

Step #2

Describe your operations.

Define allowed operations in your schema doc and annotate them with simple basebox specific directives to describe the data to read or write. Again, no need to know SQL!

See the Docs
Your annotated operation definition:
graphql
type Mutation {
  # Operation to create a task
  createTask(
    title: String!,
    completed: Boolean!, 
    user: UserInput! 
  ): Task 
    # Tell basebox how to create a task - that's it
    @bb_resolver(
      _type: INSERT, 
      _object: Task, 
      _fields: { 
        title: "$title", 
        completed: "$completed", 
        user: { username: "$user.$username" } 
      }
    )
}
type Mutation {
  # Operation to create a task
  createTask(
    title: String!,
    completed: Boolean!, 
    user: UserInput! 
  ): Task 
    # Tell basebox how to create a task - that's it
    @bb_resolver(
      _type: INSERT, 
      _object: Task, 
      _fields: { 
        title: "$title", 
        completed: "$completed", 
        user: { username: "$user.$username" } 
      }
    )
}
... and an example request you send to basebox:
graphql
createTask(
  "Buy dog food",
  "false",
  user: {
    username: "Freddy56"
  }
)
createTask(
  "Buy dog food",
  "false",
  user: {
    username: "Freddy56"
  }
)
No need to write a resolver function!
Operation definition for getting a user:
graphql
type Query {

  getUser(
    username: String!
  ): User 
    @bb_resolver(
      _type: SELECT, 
      _object: User, 
      _filter: { 
        username: { 
          _eq: "$username" 
      } 
    }
  )
}
type Query {

  getUser(
    username: String!
  ): User 
    @bb_resolver(
      _type: SELECT, 
      _object: User, 
      _filter: { 
        username: { 
          _eq: "$username" 
      } 
    }
  )
}
A simple request returns a user and all his/her tasks:
graphql
query {
  getUser(username: "4a21520d...") {
    name
    tasks {
      id
      title
      completed
    }
  }
}
query {
  getUser(username: "4a21520d...") {
    name
    tasks {
      id
      title
      completed
    }
  }
}
Again: no need to write a resolver!
Define how to update a task:
graphql
type Mutation {

  updateTask(
    id: ID!,
    title: String,
    completed: Boolean,
  ): Task 
    @bb_resolver(
      _type: UPDATE, 
      _object: Task, 
      _filter: { id: { _eq: "$id" } }, 
      _fields: { 
        title: "$title", 
        completed: "$completed", 
      }
    )
}
type Mutation {

  updateTask(
    id: ID!,
    title: String,
    completed: Boolean,
  ): Task 
    @bb_resolver(
      _type: UPDATE, 
      _object: Task, 
      _filter: { id: { _eq: "$id" } }, 
      _fields: { 
        title: "$title", 
        completed: "$completed", 
      }
    )
}
Your request to update a task:
graphql
mutation {
  updateTask(
    id: "45673-...",
    title: "Buy lots of dog food!!",
    completed: "false",
  ) {
    id
  }
}
mutation {
  updateTask(
    id: "45673-...",
    title: "Buy lots of dog food!!",
    completed: "false",
  ) {
    id
  }
}
Remember: no need to write a resolver!
Define how to delete a task:
graphql
type Mutation {

  deleteTask(id: ID!): Task 
    @bb_resolver(
      _type: DELETE, 
      _object: Task, 
      _filter: { 
        id: { 
          _eq: "$id" 
        }
      }
    )

}
type Mutation {

  deleteTask(id: ID!): Task 
    @bb_resolver(
      _type: DELETE, 
      _object: Task, 
      _filter: { 
        id: { 
          _eq: "$id" 
        }
      }
    )

}
Your request to delete a task:
graphql
mutation {
  deleteTask(id: "49586-...") {
    id
  }
}
mutation {
  deleteTask(id: "49586-...") {
    id
  }
}
Still: no need to write a resolver!

Step #3

Compile your schema.

Run bbc, the basebox compiler, to compile your schema. This will create a complete SQL script to initialize your database and a set of files that basebox later uses to compile your requests into SQL as you send them.

See the Docs
Compile your schema file:
sh
# Run basebox' compiler:
bbc --prefix=bb_todo -f
basebox compiler (bbc) version 1.0.0
  Writing output files to '/home/username/basebox/schema'
    Data model: 'bb_todo-datamodel.sql'
    Resolver:   'bb_todo-resolver.toml'
    Type map:   'bb_todo-typemap.json'
Done.
# Run basebox' compiler:
bbc --prefix=bb_todo -f
basebox compiler (bbc) version 1.0.0
  Writing output files to '/home/username/basebox/schema'
    Data model: 'bb_todo-datamodel.sql'
    Resolver:   'bb_todo-resolver.toml'
    Type map:   'bb_todo-typemap.json'
Done.
... and your backend is ready to go!
This is how you describe a relation between types:
graphql
# The user type. Now owner of lists.
type User @bb_user {
  username: String! @bb_primaryKey
  name: String
}

# Each task is owned by a user.
type Task @bb_owned {
  id: ID!
  title: String!
  description: String,
  completed: Boolean!
  user: User!
}
# The user type. Now owner of lists.
type User @bb_user {
  username: String! @bb_primaryKey
  name: String
}

# Each task is owned by a user.
type Task @bb_owned {
  id: ID!
  title: String!
  description: String,
  completed: Boolean!
  user: User!
}
... and basebox implements the relation in for you:
sql
-- This creates a table for the `User` type.
CREATE TABLE "User" (
  "username" VARCHAR NOT NULL,
  "name" VARCHAR 
);

-- The `List` table, relating to its owner.
CREATE TABLE "List" (
  "id" UUID DEFAULT gen_random_uuid() NOT NULL,
  "title" VARCHAR NOT NULL,
  "user_username" VARCHAR NOT NULL 
);
-- This creates a table for the `User` type.
CREATE TABLE "User" (
  "username" VARCHAR NOT NULL,
  "name" VARCHAR 
);

-- The `List` table, relating to its owner.
CREATE TABLE "List" (
  "id" UUID DEFAULT gen_random_uuid() NOT NULL,
  "title" VARCHAR NOT NULL,
  "user_username" VARCHAR NOT NULL 
);