Realtime GraphQL on PostgreSQL / MySQL
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
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);
| 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
}
]
}
}
]
}
} |
| 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
}
]
}
}
]
}
} |
{ 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
}
]
}
}
]
}
} |
| 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
}
]
}
} |
Start Postgres container:
scripts/start_postgres.shStart FastGQL in dev mode with hot reload:
./gradlew vertxRunGo to localhost:8080/graphiql/ or query localhost:8080/graphql
Build production bundle:
./gradlew installDistExecute production version:
build/install/fastgql/bin/fastgql run --conf src/main/resources/conf-postgres.json dev.fastgql.FastGQL