Skip to content

A demo application with Cloud Run, Cloud SQL and Cloud Pub/Sub, which has Restful APIs and Push notification by gRPC server-side streaming.

Notifications You must be signed in to change notification settings

kazshinohara/eats-api-demo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Eats API demo

A demo application inspired by *ber Eats with the following Google Cloud Products.

Technologies which this demo application uses.

Architecture

Diagram

architecture_diagram

Database schema

db_schema

How to use

1. Preparation

Set your preferred Google Cloud region name.

export REGION_NAME={{REGION_NAME}}

Set your Google Cloud Project ID

export PROJECT_ID={{PROJECT_ID}}

Set your Artifact Registry repository name

export REPO_NAME={{REPO_NAME}}

Set your Service Account name

export SA_NAME={{SERVICE_ACCOUNT_NAME}}

Set your DB instance name

export DB_INSTANCE_NAME={{DB_INSTANCE_NAME}}

Set your schema id

export SCHEMA_ID={{SCHEMA_ID}}

Set your Topic id

export TOPIC_ID={{TOPIC_ID}}

Set your Subscription id

export SUB_ID={{SUB_ID}}

Enable Google Cloud APIs

gcloud services enable \
  run.googleapis.com \
  sql-component.googleapis.com \
  sqladmin.googleapis.com \
  compute.googleapis.com \
  pubsub.googleapis.com \
  artifactregistry.googleapis.com \
  cloudbuild.googleapis.com

Set the project id into gcloud.

gcloud config set project $PROJECT_ID

Create a Service Account and give necessary roles to it.

gcloud iam service-accounts create ${SA_NAME}
gcloud projects add-iam-policy-binding ${PROJECT_ID} --member "serviceAccount:${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com" --role "roles/pubsub.publisher"
gcloud projects add-iam-policy-binding ${PROJECT_ID} --member "serviceAccount:${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com" --role "roles/pubsub.subscriber"

dd

gcloud projects add-iam-policy-binding ${PROJECT_ID} --member "serviceAccount:${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com" --role "roles/cloudsql.client"

2. Create a Cloud SQL instance

Create a MySQL DB Instance.

gcloud sql instances create ${DB_INSTANCE_NAME} --tier=db-custom-1-3840 --region=${REGION_NAME}

Confirm if you could create it.

gcloud sql instances list

Change the root user's password.

gcloud sql users set-password root \
--host="%" \
--instance=${DB_INSTANCE_NAME} \
--prompt-for-password

Connect to the DB instance with the root user.

gcloud sql connect ${DB_INSTANCE_NAME} --user=root

Create your database, the name must be "handson"

CREATE DATABASE handson;

Leave from the DB

QUIT;

Set DB related parameters as env vars.

export DB_USER=root
export DB_PWD={{DB_PASSWORD}}
export DB_INSTANCE=$(gcloud sql instances describe ${DB_INSTANCE_NAME} --format json | jq -r .connectionName)
export DB_CONNECTION="/cloudsql/"$(gcloud sql instances describe ${DB_INSTANCE_NAME} --format json | jq -r .connectionName)

3. Create Cloud Pub/Sub's schema, topic and subscription.

Create the message schema as Protocol buffer type.

gcloud beta pubsub schemas create ${SCHEMA_ID} \
--type=PROTOCOL_BUFFER \
--definition='syntax = "proto3";message ProtocolBuffer {string event_name = 1;string purchaser = 2;int64 order_id = 3;int64 item_id = 4;}'

Verify your schema.

gcloud beta pubsub schemas validate-message \
--message-encoding=JSON \
--message='{"event_name": "Order received", "purchaser": "Taro Yamada", "order_id": 1, "item_id": 1 }'  \
--schema-name=${SCHEMA_ID}                 

Create a topic with the schema.

gcloud beta pubsub topics create ${TOPIC_ID} \
--message-encoding=JSON \
--schema=${SCHEMA_ID}

Create a subscription.

gcloud pubsub subscriptions create ${SUB_ID} \
--topic=${TOPIC_ID}

4. Build container images

Note: please make your own Artifact Registry repo in advance, if you don't have it yet.

Create an Artifact Registry's repo.

gcloud artifacts repositories create ${REPO_NAME} --repository-format=docker --location=${REGION_NAME}

Git clone this repo to your local.

git clone git@github.com:kazshinohara/eats-api-demo.git

Build eats service image & Push it to Artifact Registry's repo by Cloud Build.

cd eats-api-demo/eats
gcloud builds submit --tag ${REGION_NAME}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/eats:v1

Build notification server image & Push it to Artifact Registry's repo by Cloud Build.

cd ../notification-server
gcloud builds submit --tag ${REGION_NAME}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/notification-server:v1

Build notification client image in your local.

cd ../notification-client
docker build -t ${REGION_NAME}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/notification-client:v1 .

5. Deploy containers to Cloud Run (fully managed)

Set Cloud Run's base configuration.

gcloud config set run/region ${REGION_NAME}
gcloud config set run/platform managed

Deploy Eats.

gcloud run deploy eats \
--image=${REGION_NAME}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/eats:v1 \
--allow-unauthenticated \
--set-env-vars=DB_PWD=${DB_PWD},DB_USER=${DB_USER},DB_CONNECTION=${DB_CONNECTION},PROJECT_ID=${PROJECT_ID},TOPIC_ID=${TOPIC_ID} \
--set-cloudsql-instances=${DB_INSTANCE} \
--service-account="${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"

Get Eats service's url for test access later.

export EATS_URL=$(gcloud run services describe eats --format json | jq -r '.status.address.url')

Deploy Notification server.

gcloud beta run deploy notification-server \
--image=${REGION_NAME}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/notification-server:v1 \
--allow-unauthenticated \
--use-http2 \
--timeout=3600 \
--set-env-vars=PROJECT_ID=${PROJECT_ID},SUB_ID=${SUB_ID} \
--service-account="${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"

Get domain name of Notification server for the client's access.

export NOTIFICATION_DOMAIN=$(gcloud run services describe notification-server --format json | jq -r '.status.address.url' | sed 's|https://||g')

6. Check behavior

Confirm if Eats service is alive.

curl -X GET ${EATS_URL}/ | jq
{"version":"v1","message":"This is Eats service API"}

Get items list, these items were automatically created in the db when eats service starts up.

curl -X GET ${EATS_URL}/items | jq
[
    {
        "ID":1,
        "CreatedAt":"2021-06-11T16:48:44.379Z",
        "UpdatedAt":"2021-06-11T16:48:44.379Z",
        "DeletedAt":null,
        "name":"Simple Pizza",
        "price":1000,
        "currency":"JPY"
    },
    {
        "ID":2,
        "CreatedAt":"2021-06-11T16:48:44.385Z",
        "UpdatedAt":"2021-06-11T16:48:44.385Z",
        "DeletedAt":null,
        "name":"Normal Pizza",
        "price":2000,
        "currency":"JPY"
    },
    {
        "ID":3,
        "CreatedAt":"2021-06-11T16:48:44.393Z",
        "UpdatedAt":"2021-06-11T16:48:44.393Z",
        "DeletedAt":null,
        "name":"Luxury Pizza",
        "price":3000,
        "currency":"JPY"
    }
]

Create an order.

curl -X POST -d '{"purchaser":"Taro Yamada","item_id":1}' ${EATS_URL}/orders | jq
{
    "ID":1,
    "CreatedAt":"2021-06-13T16:34:30.286Z",
    "UpdatedAt":"2021-06-13T16:34:30.286Z",
    "DeletedAt":null,"item_id":1,
    "purchaser":"Taro Yamada",
    "item_completed":false,
    "delivery_completed":false,
    "delivery_completed_at":null
}

Get orders list, you could see what you created in the earlier step.

curl -X GET ${EATS_URL}/orders | jq
{
    "ID":1,
    "CreatedAt":"2021-06-13T16:34:30.286Z",
    "UpdatedAt":"2021-06-13T16:34:30.286Z",
    "DeletedAt":null,"item_id":1,
    "purchaser":"Taro Yamada",
    "item_completed":false,
    "delivery_completed":false,
    "delivery_completed_at":null
}

Update your order changing item_completed flag to true.

curl -X PUT -d '{"purchaser":"Taro Yamada","item_id":1,"item_completed":true}' ${EATS_URL}/orders/1 | jq
{
    "ID":1,
    "CreatedAt":"2021-06-13T16:34:30.286Z",
    "UpdatedAt":"2021-06-13T17:10:53.908Z",
    "DeletedAt":null,
    "item_id":1,
    "purchaser":"Taro Yamada",
    "item_completed":true,
    "delivery_completed":false,
    "delivery_completed_at":null
}

Delete your order.

curl -X DELETE ${EATS_URL}/orders/1 | jq
{"id":"1","message":"deleted"}

Run Notification client in your local.

docker run --name notification-client -e INSECURE=false -e DOMAIN=${NOTIFICATION_DOMAIN} -e PORT=443 ${REGION_NAME}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/notification-client:v1

Create orders, recommend you to try creating 5 ~ 6 orders to get the notification quickly.

curl -X POST -d '{"purchaser":"Taro Yamada","item_id":1}' ${EATS_URL}/orders | jq

In your Notification client, you could see the following messages from Notification server.

2021/06/12 14:40:10 Subscribing...
2021/06/12 14:40:34 {"event_name":"Order received","purchaser":"Taro Yamada","order_id":2,"item_id":1}
2021/06/12 14:40:34 {"event_name":"Order received","purchaser":"Taro Yamada","order_id":3,"item_id":2}
2021/06/12 14:40:34 {"event_name":"Order received","purchaser":"Taro Yamada","order_id":4,"item_id":3}

Let's try Updating your order and confirm if the notification comes.

curl -X PUT -d '{"purchaser":"Taro Yamada","item_id":1,"item_completed":true}' ${EATS_URL}/orders/2 | jq

In your Notification client.

2021/06/13 17:10:47 {"event_name":"Order updated","purchaser":"Taro Yamada","order_id":2,"item_id":3}

About

A demo application with Cloud Run, Cloud SQL and Cloud Pub/Sub, which has Restful APIs and Push notification by gRPC server-side streaming.

Topics

Resources

Stars

Watchers

Forks