• Stars
    star
    458
  • Rank 95,591 (Top 2 %)
  • Language
    JavaScript
  • Created about 6 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Canonical example of building a 3factor app : a food ordering application

3Factor Canonical App

This is a canonical app for 3factor which showcases the three factors in detail with a reference implementation. The reference implementation is a food ordering app which has a user facing component (order-app) and an admin dashboard (analytics-app).

You can follow along this step-by-step guide to deploy and evaluate this application design pattern yourself.

What is a 3Factor App?

From 3factor.app :

Today, it is possible to build backends for apps that allow for fast iteration, while being resilient and highly scalable from the get go.

We propose an architecture pattern which is composed of 3 factors:

  1. Realtime GraphQL

  2. Reliable eventing

  3. Async serverless

Here is the high-level diagram comparing a traditional architecture vs a 3factor architecture:

3factor-migration

Step-by-Step Guide

Stack

NodeJS 8.1

Postgres 9.5+

Hasura GraphQL Engine

AWS Lambda

Step 1: Model application

The core modeling of a 3factor app is very similar to traditional application modeling: we start by defining the schema and then define different functional components. The main difference is that 3factor emphasizes that each function be atomic (i.e. either happens completely or doesn't happen at all) and invoked via (persisted) events.

Schema

The schema of our application is defined in schema.sql which you can apply on your postgres database.

$ export POSTGRES_CONNECTION_STRING='postgres://postgres:password@localhost:5432/postgres'

$ psql $POSTGRES_CONNECTION_STRING < schema.sql

In the above snippet, we are running a postgres database on localhost.

Functions

Next, let's design the order workflow and describe its functional components. The order workflow consists of all the steps from a user placing an order to delivery agent assignment for the order.

Order workflow: Login -> Place order -> Validate order -> Payment -> Restaurant approval -> Agent assignment

Let's describe these steps in detail:

  1. Login: A user enters the app using a username. For this demo, there is no authentication.

  2. Place order: The user selects food items and places an order.

  3. Validate order: As soon as an order is placed, it is validated in the backend.

  4. Payment: After the order is validated, user is requested for payment.

  5. Restaurant approval: After successful payment for the order, restaurant receives and approves the order.

  6. Agent assignment: After restaurant approves, an agent is assigned for delivery of the order.

Next, let's get into development.

Step 2: Setup a realtime GraphQL interface

3factor requires the frontend use GraphQL for querying and performing actions. The reason for this is two-fold: fast iteration and realtime feedback.

We will use Hasura to get GraphQL APIs over our existing postgres database. We will use Docker to run Hasura. If you do not have Docker, you can install it from here.

If you have a remote postgres database, run the following command:

$ docker run -d -p 8080:8080 \
  -e HASURA_GRAPHQL_DATABASE_URL=$POSTGRES_CONNECTION_STRING \
  -e HASURA_GRAPHQL_ENABLE_CONSOLE=true \
  hasura/graphql-engine:latest

If your postgres database is running on localhost, run the following command instead:

$ docker run -d --net=host \
  -e HASURA_GRAPHQL_DATABASE_URL=$POSTGRES_CONNECTION_STRING \
  -e HASURA_GRAPHQL_ENABLE_CONSOLE=true \
  hasura/graphql-engine:latest

Open the Hasura console by visiting http://localhost:8080/console. In the Data tab, you will see all the tables in our postgres database. Just track them all to get GraphQL APIs over them instantly:

track-all

Hasura will also detect relationships (via foreign-keys) automatically and you can track them as well to get GraphQL APIs over relationships:

track-all-relations

Step 3: Local development

Now, we can write our frontend using GraphQL APIs. We can perform the following actions directly via the frontend using authenticated GraphQL APIs:

  1. Login
  2. Place order

Refer to src/order-app-frontend for the frontend source code. Run the frontend app as follows:

$ cd src/order-app-frontend
$ npm install
$ npm start

We need to setup a development environment for our backend. We need to write backend logic for the following steps:

  1. Validate order: Source code: validate-order

  2. Payment: Source code: payment

  3. Restaurant approval: Source code: restaurant-approval

  4. Agent assignment: Source code: agent-assignment

For this purpose, we will run a node server with each of the above functions exposed as HTTP APIs as defined in src/backend/localDevelopment.js. Run the server and try these functions out:

$ cd src/backend
$ npm install
$ node localDevelopment.js

Output: server running on port 8081

In a different terminal:

$ curl -d '{"order_id": "abc-ad21-adf"}' -H 'Content-Type: application/json' localhost:8081/validate-order

Step 4: Setup event system

Now that we have our frontend components and backend components ready, it is time to glue everything together via events. The event system is at the center of 3factor architecture. The event system is what drives the entire workflow: from the frontend initiating the events to the backend triggering functions on emitted events.

The order workflow is initiated by the user creating an event (via an insert to the order table) and ends with the backend creating an event for agent assignment (via an update to the order table).

In the frontend, we will subscribe to the events on order table via realtime GraphQL and update the UI.

In the backend, we will use Hasura Event Triggers to invoke webhooks when events are emitted. The backend requires the following Event Triggers:

  1. validate-order: On insert of an order.
  2. restaurant-approval: On update of an order after successful payment.
  3. agent-assignment: On update of an order after restaurant approval.

Let's setup these triggers with our locally deployed functions: localDevelopment.js. We can do this either interactively via the Hasura console or through Hasura API. Run the following command to setup these event triggers via Hasura API:

$ curl -d @event-triggers.json -H 'Content-Type: application/json' localhost:8080/v1/query

Go back to the Hasura console at http://localhost:8080/console and in the Events tab you will see the newly created Event Triggers:

event-triggers

This finishes the entire development cycle on our local machine. You can start testing the app now.

Step 5: Use serverless functions

Now, that you have locally developed and tested your app. Let's deploy all these functions to AWS Lambda and update the Event Triggers from localhost HTTP APIs to Lambda APIs.

Serverless functions are a crucial component of 3factor as it provides infinite scale, no-ops and optimal cost.

To prepare our HTTP APIs for Lambda, we need to wrap the business logic in a Lambda "context". The Lambda context for validate-order is given in validate-order/lambdaCtx.js. Let's package this as a zip file and deploy to Lambda:

$ zip -r validate-order.zip validate-order/*

Do the same for the other Event Triggers.

There are many tutorials to deploy a NodeJS package on AWS Lambda with API Gateway for e.g. this. We will keep Lambda deployment out of the scope of this tutorial.

Assuming you have deployed your Lambda succesfully, you would have received an HTTP endpoint for it. Update your Event Triggers with the new endpoints through the Hasura console or Hasura API and that's it.

(Optional) Connection Pooling

The Lambda functions need database connections to execute their logic which cannot scale at the same rate as serverless invocations (as database connections are slow and costly). Hence, we need an external connection pooler to "loadbalance" the database connections.

With Postgres, we can add a standalone connection pooler like pgBouncer to accomplish this.

Follow the guide here to deploy pgBouncer in few clicks on a free EC2 instance using AWS Cloudformation. The output of the cloudformation template should give a new POSTGRES_CONNECTION_STRING which you can update in your Lambda to start using pgBouncer.

More Repositories

1

graphql-engine

Blazing fast, instant realtime GraphQL APIs on your DB with fine grained access control, also trigger webhooks on database events.
TypeScript
31,162
star
2

gitkube

Build and deploy docker images to Kubernetes using git push
Go
3,805
star
3

graphqurl

curl for GraphQL with autocomplete, subscriptions and GraphiQL. Also a dead-simple universal javascript GraphQL client.
JavaScript
3,339
star
4

skor

Now part of Hasura GraphQL Engine. Listen to postgres events and forward them as JSON payloads to a webhook
C
1,246
star
5

learn-graphql

Real world GraphQL tutorials for frontend developers with deadlines!
JavaScript
1,177
star
6

gatsby-gitbook-starter

Generate GitBook style modern docs/tutorial websites using Gatsby + MDX
JavaScript
985
star
7

awesome-react-graphql

A curated collection of resources, clients and tools that make working with `GraphQL and React/React Native` awesome
738
star
8

eff

🚧 a work in progress effect system for Haskell 🚧
Haskell
547
star
9

react-check-auth

Add auth protection anywhere in your react/react-native app
JavaScript
530
star
10

awesome-live-reloading

A curated collection of live-reloading / hot-reloading / watch-reloading tools for different languages and frameworks.
435
star
11

ra-data-hasura

react-admin data provider for Hasura GraphQL Engine
TypeScript
335
star
12

awesome-vue-graphql

A curated collection of resources, clients and tools that make working with `GraphQL and Vue.js` awesome
302
star
13

graphql-bench

A super simple tool to benchmark GraphQL queries
TSQL
263
star
14

hasura-ecommerce

TypeScript
246
star
15

pgdeltastream

Streaming Postgres logical replication changes atleast-once over websockets
Go
244
star
16

graphql-engine-heroku

Blazing fast, instant realtime GraphQL APIs on Postgres with fine grained access control, also trigger webhooks on database events.
Dockerfile
231
star
17

graphql2chartjs

graphql2chartjs reshapes your GraphQL data as per the ChartJS API.
JavaScript
222
star
18

hasura-aws-stack

A complete production ready 100% serverless stack on AWS with Hasura
JavaScript
215
star
19

json2graphql

From a JSON file to postgres-backed realtime GraphQL
JavaScript
200
star
20

3factor

3factor app is an architecture pattern for modern fullstack apps. 3factor apps are fast to build and are highly scalable.
SCSS
181
star
21

client-side-graphql

147
star
22

hasura-k8s-stack

A feature-complete Hasura stack on Kubernetes
JavaScript
138
star
23

hasura-actions-examples

Examples of handling custom business logic with Hasura Actions
JavaScript
135
star
24

awesome-angular-graphql

A curated collection of resources, clients and tools that make working with `GraphQL and Angular` awesome
132
star
25

gqless-movies-demo

A movies app using Hasura and gqless
TypeScript
127
star
26

awesome-fluent-graphql

Awesome list of fluent GraphQL clients & examples
TypeScript
106
star
27

graphiql-online

Explore your GraphQL APIs with headers
JavaScript
90
star
28

kubeformation

Create declarative cluster specifications for your managed Kubernetes vendor (GKE, AKS)
Go
86
star
29

data-dictionary

TypeScript
85
star
30

firebase2graphql

Move from Firebase realtime db to instant GraphQL APIs on Postgres
JavaScript
81
star
31

jwt-guide

TypeScript
79
star
32

nodejs-graphql-subscriptions-boilerplate

Boilerplate to setup GraphQL subscriptions in your nodejs code
JavaScript
78
star
33

pacha

Connect your private data to LLMs
PLpgSQL
74
star
34

graphql-serverless

Example boilerplates for GraphQL backends hosted on serverless platforms
Go
71
star
35

graphql-parser-hs

A GraphQL query parser for Haskell
Haskell
59
star
36

sphinx-graphiql

Sphinx plugin that adds a GraphiQL directive so that you can embed an interactive GraphQL query explorer in your docs
JavaScript
57
star
37

kriti-lang

A minimal JSON templating language
Haskell
55
star
38

schema-stitching-examples

JavaScript
44
star
39

gitkube-example

An example repo to be used with gitkube: git push to deploy on to Kubernetes
HTML
43
star
40

graphql-backend-benchmarks

GraphQL performance benchmarks across Hasura, Postgraphile and Prisma
Shell
42
star
41

comment-progress

Notify progress by commenting on GitHub issues, pull requests, and commits :octocat: 💬
JavaScript
42
star
42

local-development

[Deprecated] Run Hasura locally on your computer
37
star
43

rxdb-hasura-demo

An Offline first todo app
JavaScript
37
star
44

monad-validate

(NOTE: REPOSITORY MOVED TO NEW OWNER: https://github.com/lexi-lambda/monad-validate) A Haskell monad transformer library for data validation
Haskell
32
star
45

pod42

Python
31
star
46

gitlab-graphql

Install gitlab and expose the gitlab api's over GraphQL
JavaScript
29
star
47

codegen-assets

TypeScript
27
star
48

ndc-hub

Go
26
star
49

data-hub

Explore data sources from a native GraphQL API, database schemas to custom code contributed by the community.
PLpgSQL
26
star
50

pg-client-hs

A low level Haskell library to connect to postgres
Haskell
25
star
51

yelp-clone-react

A Yelp clone built using React + GraphQL + Hasura
JavaScript
24
star
52

github-integration-starter

Try out Hasura's GitHub Integration on Cloud Projects using the examples in this repo.
24
star
53

template-gallery

Repository containing schema sharing packages.
PLpgSQL
24
star
54

authz-workshop

TSQL
23
star
55

hasura-cloud-preview-apps

TypeScript
22
star
56

graphql-schema-stitching-demo

Schema Stitching Example with Hasura GraphQL + MetaWeather API
JavaScript
22
star
57

hasura-discord-docs-bot

PLpgSQL
21
star
58

ndc-typescript-deno

Instant Hasura Native Data Connector by writing Typescript Functions
TypeScript
21
star
59

ndc-spec

NDC Specification and Reference Implementation
Rust
20
star
60

issues

Dump and sync org wide issues into postgres and visualise with metabase.
Python
19
star
61

realm-pg-sync

The realm-pg-sync microservice
JavaScript
18
star
62

graphql-data-specification

A specification for Data APIs with GraphQL
Haskell
18
star
63

imad-app

Base repository for IMAD course application.
JavaScript
18
star
64

ndc-postgres

Hasura v3 Data Connector for PostgreSQL
Rust
18
star
65

react-apollo-todo

A todo app with react, apollo demonstrating graphql queries, mutations and subscriptions.
CSS
17
star
66

architect-graphql-workshop

JavaScript
16
star
67

continuous-backup

Postgres wal-e continuous backup system
Shell
16
star
68

preview-actions

Starter kit to try out actions
JavaScript
16
star
69

auth-ui-kit

Web UI Kit for Hasura Authentication
JavaScript
15
star
70

graphql-example-apps

PLpgSQL
14
star
71

smooth-checkout-buildkite-plugin

All the things you need during a Buildkite checkout 🧈 🪁
Shell
14
star
72

js-sdk

JavaScript
14
star
73

cloud-functions-boilerplates

Boilerplates for cloud functions (AWS Lambda, Google Cloud Functions, Azure Cloud Functions, Zeit, etc.) that work in conjunction with Hasura GraphQL Engine's event triggers
JavaScript
14
star
74

graphql-subscriptions-benchmark

TypeScript
13
star
75

sample-apps

TypeScript
12
star
76

demo-apps

Config to deploy Hasura demo apps using Docker Compose
HTML
12
star
77

github-bot

Hasura's own GitHub bot 🤖
JavaScript
11
star
78

generator-hasura-web

JavaScript
11
star
79

open-data-domain-specification

Rust
11
star
80

sqlite-dataconnector-agent

SQLite Data Connector Agent for Hasura GQL Engine. Please note that this repository is a mirror. We will still accept PRs, but will have to mirror them to our upstream repo.
TypeScript
11
star
81

ndc-sdk-typescript

NDC SDK for TypeScript
TypeScript
11
star
82

smooth-secrets-buildkite-plugin

A buildkite plugin to setup ssh keys and env secrets for your pipelines 🧈 🔒
Shell
11
star
83

chat-app-android

Java
10
star
84

custom-resolvers-boilerplate

A boilerplate for writing custom resolvers with Hasura GraphQL Engine
JavaScript
10
star
85

reactathon-workshop

10
star
86

go-buildkite-dsl

Write Buildkite configs in Go 🪁 📝
Go
9
star
87

android-sdk

The Android SDK for Hasura
Java
9
star
88

sample-auth-webhook

Sample auth webhooks for the Hasura GraphQL engine
JavaScript
9
star
89

generator-hasura-node

JavaScript
9
star
90

graphql-asia-workshop

JavaScript
9
star
91

supergraph-io

Content for the supergraph.io website
HTML
8
star
92

graphql-on-various-pg

Hasura's GraphQL engine on various Postgres systems/providers
Shell
8
star
93

cli-plugins-index

Shell
8
star
94

graphql-weather-api

A simple GraphQL express weather api server boilerplate
JavaScript
8
star
95

supergraph-top-n-challenge

JavaScript
8
star
96

ddn-sample-app

TypeScript
8
star
97

ndc-nodejs-lambda

Write NodeJS TypeScript functions and easily expose them in your Hasura DDN project
TypeScript
7
star
98

haskell-docker-builder

Package haskell binaries as docker images
Makefile
7
star
99

graphql-engine-install-manifests

Various installation manifests for Hasura's GraphQL Engine
Shell
7
star
100

laravel-todo-hge

A sample Laravel app with an auth webhook
PHP
7
star