Skip to content

Qimia/fastGQL

Repository files navigation

fastGQL

Realtime GraphQL on PostgreSQL / MySQL

About

This project exposes PostgreSQL / MySQL through GraphQL API, with built-in authorization engine. Inspired by Hasura.

This is alpha-version, with some features still in development:

  • basic operations
    • query
    • mutate
      • insert
      • update
    • delete
    • subscription
  • JWT authentication
  • JWT authorization
    • query
    • mutate
    • delete
    • subscription
  • authorization engine configured with groovy DSL
    • role-based column access
    • role-based and content-based row access
  • user-defined filtering via GraphQL arguments
    • where
    • order by
    • limit
    • offset

Example

Database

CREATE TABLE addresses(
  id INT PRIMARY KEY,
  street VARCHAR(255)
);

CREATE TABLE customers(
  id INT PRIMARY KEY,
  name VARCHAR(255),
  address INT REFERENCES addresses(id)
);

INSERT INTO addresses VALUES (0, 'Danes Hill');
INSERT INTO addresses VALUES (1, 'Rangewood Road');
INSERT INTO customers VALUES (0, 'Stacey', 0);
INSERT INTO customers VALUES (1, 'John', 0);
INSERT INTO customers VALUES (2, 'Daniele', 1);

Simple query

Permissions JWT token data
permissions {
  role ('default') {
    table ('customers') {
      ops ([select]) {
          allow 'id', 'name', 'address'
      }
    }
    table ('addresses') {
      ops ([select]) {
          allow 'id', 'street'
      }
    }
  }
}
{
  "role": "default"
}
Query Response
query {
  customers {
    id
    name
    address
    address_ref {
      id
      street
      customers_on_address {
        id
      }
    }
  }
}
{
  "data": {
    "customers": [
      {
        "id": 0,
        "name": "Stacey",
        "address": 0,
        "address_ref": {
          "id": 0,
          "street": "Danes Hill",
          "customers_on_address": [
            {
              "id": 0
            },
            {
              "id": 1
            }
          ]
        }
      },
      {
        "id": 1,
        "name": "John",
        "address": 0,
        "address_ref": {
          "id": 0,
          "street": "Danes Hill",
          "customers_on_address": [
            {
              "id": 0
            },
            {
              "id": 1
            }
          ]
        }
      },
      {
        "id": 2,
        "name": "Daniele",
        "address": 1,
        "address_ref": {
          "id": 1,
          "street": "Rangewood Road",
          "customers_on_address": [
            {
              "id": 2
            }
          ]
        }
      }
    ]
  }
}

Query with arguments

Permissions JWT token data
permissions {
  role ('default') {
    table ('customers') {
      ops ([select]) {
          allow 'id', 'name', 'address'
      }
    }
    table ('addresses') {
      ops ([select]) {
          allow 'id', 'street'
      }
    }
  }
}
{
  "role": "default"
}
Query Response
query {
  customers (
    where:{
      name:{_in:["John", "Daniele"]},
      _or:[
        {id:{_eq:3}},
        {address:{_lt:10}}
      ]
    },
    order_by:{address_ref:{street:desc}}
  ) {
    id
    name
    address
    address_ref {
      id
      street
      customers_on_address (limit:1) {
        id
      }
    }
  }
}
{
  "data": {
    "customers": [
      {
        "id": 2,
        "name": "Daniele",
        "address": 1,
        "address_ref": {
          "id": 1,
          "street": "Rangewood Road",
          "customers_on_address": [
            {
              "id": 2
            }
          ]
        }
      },
      {
        "id": 1,
        "name": "John",
        "address": 0,
        "address_ref": {
          "id": 0,
          "street": "Danes Hill",
          "customers_on_address": [
            {
              "id": 0
            }
          ]
        }
      }
    ]
  }
}

Query with row access restrictions

{ it.id } in this example is a closure which accepts JWT token data, it is equivalent to Java lambda:

@FunctionalInterface
interface ValueGetter {
  Object getValue(Map<String, Object> jwtData);
}

class C {
  ValueGetter valueGetter = it -> it.get("id");
}
Permissions JWT token data
permissions {
  role ('default') {
    table ('customers') {
      ops ([select]) {
          allow 'id', 'name', 'address'
          check 'id' eq { it.id }
      }
    }
    table ('addresses') {
      ops ([select]) {
          allow 'id', 'street'
      }
    }
  }
}
{
  "role": "default",
  "id": 0
}
Query Response
query {
  customers {
    id
    name
    address_ref {
      customers_on_address {
        id
      }
    }
  }
}
{
  "data": {
    "customers": [
      {
        "id": 0,
        "name": "Stacey",
        "address_ref": {
          "customers_on_address": [
            {
              "id": 0
            }
          ]
        }
      }
    ]
  }
}

Mutation with preset and validity check

Permissions JWT token data
permissions {
  role ('default') {
    table ('customers') {
      ops ([select]) {
          allow 'id', 'name', 'address'
          check 'id' eq { it.id }
      }
      ops ([insert]) {
          allow 'name', 'address'
          preset 'id' to { it.id }
          check 'address' lt 100
      }
    }
  }
}
{
  "role": "default",
  "id": 3
}
Mutation Response
mutation {
  insert_customers (
    objects:{
      name:"Oscar",
      address:0
    }
  ) {
    affected_rows
  }
}
{
  "data": {
    "insert_customers": {
      "affected_rows": 1
    }
  }
}
Query Response
query {
  customers {
    id
    name
    address
  }
}
{
  "data": {
    "customers": [
      {
        "id": 3,
        "name": "Oscar",
        "address": 0
      }
    ]
  }
}

Building and running

Development

Start Postgres container:

scripts/start_postgres.sh

Start FastGQL in dev mode with hot reload:

./gradlew vertxRun

Go to localhost:8080/graphiql/ or query localhost:8080/graphql

Production

Build production bundle:

./gradlew installDist

Execute production version:

build/install/fastgql/bin/fastgql run --conf src/main/resources/conf-postgres.json dev.fastgql.FastGQL

About

Realtime GraphQL on PostgreSQL / MySQL

Resources

License

Stars

1 star

Watchers

3 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages