RESTful API for interacting with me programmatically!
Build & run locally (http://localhost:80)
Note
This approach is the quickest way to get everything up and running. However, services are deployed differently than when deployed into GCP so use this as a quick way to build & test functionality.
$ ./init_env.sh
- Fill out all the details for your local database (replace examples in brackets):
# Shared environment variables for ./api-app, ./webhook-app, ./reverse-proxy, and ./db
ENVIRONMENT=[development]
# ReadMe.io API key secret
README_API_KEY=[""] # Get from https://dash.readme.com/project/api-davidchang-dev/ > Developer Dashboard > Set Up API Keys
# Database auth/connection variables
DB_USER=[root]
DB_PASSWORD=[password]
DB_NAME=[db]
DB_CONNECTION_NAME=$DB_CONTAINER_NAME:$MYSQL_CONTAINER_PORT
DB_CONNECTION_STRING="$DB_USER:$DB_PASSWORD@tcp($DB_CONNECTION_NAME)/$DB_NAME?charset=utf8&parseTime=True&loc=Local"
# Docker variables
## Network
NETWORK_NAME=[api-bridge]
## Database (built with MySQL locally and Cloud SQL in GCP)
DB_IMAGE_NAME=[mysql-db-image]
DB_CONTAINER_NAME=[db]
DB_HOST_PORT="3306" # Must match db/Dockerfile
DB_CONTAINER_PORT="3306" # Must match db/Dockerfile
## API Provider (built with Go)
API_IMAGE_NAME=[go-app-image]
API_CONTAINER_NAME=[api-app]
API_HOST_PORT="8080" # Must match api-app/Dockerfile
API_CONTAINER_PORT="8080" # Must match api-app/Dockerfile
## Webhook Provider (built with NodeJS)
WEBHOOK_IMAGE_NAME=[nodejs-app-image]
WEBHOOK_CONTAINER_NAME=[webhook-app]
WEBHOOK_HOST_PORT="8000" # Must match webhook-app/Dockerfile
WEBHOOK_CONTAINER_PORT="8000" # Must match webhook-app/Dockerfile
## Reverse Proxy (built with Nginx locally and Cloud Endpoints in GCP)
REVERSE_PROXY_IMAGE_NAME=[nginx-server-image]
REVERSE_PROXY_CONTAINER_NAME=[reverse-proxy]
REVERSE_PROXY_HOST_PORT="80" # Must match reverse-proxy/Dockerfile
REVERSE_PROXY_CONTAINER_PORT="80" # Must match reverse-proxy/Dockerfile
- Propagate environments to application and database
$ ./propagate_env.sh
- Generate the db/init.sql file
$ cd db
$ ./init.sh
- Build
$ docker compose build
- Run
$ docker compose up
- Tear down
$ docker compose down
Note
Deploying testing locally uses MySQL as a database and Nginx as a reverse-proxy. Deploying to GCP will use other services such as Cloud SQL and Cloud Endpoints respectively instead. This will require the need to be able to build and deploy each of these services individually to be compatible with the production environment.
$ ./init_env.sh
- Fill out all the details for your local database (replace examples in brackets):
# Shared environment variables for ./api-app, ./webhook-app, ./reverse-proxy, and ./db
ENVIRONMENT=[development]
# ReadMe.io API key secret
README_API_KEY=[""] # Get from https://dash.readme.com/project/api-davidchang-dev/ > Developer Dashboard > Set Up API Keys
# Database auth/connection variables
DB_USER=[root]
DB_PASSWORD=[password]
DB_NAME=[db]
DB_CONNECTION_NAME=$DB_CONTAINER_NAME:$MYSQL_CONTAINER_PORT
DB_CONNECTION_STRING="$DB_USER:$DB_PASSWORD@tcp($DB_CONNECTION_NAME)/$DB_NAME?charset=utf8&parseTime=True&loc=Local"
# Docker variables
## Network
NETWORK_NAME=[api-bridge]
## Database (built with MySQL locally and Cloud SQL in GCP)
DB_IMAGE_NAME=[mysql-db-image]
DB_CONTAINER_NAME=[db]
DB_HOST_PORT="3306" # Must match db/Dockerfile
DB_CONTAINER_PORT="3306" # Must match db/Dockerfile
## API Provider (built with Go)
API_IMAGE_NAME=[go-app-image]
API_CONTAINER_NAME=[api-app]
API_HOST_PORT="8080" # Must match api-app/Dockerfile
API_CONTAINER_PORT="8080" # Must match api-app/Dockerfile
## Webhook Provider (built with NodeJS)
WEBHOOK_IMAGE_NAME=[nodejs-app-image]
WEBHOOK_CONTAINER_NAME=[webhook-app]
WEBHOOK_HOST_PORT="8000" # Must match webhook-app/Dockerfile
WEBHOOK_CONTAINER_PORT="8000" # Must match webhook-app/Dockerfile
## Reverse Proxy (built with Nginx locally and Cloud Endpoints in GCP)
REVERSE_PROXY_IMAGE_NAME=[nginx-server-image]
REVERSE_PROXY_CONTAINER_NAME=[reverse-proxy]
REVERSE_PROXY_HOST_PORT="80" # Must match reverse-proxy/Dockerfile
REVERSE_PROXY_CONTAINER_PORT="80" # Must match reverse-proxy/Dockerfile
- Propagate environments to application and database
$ ./propagate_env.sh
$ docker network create $NETWORK_NAME
- Build & run
$ cd ./db
$ ./init.sh
$ docker build -t $DB_IMAGE_NAME .
$ docker run -d -p $DB_HOST_PORT:$DB_CONTAINER_PORT --name $DB_CONTAINER_NAME --network $NETWORK_NAME -e MYSQL_ROOT_PASSWORD=$DB_PASSWORD -e DB_NAME=$DB_NAME $DB_IMAGE_NAME
- Test (TODO)
- Build & run
$ cd ./api-app
$ docker build -t $API_IMAGE_NAME .
$ docker run -p $API_HOST_PORT:$API_CONTAINER_PORT -it --rm --name $API_CONTAINER_NAME --network $NETWORK_NAME $API_IMAGE_NAME
- Test
$ curl --request GET --url localhost:$API_HOST_PORT/resumes --header 'accept: application/json'
- Ok if you get a 200 response
- Build & run
$ cd ./webhook-app
$ docker build -t $WEBHOOK_IMAGE_NAME .
$ docker run -p $WEBHOOK_HOST_PORT:$WEBHOOK_CONTAINER_PORT -it --rm --name $WEBHOOK_CONTAINER_NAME --network $NETWORK_NAME $WEBHOOK_IMAGE_NAME
- Test (TODO)
$ cd ./reverse-proxy
$ docker build -t $REVERSE_PROXY_IMAGE_NAME .
$ docker run -p $REVERSE_PROXY_HOST_PORT:$REVERSE_PROXY_CONTAINER_PORT -it --rm --name $REVERSE_PROXY_CONTAINER_NAME --network $NETWORK_NAME $REVERSE_PROXY_IMAGE_NAME
- Test (TODO)
$ gcloud run deploy api.davidchang.dev \
--image="gcr.io/cloudrun/hello" \
--allow-unauthenticated \
--platform managed \
--project=david-chang-websites
$ emacs swaggerspec.yaml
$ gcloud endpoints services deploy swaggerspec.yaml --project david-chang-websites
Build a new ESPv2 image (download and install gcloud_build_image
in /usr/local/bin
if needed)
$ gcloud_build_image -s api.davidchang.dev \
-c 2024-03-10r0 -p david-chang-websites
$ gcloud run deploy api.davidchang.dev \
--image="gcr.io/david-chang-websites/endpoints-runtime-serverless:2.47.0-api.davidchang.dev-2024-03-10r0" \
--allow-unauthenticated \
--platform managed \
--project=david-chang-websites
$ export ENDPOINTS_HOST=dev-davidchang-api-cloud-endpoints-oo452quldq-uc.a.run.app
$ curl --request GET \
--header "content-type:application/json" \
"https://${ENDPOINTS_HOST}/resumes"
API Design (https://api.davidchang.dev)
Note
The resumes
endpoint retrieves and saves resumés (meta data) from/to a database. Future extension to retrieve/save resumés as binary data from/to object storage
- GET - Get the most recent resumé
- GET - Get all resumés, returned as JSON
- POST - Add a new resumé from request data sent as JSON
- GET - Get a resumé by ID, returning resumé data as JSON
- PATCH - Update a resumé by ID
- DELETE - Delete a resumé by ID
Full documentation can be found at https://docs.davidchang.dev