mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-14 17:02:49 +03:00
This PR re-writes the README for serverless triggers on Zeit Now. `zeit-serverless-docker` have been renamed to `zeit-now`. Echo and mutation examples for Go and NodeJS are added.
This commit is contained in:
parent
f40da07aaa
commit
d2dfe7b026
@ -10,7 +10,7 @@ Examples in this repository support the following cloud function platforms:
|
||||
|
||||
* Microsoft Azure Functions
|
||||
|
||||
* Zeit serverless docker
|
||||
* Zeit Now
|
||||
|
||||
Note: *If you want to add support for other platforms, please submit a PR or create an issue and tag it with `help-wanted`*
|
||||
|
||||
|
@ -0,0 +1,37 @@
|
||||
# Event trigger boilerplates on Zeit Now
|
||||
|
||||
Contributions are welcome for boilerplates in other languages.
|
||||
|
||||
### Setup Hasura GraphQL Engine
|
||||
|
||||
Click on the following button to deploy GraphQL Engine on Heroku with the free Postgres add-on:
|
||||
|
||||
[![Deploy to Heroku](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/hasura/graphql-engine-heroku)
|
||||
|
||||
Checkout [docs](https://docs.hasura.io/1.0/graphql/manual/deployment/index.html) for other deployment options.
|
||||
|
||||
|
||||
### Setup `now`
|
||||
|
||||
1. Create a Zeit account @ https://zeit.co/
|
||||
2. Download [now cli](https://zeit.co/download#now-cli):
|
||||
```bash
|
||||
npm install -g now
|
||||
```
|
||||
3. Login to `now`:
|
||||
```bash
|
||||
now login
|
||||
```
|
||||
|
||||
### Setup and deploy the trigger
|
||||
|
||||
Checkout any of the example triggers given below for further steps:
|
||||
|
||||
- [NodeJS Echo](nodejs/echo)
|
||||
- [NodeJS Mutation](nodejs/mutation)
|
||||
- [Go Echo](go/echo)
|
||||
- [Go Mutation](go/mutation)
|
||||
<!--
|
||||
- [Python 3 Echo](python/echo)
|
||||
- [Python 3 Mutation](python/mutation)
|
||||
-->
|
@ -0,0 +1,2 @@
|
||||
*
|
||||
!main.go
|
@ -0,0 +1,8 @@
|
||||
FROM golang:1.11-alpine as base
|
||||
WORKDIR /usr/src
|
||||
COPY . .
|
||||
RUN CGO_ENABLED=0 go build -ldflags "-s -w" -o main
|
||||
|
||||
FROM scratch
|
||||
COPY --from=base /usr/src/main /go-http-microservice
|
||||
CMD ["/go-http-microservice"]
|
@ -0,0 +1,101 @@
|
||||
# Go Echo on Zeit
|
||||
|
||||
If you haven't already, follow the first part of instructions [here](../../).
|
||||
|
||||
This is an example which echoes the event back, written in Golang.
|
||||
|
||||
### Create a table
|
||||
|
||||
Visit the GraphQL Engine URL to open console.
|
||||
|
||||
Goto `Data` tab.
|
||||
|
||||
Create the following table:
|
||||
|
||||
```
|
||||
Table name: note
|
||||
|
||||
Columns:
|
||||
|
||||
id Integer auto-increment
|
||||
note Text
|
||||
|
||||
Primary key: id
|
||||
```
|
||||
|
||||
### Deploy the function
|
||||
|
||||
Execute `now` in this directory:
|
||||
|
||||
```bash
|
||||
now
|
||||
```
|
||||
|
||||
Once the deployment is done, you'll get an endpoint like
|
||||
`https://zeit-echo-hhasdewasd.now.sh`. Not this down as `NOW_URL`.
|
||||
|
||||
> **Note**: Now.sh deployments are immutable, i.e. each time you deploy the
|
||||
> code, a new URL will be provisioned. You can [alias the
|
||||
> deployment](https://zeit.co/docs/getting-started/assign-a-domain-name#1.-using-a-now.sh-domain)
|
||||
> to keep a constant URL.
|
||||
|
||||
### Create the trigger
|
||||
|
||||
Goto Hasura console, `Events` tab and create a new trigger:
|
||||
|
||||
```
|
||||
Trigger name: note_trigger
|
||||
|
||||
Schema/Table: public/note
|
||||
|
||||
Operations: Insert, Update, Delete
|
||||
|
||||
Webhook URL: NOW_URL
|
||||
```
|
||||
|
||||
Replace `NOW_URL` with the URL noted earlier.
|
||||
|
||||
|
||||
### Test the trigger
|
||||
|
||||
Goto `Data` tab on Hasura console, browse to `note` table and insert a new row.
|
||||
Once a new row is inserted, goto `Events` table and `note_trigger`. Checkout the
|
||||
request and response body for the processed events.
|
||||
|
||||
Trigger payload (request):
|
||||
```json
|
||||
{
|
||||
"event": {
|
||||
"op": "INSERT",
|
||||
"data": {
|
||||
"old": null,
|
||||
"new": {
|
||||
"text": "new-entry",
|
||||
"id": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"created_at": "2018-10-01T17:21:03.76895Z",
|
||||
"id": "b30cc7e6-9f3b-48ee-9a10-16cce333df40",
|
||||
"trigger": {
|
||||
"name": "note_trigger",
|
||||
"id": "551bd6a9-6f8b-4644-ba7f-80c08eb9227b"
|
||||
},
|
||||
"table": {
|
||||
"schema": "public",
|
||||
"name": "note"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Webhook response:
|
||||
```json
|
||||
{
|
||||
"message": "got 'b30cc7e6-9f3b-48ee-9a10-16cce333df40' for 'INSERT' operation on 'note' table in 'public' schema from 'note_trigger' trigger",
|
||||
"oldData": null,
|
||||
"newData": {
|
||||
"text": "new-entry",
|
||||
"id": 1
|
||||
}
|
||||
}
|
||||
```
|
@ -0,0 +1,69 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type HasuraEvent struct {
|
||||
ID string `json:"id"`
|
||||
Event `json:"event"`
|
||||
Table `json:"table"`
|
||||
Trigger `json:"trigger"`
|
||||
}
|
||||
|
||||
type Event struct {
|
||||
Op string `json:"op"`
|
||||
Data `json:"data"`
|
||||
}
|
||||
|
||||
type Data struct {
|
||||
Old map[string]interface{} `json:"old"`
|
||||
New map[string]interface{} `json:"new"`
|
||||
}
|
||||
|
||||
type Table struct {
|
||||
Name string `json:"name"`
|
||||
Schema string `json:"schema"`
|
||||
}
|
||||
|
||||
type Trigger struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
Message string `json:"message"`
|
||||
OldData map[string]interface{} `json:"oldData"`
|
||||
NewData map[string]interface{} `json:"newData"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
var event HasuraEvent
|
||||
err := decoder.Decode(&event)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
response := Response{
|
||||
Message: fmt.Sprintf(
|
||||
"got '%s' for '%s' operation on '%s' table in '%s' schema from '%s' trigger",
|
||||
event.ID,
|
||||
event.Event.Op,
|
||||
event.Table.Name,
|
||||
event.Table.Schema,
|
||||
event.Trigger.Name,
|
||||
),
|
||||
OldData: event.Data.Old,
|
||||
NewData: event.Data.New,
|
||||
}
|
||||
err = json.NewEncoder(w).Encode(response)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
})
|
||||
http.ListenAndServe(":3000", nil)
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "zeit-echo",
|
||||
"features": {
|
||||
"cloud": "v2"
|
||||
}
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
*
|
||||
!main.go
|
@ -0,0 +1,9 @@
|
||||
FROM golang:1.11-alpine as base
|
||||
WORKDIR /usr/src
|
||||
COPY . .
|
||||
RUN CGO_ENABLED=0 go build -ldflags "-s -w" -o main
|
||||
|
||||
FROM alpine:3.8
|
||||
RUN apk add --no-cache ca-certificates
|
||||
COPY --from=base /usr/src/main /go-http-microservice
|
||||
CMD ["/go-http-microservice"]
|
@ -0,0 +1,118 @@
|
||||
# Golang Mutation Example on Zeit
|
||||
|
||||
If you haven't already, follow the first part of instructions [here](../../).
|
||||
|
||||
This example trigger updates (executes a mutation) when an event occurs on
|
||||
another table, written in Golang.
|
||||
|
||||
### Create tables
|
||||
|
||||
```
|
||||
Table name: note
|
||||
|
||||
Columns:
|
||||
|
||||
id Integer auto-increment
|
||||
note Text
|
||||
|
||||
Primary key: id
|
||||
```
|
||||
|
||||
```
|
||||
Table name: note_revision
|
||||
|
||||
Columns:
|
||||
|
||||
id Integer auto-increment
|
||||
note Text
|
||||
note_id Integer
|
||||
update_at Timestamp, default: now()
|
||||
|
||||
Primary key: id
|
||||
```
|
||||
|
||||
### Deploy the function
|
||||
|
||||
Execute `now` in this directory with an env var required for the code to execute
|
||||
a mutation:
|
||||
|
||||
```bash
|
||||
now -e HGE_ENDPOINT=https://my-app.herokuapp.com/v1alpha1/graphql
|
||||
```
|
||||
|
||||
`HGE_ENDPOINT` is the Hasura GraphQL Engine endpoint.
|
||||
|
||||
Once the deployment is done, you'll get an endpoint like
|
||||
`https://zeit-mutation-hhasdewasd.now.sh`. Not this down as `NOW_URL`.
|
||||
|
||||
> **Note**: Now.sh deployments are immutable, i.e. each time you deploy the
|
||||
> code, a new URL will be provisioned. You can [alias the
|
||||
> deployment](https://zeit.co/docs/getting-started/assign-a-domain-name#1.-using-a-now.sh-domain)
|
||||
> to keep a constant URL.
|
||||
|
||||
### Create the trigger
|
||||
|
||||
Goto Hasura console, `Events` tab and create a new trigger:
|
||||
|
||||
```
|
||||
Trigger name: note_revision_trigger
|
||||
|
||||
Schema/Table: public/note
|
||||
|
||||
Operations: Update
|
||||
|
||||
Webhook URL: NOW_URL
|
||||
```
|
||||
|
||||
Replace `NOW_URL` with the URL noted earlier.
|
||||
|
||||
### Test the trigger
|
||||
|
||||
Goto `Data` tab on Hasura console, browse to `note` table and to the Browse rows
|
||||
tab. Edit an existing note and check if the `note_revision` entry has been
|
||||
created. Also, checkout the trigger request and response.
|
||||
|
||||
Trigger payload (request):
|
||||
```json
|
||||
{
|
||||
"event": {
|
||||
"op": "UPDATE",
|
||||
"data": {
|
||||
"old": {
|
||||
"note": "note1",
|
||||
"id": 1
|
||||
},
|
||||
"new": {
|
||||
"note": "note1 updated",
|
||||
"id": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"created_at": "2018-10-02T06:38:22.67311Z",
|
||||
"id": "f57a1c79-72ba-4c19-8791-37d1b9616bcf",
|
||||
"trigger": {
|
||||
"name": "note_revision_trigger",
|
||||
"id": "5d85cbd1-c134-45ce-810c-7ecd3b4fc1ee"
|
||||
},
|
||||
"table": {
|
||||
"schema": "public",
|
||||
"name": "note"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Webhook response:
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"insert_note_revision": {
|
||||
"affected_rows": 1,
|
||||
"returning": [
|
||||
{
|
||||
"id": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
@ -0,0 +1,101 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
type HasuraEvent struct {
|
||||
ID string `json:"id"`
|
||||
Event `json:"event"`
|
||||
Table `json:"table"`
|
||||
Trigger `json:"trigger"`
|
||||
}
|
||||
|
||||
type Event struct {
|
||||
Op string `json:"op"`
|
||||
Data `json:"data"`
|
||||
}
|
||||
|
||||
type Data struct {
|
||||
Old map[string]interface{} `json:"old"`
|
||||
New map[string]interface{} `json:"new"`
|
||||
}
|
||||
|
||||
type Table struct {
|
||||
Name string `json:"name"`
|
||||
Schema string `json:"schema"`
|
||||
}
|
||||
|
||||
type Trigger struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
const MUTATION_UPDATE_NOTE_REVISION = `
|
||||
mutation updateNoteRevision ($object: note_revision_insert_input!) {
|
||||
insert_note_revision (objects: [$object]) {
|
||||
affected_rows
|
||||
returning {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
func main() {
|
||||
var HGE_ENDPOINT = os.Getenv("HGE_ENDPOINT")
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
var event HasuraEvent
|
||||
err := decoder.Decode(&event)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
note_id, ok := event.Data.Old["id"]
|
||||
if !ok {
|
||||
http.Error(w, "invalid payload: note id not found", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
note, ok := event.Data.New["note"]
|
||||
if !ok {
|
||||
http.Error(w, "invalid payload: note not found", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// execute the mutation
|
||||
payload := map[string]interface{}{
|
||||
"query": MUTATION_UPDATE_NOTE_REVISION,
|
||||
"variables": map[string]interface{}{
|
||||
"object": map[string]interface{}{
|
||||
"note_id": note_id.(float64),
|
||||
"note": note.(string),
|
||||
},
|
||||
},
|
||||
}
|
||||
b := new(bytes.Buffer)
|
||||
json.NewEncoder(b).Encode(payload)
|
||||
res, err := http.Post(HGE_ENDPOINT, "application/json; charset=utf-8", b)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer res.Body.Close()
|
||||
var response map[string]interface{}
|
||||
|
||||
err = json.NewDecoder(res.Body).Decode(&response)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
err = json.NewEncoder(w).Encode(response)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
})
|
||||
http.ListenAndServe(":3000", nil)
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "zeit-mutation",
|
||||
"features": {
|
||||
"cloud": "v2"
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
# NodeJS Echo Example on Zeit
|
||||
|
||||
If you haven't already, follow the first part of instructions [here](../../).
|
||||
|
||||
This is an example which echoes the event back, written in NodeJS.
|
||||
|
||||
### Create a table
|
||||
|
||||
Visit the GraphQL Engine URL to open console.
|
||||
|
||||
Goto `Data` tab.
|
||||
|
||||
Create the following table:
|
||||
|
||||
```
|
||||
Table name: note
|
||||
|
||||
Columns:
|
||||
|
||||
id Integer auto-increment
|
||||
note Text
|
||||
|
||||
Primary key: id
|
||||
```
|
||||
|
||||
### Deploy the function
|
||||
|
||||
Execute `now` in this directory:
|
||||
|
||||
```bash
|
||||
now
|
||||
```
|
||||
|
||||
Once the deployment is done, you'll get an endpoint like
|
||||
`https://zeit-echo-hhasdewasd.now.sh`. Not this down as `NOW_URL`.
|
||||
|
||||
> **Note**: Now.sh deployments are immutable, i.e. each time you deploy the
|
||||
> code, a new URL will be provisioned. You can [alias the
|
||||
> deployment](https://zeit.co/docs/getting-started/assign-a-domain-name#1.-using-a-now.sh-domain)
|
||||
> to keep a constant URL.
|
||||
|
||||
### Create the trigger
|
||||
|
||||
Goto Hasura console, `Events` tab and create a new trigger:
|
||||
|
||||
```
|
||||
Trigger name: note_trigger
|
||||
|
||||
Schema/Table: public/note
|
||||
|
||||
Operations: Insert, Update, Delete
|
||||
|
||||
Webhook URL: NOW_URL
|
||||
```
|
||||
|
||||
Replace `NOW_URL` with the URL noted earlier.
|
||||
|
||||
|
||||
### Test the trigger
|
||||
|
||||
Goto `Data` tab on Hasura console, browse to `note` table and insert a new row.
|
||||
Once a new row is inserted, goto `Events` table and `note_trigger`. Checkout the
|
||||
request and response body for the processed events.
|
||||
|
||||
Trigger payload (request):
|
||||
```json
|
||||
{
|
||||
"event": {
|
||||
"op": "INSERT",
|
||||
"data": {
|
||||
"old": null,
|
||||
"new": {
|
||||
"text": "new-entry",
|
||||
"id": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"created_at": "2018-10-01T17:21:03.76895Z",
|
||||
"id": "b30cc7e6-9f3b-48ee-9a10-16cce333df40",
|
||||
"trigger": {
|
||||
"name": "note_trigger",
|
||||
"id": "551bd6a9-6f8b-4644-ba7f-80c08eb9227b"
|
||||
},
|
||||
"table": {
|
||||
"schema": "public",
|
||||
"name": "note"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Webhook response:
|
||||
```json
|
||||
{
|
||||
"message": "received 'b30cc7e6-9f3b-48ee-9a10-16cce333df40' for 'INSERT' operation on 'note' table in 'public' schema from 'note_trigger' trigger",
|
||||
"oldData": null,
|
||||
"newData": {
|
||||
"text": "new-entry",
|
||||
"id": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -0,0 +1,19 @@
|
||||
const { json, send } = require('micro');
|
||||
|
||||
module.exports = async (req, res) => {
|
||||
let payload;
|
||||
try {
|
||||
payload = await json(req);
|
||||
} catch (error) {
|
||||
send(res, 400, { error });
|
||||
return;
|
||||
}
|
||||
|
||||
const { id, event: {op, data}, table, trigger } = payload;
|
||||
|
||||
send(res, 200, {
|
||||
message: `received '${id}' for '${op}' operation on '${table.name}' table in '${table.schema}' schema from '${trigger.name}' trigger`,
|
||||
oldData: data.old,
|
||||
newData: data.new,
|
||||
});
|
||||
};
|
@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "zeit-echo",
|
||||
"dependencies": {
|
||||
"micro": "9.3.3"
|
||||
},
|
||||
"license": "MIT",
|
||||
"main": "./index.js",
|
||||
"scripts": {
|
||||
"start": "micro"
|
||||
}
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
# NodeJS Mutation Example on Zeit
|
||||
|
||||
If you haven't already, follow the first part of instructions [here](../../).
|
||||
|
||||
This example trigger updates (executes a mutation) when an event occurs on
|
||||
another table, written in NodeJS.
|
||||
|
||||
### Create tables
|
||||
|
||||
```
|
||||
Table name: note
|
||||
|
||||
Columns:
|
||||
|
||||
id Integer auto-increment
|
||||
note Text
|
||||
|
||||
Primary key: id
|
||||
```
|
||||
|
||||
```
|
||||
Table name: note_revision
|
||||
|
||||
Columns:
|
||||
|
||||
id Integer auto-increment
|
||||
note Text
|
||||
note_id Integer
|
||||
update_at Timestamp, default: now()
|
||||
|
||||
Primary key: id
|
||||
```
|
||||
|
||||
### Deploy the function
|
||||
|
||||
Execute `now` in this directory with an env var required for the code to execute
|
||||
a mutation:
|
||||
|
||||
```bash
|
||||
now -e HGE_ENDPOINT=https://my-app.herokuapp.com/v1alpha1/graphql
|
||||
```
|
||||
|
||||
`HGE_ENDPOINT` is the Hasura GraphQL Engine endpoint.
|
||||
|
||||
Once the deployment is done, you'll get an endpoint like
|
||||
`https://zeit-mutation-hhasdewasd.now.sh`. Not this down as `NOW_URL`.
|
||||
|
||||
> **Note**: Now.sh deployments are immutable, i.e. each time you deploy the
|
||||
> code, a new URL will be provisioned. You can [alias the
|
||||
> deployment](https://zeit.co/docs/getting-started/assign-a-domain-name#1.-using-a-now.sh-domain)
|
||||
> to keep a constant URL.
|
||||
|
||||
### Create the trigger
|
||||
|
||||
Goto Hasura console, `Events` tab and create a new trigger:
|
||||
|
||||
```
|
||||
Trigger name: note_revision_trigger
|
||||
|
||||
Schema/Table: public/note
|
||||
|
||||
Operations: Update
|
||||
|
||||
Webhook URL: NOW_URL
|
||||
```
|
||||
|
||||
Replace `NOW_URL` with the URL noted earlier.
|
||||
|
||||
### Test the trigger
|
||||
|
||||
Goto `Data` tab on Hasura console, browse to `note` table and to the Browse rows
|
||||
tab. Edit an existing note and check if the `note_revision` entry has been
|
||||
created. Also, checkout the trigger request and response.
|
||||
|
||||
Trigger payload (request):
|
||||
```json
|
||||
{
|
||||
"event": {
|
||||
"op": "UPDATE",
|
||||
"data": {
|
||||
"old": {
|
||||
"note": "note1",
|
||||
"id": 1
|
||||
},
|
||||
"new": {
|
||||
"note": "note1 updated",
|
||||
"id": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"created_at": "2018-10-02T06:38:22.67311Z",
|
||||
"id": "f57a1c79-72ba-4c19-8791-37d1b9616bcf",
|
||||
"trigger": {
|
||||
"name": "note_revision_trigger",
|
||||
"id": "5d85cbd1-c134-45ce-810c-7ecd3b4fc1ee"
|
||||
},
|
||||
"table": {
|
||||
"schema": "public",
|
||||
"name": "note"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Webhook response:
|
||||
```json
|
||||
{
|
||||
"result": {
|
||||
"data": {
|
||||
"insert_note_revision": {
|
||||
"returning": [
|
||||
{
|
||||
"__typename": "note_revision",
|
||||
"id": 1
|
||||
}
|
||||
],
|
||||
"affected_rows": 1,
|
||||
"__typename": "note_revision_mutation_response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
@ -0,0 +1,42 @@
|
||||
const {json, send} = require('micro');
|
||||
const { query } = require('graphqurl');
|
||||
|
||||
const HGE_ENDPOINT = process.env.HGE_ENDPOINT;
|
||||
|
||||
const MUTATION_UPDATE_NOTE_REVISION = `
|
||||
mutation updateNoteRevision ($object: note_revision_insert_input!) {
|
||||
insert_note_revision (objects: [$object]) {
|
||||
affected_rows
|
||||
returning {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
module.exports = async (req, res) => {
|
||||
let payload;
|
||||
try {
|
||||
payload = await json(req);
|
||||
} catch (error) {
|
||||
send(res, 400, { error });
|
||||
return;
|
||||
}
|
||||
|
||||
const { id, event: {op, data}, table, trigger } = payload;
|
||||
|
||||
try {
|
||||
const result = await query({
|
||||
query: MUTATION_UPDATE_NOTE_REVISION,
|
||||
endpoint: HGE_ENDPOINT,
|
||||
variables: {
|
||||
object: {
|
||||
note_id: data.old.id, note: data.new.note
|
||||
}
|
||||
},
|
||||
});
|
||||
send(res, 200, { result });
|
||||
} catch (error) {
|
||||
send(res, 500, { error });
|
||||
}
|
||||
};
|
@ -1,9 +1,12 @@
|
||||
{
|
||||
"name": "hge-events-zeit-node-echo",
|
||||
"name": "zeit-mutation",
|
||||
"dependencies": {
|
||||
"graphqurl": "^0.3.1",
|
||||
"micro": "9.3.3"
|
||||
},
|
||||
"license": "MIT",
|
||||
"main": "./index.js"
|
||||
"main": "./index.js",
|
||||
"scripts": {
|
||||
"start": "micro"
|
||||
}
|
||||
}
|
@ -1,13 +1 @@
|
||||
# Boilerplates for Zeit Serverless Docker functions and Hasura GraphQL Engine's Event Triggers
|
||||
|
||||
**NOTE**
|
||||
Some of the language/platforms are work in progress. We welcome contributions for the WIP langauages. See issues.
|
||||
|
||||
# Pre-requisite:
|
||||
|
||||
1. Running instance of Hasura GraphQL engine
|
||||
|
||||
# Setup `now` cli
|
||||
1. Create zeit account @ https://zeit.co/
|
||||
2. Download now cli from https://zeit.co/download#now-cli
|
||||
3. Login using now Login
|
||||
Moved to [zeit-now](../zeit-now)
|
||||
|
@ -1,5 +0,0 @@
|
||||
FROM node:10-alpine
|
||||
COPY package.json package-lock.json ./
|
||||
RUN npm ci
|
||||
COPY index.js .
|
||||
CMD ["node", "node_modules/.bin/micro"]
|
@ -1,22 +0,0 @@
|
||||
# Setup our tables
|
||||
|
||||
Create table using the console:
|
||||
|
||||
```
|
||||
Table name: notes
|
||||
|
||||
Columns:
|
||||
id: Integer auto-increment
|
||||
note: Text
|
||||
```
|
||||
|
||||
# Setup echo serverless function
|
||||
1. cd echo
|
||||
2. edit now.json to change app and alias name (Note: alias will be the domain for example setting alias to hge-events-zeit-node-echo will provide hge-events-zeit-node-echo.now.sh)
|
||||
3. Deploy the function by running `now && now alias && now remove <app-name> --safe -y`
|
||||
|
||||
# Add events in Hasura GraphQL
|
||||
|
||||
1. In events tab, add a trigger
|
||||
2. Select all insert, update, delete operations for the trigger.
|
||||
3. Paste the API endpoint as the webhook.
|
@ -1,21 +0,0 @@
|
||||
const {json, send} = require('micro');
|
||||
|
||||
module.exports = async (req, res) => {
|
||||
let js;
|
||||
try {
|
||||
js = await json(req);
|
||||
} catch (err) {
|
||||
send(res, 400, {'error': err.message});
|
||||
}
|
||||
let message = 'Not able to process request';
|
||||
|
||||
if (js.event.op == 'INSERT' && js.table.name == 'notes') {
|
||||
message = `New note ${js.event.data.new.id} inserted, with data: ${js.event.data.new.note}`;
|
||||
} else if (js.event.op == 'UPDATE' && js.table.name == 'notes') {
|
||||
message = `note ${js.event.data.new.id} updated, with data: ${js.event.data.new.note}`;
|
||||
} else if (js.event.op == 'DELETE' && js.table.name == 'notes') {
|
||||
message = `New note ${js.event.data.old.id} deleted, with data: ${js.event.data.old.note}`;
|
||||
}
|
||||
|
||||
send(res, 200, {'message': message});
|
||||
};
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"public": true,
|
||||
"type": "docker",
|
||||
"features": {
|
||||
"cloud": "v2"
|
||||
},
|
||||
"alias": "hge-events-zeit-node-echo",
|
||||
"name": "hge-events-zeit-node-echo"
|
||||
}
|
@ -1,145 +0,0 @@
|
||||
{
|
||||
"name": "hge-events-zeit-node",
|
||||
"requires": true,
|
||||
"lockfileVersion": 1,
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"requires": {
|
||||
"color-convert": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"arg": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/arg/-/arg-2.0.0.tgz",
|
||||
"integrity": "sha512-XxNTUzKnz1ctK3ZIcI2XUPlD96wbHP2nGqkPKpvk/HNRlPveYrXIVSTk9m3LcqOgDPg3B1nMvdV/K8wZd7PG4w=="
|
||||
},
|
||||
"bytes": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
|
||||
"integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
|
||||
},
|
||||
"chalk": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.0.tgz",
|
||||
"integrity": "sha512-Wr/w0f4o9LuE7K53cD0qmbAMM+2XNLzR29vFn5hqko4sxGlUsyy363NvmyGIyk5tpe9cjTr9SJYbysEyPkRnFw==",
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"requires": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
|
||||
},
|
||||
"content-type": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
|
||||
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
|
||||
},
|
||||
"depd": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz",
|
||||
"integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k="
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
|
||||
},
|
||||
"http-errors": {
|
||||
"version": "1.6.2",
|
||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz",
|
||||
"integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=",
|
||||
"requires": {
|
||||
"depd": "1.1.1",
|
||||
"inherits": "2.0.3",
|
||||
"setprototypeof": "1.0.3",
|
||||
"statuses": ">= 1.3.1 < 2"
|
||||
}
|
||||
},
|
||||
"iconv-lite": {
|
||||
"version": "0.4.19",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
|
||||
"integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ=="
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
|
||||
},
|
||||
"is-stream": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
|
||||
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
|
||||
},
|
||||
"micro": {
|
||||
"version": "9.3.3",
|
||||
"resolved": "https://registry.npmjs.org/micro/-/micro-9.3.3.tgz",
|
||||
"integrity": "sha512-GbCp4NFQguARch0odX+BuWDja2Kc1pbYZqWfRvEDihGFTJG8U77C0L+Owg2j7TPyhQ5Tc+7z/SxspRqjdiZCjQ==",
|
||||
"requires": {
|
||||
"arg": "2.0.0",
|
||||
"chalk": "2.4.0",
|
||||
"content-type": "1.0.4",
|
||||
"is-stream": "1.1.0",
|
||||
"raw-body": "2.3.2"
|
||||
}
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.2.0.tgz",
|
||||
"integrity": "sha512-OayFWziIxiHY8bCUyLX6sTpDH8Jsbp4FfYd1j1f7vZyfgkcOnAyM4oQR16f8a0s7Gl/viMGRey8eScYk4V4EZA=="
|
||||
},
|
||||
"raw-body": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz",
|
||||
"integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=",
|
||||
"requires": {
|
||||
"bytes": "3.0.0",
|
||||
"http-errors": "1.6.2",
|
||||
"iconv-lite": "0.4.19",
|
||||
"unpipe": "1.0.0"
|
||||
}
|
||||
},
|
||||
"setprototypeof": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz",
|
||||
"integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ="
|
||||
},
|
||||
"statuses": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
|
||||
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"unpipe": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
{
|
||||
"name": "hge-events-zeit-node-echo",
|
||||
"dependencies": {
|
||||
"micro": "9.3.3"
|
||||
},
|
||||
"license": "MIT",
|
||||
"main": "./index.js"
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
FROM node:10-alpine
|
||||
COPY package.json package-lock.json ./
|
||||
RUN npm ci
|
||||
COPY index.js .
|
||||
CMD ["node", "node_modules/.bin/micro"]
|
@ -1,30 +0,0 @@
|
||||
# Setup our tables
|
||||
|
||||
Create table using the console:
|
||||
|
||||
```
|
||||
Table name: notes
|
||||
|
||||
Columns:
|
||||
id: Integer auto-increment
|
||||
note: Text
|
||||
|
||||
Table name: note_revision
|
||||
|
||||
Columns:
|
||||
id: Integer auto-increment
|
||||
note: Text
|
||||
note_id: Integer (foreign key to notes.id)
|
||||
update_at: Timestamp, default `now()`
|
||||
```
|
||||
|
||||
# Setup echo serverless function
|
||||
1. cd echo
|
||||
2. edit now.json to change app and alias name (Note: alias will be the domain for example setting alias to hge-events-zeit-node-echo will provide hge-events-zeit-node-echo.now.sh)
|
||||
3. Deploy the function by running `now && now alias && now remove <app-name> --safe -y`
|
||||
|
||||
# Add events in Hasura GraphQL
|
||||
|
||||
1. In events tab, add a trigger
|
||||
2. Select all insert, update, delete operations for the trigger.
|
||||
3. Paste the API endpoint as the webhook.
|
@ -1,43 +0,0 @@
|
||||
const {json, send} = require('micro');
|
||||
const { query } = require('graphqurl');
|
||||
|
||||
const accessKey = process.env.ACCESS_KEY;
|
||||
const hgeEndpoint = process.env.HGE_ENDPOINT + '/v1alpha1/graphql';
|
||||
|
||||
const q = `
|
||||
mutation updateNoteRevision ($noteId: Int!, $data: String!) {
|
||||
insert_note_revisions (objects: [
|
||||
{
|
||||
note_id: $noteId,
|
||||
updated_note: $data
|
||||
}
|
||||
]) {
|
||||
affected_rows
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
module.exports = async (req, res) => {
|
||||
let js;
|
||||
try {
|
||||
js = await json(req);
|
||||
} catch (err) {
|
||||
send(res, 400, {'error': err.message});
|
||||
}
|
||||
query(
|
||||
{
|
||||
query: q,
|
||||
endpoint: hgeEndpoint,
|
||||
variables: {noteId: js.event.data.old.id, data: js.event.data.old.note},
|
||||
headers: {
|
||||
'x-hasura-access-key': accessKey,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
).then((response) => {
|
||||
console.log(response);
|
||||
send(res, 200, {'message': response});
|
||||
}).catch((error) => {
|
||||
send(res, 400, {'message': error});
|
||||
});
|
||||
};
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"public": true,
|
||||
"type": "docker",
|
||||
"features": {
|
||||
"cloud": "v2"
|
||||
},
|
||||
"alias": "hge-events-zeit-node-mutation",
|
||||
"name": "hge-events-zeit-node-mutation"
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user