diff --git a/community/boilerplates/event-triggers/aws-lambda/java/echo/README.md b/community/boilerplates/event-triggers/aws-lambda/java/echo/README.md new file mode 100644 index 00000000000..32a7f56e2bc --- /dev/null +++ b/community/boilerplates/event-triggers/aws-lambda/java/echo/README.md @@ -0,0 +1,30 @@ +# Setup tables +1. Create table: + +``` +notes: + id: int + note: text +``` + +# Setup AWS Lambda +Create a lambda function in AWS. This will be our webhook. + +1. Create a function. +2. Select Java 8 as the runtime. +3. Select "start from scratch". +4. Add API gateway as a trigger. +5. Add an API to API gateway. +6. Edit the code in the `handleRequest` method in `/src/main/java/example/Hello.java`. + +# Deploy AWS Lambda + +1. In terminal go into project: `cd community/boilerplates/serverless-triggers/aws-lambda/java/echo` +2. Build deployment package: `mvn package` +2. Upload `target/java-lambda-1.0-SNAPSHOT.jar` using AWS console. + + +# Add the trigger 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 of your AWS lambda as the webhook. diff --git a/community/boilerplates/event-triggers/aws-lambda/java/echo/pom.xml b/community/boilerplates/event-triggers/aws-lambda/java/echo/pom.xml new file mode 100644 index 00000000000..3448e0185c0 --- /dev/null +++ b/community/boilerplates/event-triggers/aws-lambda/java/echo/pom.xml @@ -0,0 +1,65 @@ + + 4.0.0 + + io.hasura.serverless + java-lambda + jar + 1.0-SNAPSHOT + Java Lambda + + + + com.amazonaws + aws-lambda-java-core + 1.2.0 + + + com.jayway.jsonpath + json-path + 2.4.0 + + + org.slf4j + slf4j-nop + 1.7.25 + + + + org.junit.jupiter + junit-jupiter-api + 5.1.0 + test + + + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.2.0 + + false + + + + package + + shade + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + + + \ No newline at end of file diff --git a/community/boilerplates/event-triggers/aws-lambda/java/echo/src/main/java/example/Hello.java b/community/boilerplates/event-triggers/aws-lambda/java/echo/src/main/java/example/Hello.java new file mode 100644 index 00000000000..1bdbdb082b9 --- /dev/null +++ b/community/boilerplates/event-triggers/aws-lambda/java/echo/src/main/java/example/Hello.java @@ -0,0 +1,48 @@ +package example; + +import java.util.HashMap; +import java.util.Map; + +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.RequestHandler; +import com.jayway.jsonpath.DocumentContext; +import com.jayway.jsonpath.JsonPath; + +public class Hello implements RequestHandler, Map> { + + private static final int INTERNAL_SERVER_ERROR = 500; + private final Notebook notebook; + + public Hello() { + this.notebook = new Notebook(); + } + + @Override + public Map handleRequest(Map request, Context context) { + context.getLogger().log(request.toString()); + Map response = new HashMap<>(); + response.put("isBase64Encoded", false); + try { + String requestBody = (String) request.get("body"); + response.put("body", handleRequestBody(requestBody)); + response.put("statusCode", 200); + } catch (Exception e) { + response.put("body", e.toString()); + response.put("statusCode", INTERNAL_SERVER_ERROR); + } + return response; + } + + private String handleRequestBody(String requestBody) { + DocumentContext body = JsonPath.parse(requestBody); + String table = body.read("$.table.name"); + if (table != null && table.equals("notes")) { + Notebook.Operation operation = Notebook.Operation.valueOf(body.read("$.event.op")); + Note newNote = body.read("$.event.data.new", Note.class); + Note oldNote = body.read("$.event.data.old", Note.class); + return notebook.handleOperation(operation, newNote, oldNote); + } else { + throw new UnsupportedOperationException("table: " + table); + } + } +} \ No newline at end of file diff --git a/community/boilerplates/event-triggers/aws-lambda/java/echo/src/main/java/example/Note.java b/community/boilerplates/event-triggers/aws-lambda/java/echo/src/main/java/example/Note.java new file mode 100644 index 00000000000..c0096b9b892 --- /dev/null +++ b/community/boilerplates/event-triggers/aws-lambda/java/echo/src/main/java/example/Note.java @@ -0,0 +1,23 @@ +package example; + +class Note { + + private Integer id; + private String note; + + Integer getId() { + return id; + } + + void setId(Integer id) { + this.id = id; + } + + String getNote() { + return note; + } + + void setNote(String note) { + this.note = note; + } +} diff --git a/community/boilerplates/event-triggers/aws-lambda/java/echo/src/main/java/example/Notebook.java b/community/boilerplates/event-triggers/aws-lambda/java/echo/src/main/java/example/Notebook.java new file mode 100644 index 00000000000..2be0574444c --- /dev/null +++ b/community/boilerplates/event-triggers/aws-lambda/java/echo/src/main/java/example/Notebook.java @@ -0,0 +1,22 @@ +package example; + +class Notebook { + + enum Operation { + INSERT, UPDATE, DELETE; + } + + String handleOperation(Operation operation, Note newNote, Note oldNote) { + switch (operation) { + case INSERT: + return "New note " + newNote.getId() + " inserted, with data: " + newNote.getNote(); + case UPDATE: + return "Note " + newNote.getId() + " updated, with data: " + newNote.getNote(); + case DELETE: + return "Note " + oldNote.getId() + " deleted, with data: " + oldNote.getNote(); + default: + throw new UnsupportedOperationException("operation: " + operation); + } + } + +} diff --git a/community/boilerplates/event-triggers/aws-lambda/java/echo/src/test/java/example/ContextStub.java b/community/boilerplates/event-triggers/aws-lambda/java/echo/src/test/java/example/ContextStub.java new file mode 100644 index 00000000000..6e16e229d83 --- /dev/null +++ b/community/boilerplates/event-triggers/aws-lambda/java/echo/src/test/java/example/ContextStub.java @@ -0,0 +1,74 @@ +package example; + +import com.amazonaws.services.lambda.runtime.ClientContext; +import com.amazonaws.services.lambda.runtime.CognitoIdentity; +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.LambdaLogger; + +public class ContextStub implements Context { + + @Override + public LambdaLogger getLogger() { + return new LambdaLogger() { + @Override + public void log(String s) { + System.out.println(s); + } + + @Override + public void log(byte[] bytes) { + log(new String(bytes)); + } + }; + } + + @Override + public String getAwsRequestId() { + return null; + } + + @Override + public String getLogGroupName() { + return null; + } + + @Override + public String getLogStreamName() { + return null; + } + + @Override + public String getFunctionName() { + return null; + } + + @Override + public String getFunctionVersion() { + return null; + } + + @Override + public String getInvokedFunctionArn() { + return null; + } + + @Override + public CognitoIdentity getIdentity() { + return null; + } + + @Override + public ClientContext getClientContext() { + return null; + } + + @Override + public int getRemainingTimeInMillis() { + return -1; + } + + @Override + public int getMemoryLimitInMB() { + return -1; + } +} diff --git a/community/boilerplates/event-triggers/aws-lambda/java/echo/src/test/java/example/HelloTest.java b/community/boilerplates/event-triggers/aws-lambda/java/echo/src/test/java/example/HelloTest.java new file mode 100644 index 00000000000..aea37398a98 --- /dev/null +++ b/community/boilerplates/event-triggers/aws-lambda/java/echo/src/test/java/example/HelloTest.java @@ -0,0 +1,35 @@ +package example; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class HelloTest { + + @Test + void handleRequestDelete() throws IOException { + Map request = new HashMap<>(); + request.put("body", loadResource("delete.json")); + + Map response = new Hello().handleRequest(request, new ContextStub()); + + assertEquals(200, response.get("statusCode")); + assertEquals("Note 1 deleted, with data: a", response.get("body")); + } + + private String loadResource(String name) { + return new BufferedReader(new InputStreamReader( + ClassLoader.getSystemResourceAsStream(name) + )) + .lines() + .collect(Collectors.joining("\n")); + } + +} \ No newline at end of file diff --git a/community/boilerplates/event-triggers/aws-lambda/java/echo/src/test/resources/delete.json b/community/boilerplates/event-triggers/aws-lambda/java/echo/src/test/resources/delete.json new file mode 100644 index 00000000000..00267e7ba9a --- /dev/null +++ b/community/boilerplates/event-triggers/aws-lambda/java/echo/src/test/resources/delete.json @@ -0,0 +1,18 @@ +{ + "table": { + "name": "notes" + }, + "event": { + "op": "DELETE", + "data": { + "new": { + "id": 2, + "note": "b" + }, + "old": { + "id": 1, + "note": "a" + } + } + } +} \ No newline at end of file