-
Notifications
You must be signed in to change notification settings - Fork 71
Tutorial Overview
** WARNING!!! this content was written with a slightly different setup, it needs some updates!! **
As tradition goes we'll build and API for a To-do app but we'll go much further then the concept of tasks. We'll have users, clients, projects, tasks and (real-time) comments, all the core models to build a complete api for a project management tool. We'll also have a codename for this secret project, "Khumbu Icefall", you get extra points if you can figure out why I chose the name.
Unlike most tutorials that just explain a few basic concept with a toy example, this one will take you through all the steps of building real world, complex api that is ready to go into production. You've probably heard (marketing) phrases like "build a production ready API in 5 minutes", tried it and found out it's ... marketing, a production ready toy, not a real system. This tutorial is not going to take 5 minutes but it's also not going to take days to complete (or even months, because usually that is the timeframe you are looking at when building real world APIs). We are looking at 1-2 hours of your time. If you are in a hurry or maybe you'd like to see why you should spend two hours of your time on this, skip to the end and try interacting with a live version of Khumbu Icefall (KI) or run it directly on your computer.
When presented with systems like Sub0, in some cases the conversation goes like "Yes, i guess it's an excelent tool for prototyping but my api is not a 1:1 map of my data models and it has a lot of business logic so I can not use it in production". In this tutorial we'll show how a Sub0 based API is not coupled to your tables and how you can implement your custom business logic and even integrate/interface with 3rd party systems (and not just by calling webhooks).
For most of the tutorial we'll be using the REST interface to interact with the system because it's easier to copy/paste curl lines, but while you are growing your REST API, GraphQL is right next to it.
Follow the instructions for your platform here.
Download the Sub0 kickstart project.
wget http://graphqlapi.com/tutorial/sub0_kickstart.zip
unzip sub0_kickstart.zip
mv sub0_kickstart khumbu_icefall
cd khumbu_icefall
Check out the README in the root directory that gives an overview of what it contains.
.
|-- html -- the directory that will contain all your frontend code (html/javascript/css/images)
|-- lua -- directory where all your lua code/modules reside
| `-- user_module.lua -- a special module that contains hooks that you can use to add your custom logic at different stages of a request
|-- nginx -- directory where nginx/openresty configs reside
| `-- conf
| |-- nginx.conf -- main config file
| |-- root_location.conf -- config for the / location
| |-- includes -- your custom configs/location definitions reside here
| `-- sub0 -- internal locations definition and configurations used by sub0
|-- sql -- directory where your database definition resides
| |-- api -- schema where all the api exposed entities reside
| |-- data -- schema where all your source tables reside
| |-- pgjwt -- schema with JWT related functions
| |-- rabbitmq -- schema with functions related to sending messages to RabbitMQ
| |-- util -- a few convenience functions
| |-- init.sh -- script executed on the database boot (will enable logging on all queries)
| `-- init.sql -- main scripts that kickstarts the creation of the database schema
|-- .env -- a file that contains global configuration of the system (used in the docker-compose.yaml)
`-- docker-compose.yml -- docker config file that ties all the containers (proxy/postgrest/db) together
Edit the file .env
file and give the project a distinct name
COMPOSE_PROJECT_NAME=khumbuicefall
Bring up the system to check everything works
docker-compose up -d # wait 5-10s before running the next command
curl http://localhost:8080/rest/items
The result should look something like this
{"hint":null,"details":null,"code":"42501","message":"permission denied for relation items"}
To have a nicer development workflow, Sub0 comes with a few helper tools packaged in docker image sub0/devutils
.
In a separate terminal run these commands to start the development console
Create an alias for the command used to interact with the sub0/devtools docker images, you might want to add this line to your .bash_profile
alias sub0='function _sub0(){ source $(pwd)/.env; docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v $(pwd):/project -l ${COMPOSE_PROJECT_NAME}_db_1:db --network ${COMPOSE_PROJECT_NAME}_default -ti sub0/devtools $@; };_sub0'
Start the console
sub0 console reset=true
You should see something like this
Now that we have our devtools
up and running, let's see what we can do.
Run this request again and see it reflected in the dev console
curl http://localhost:8080/rest/items
Now let's make an authorized request
export JWT_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJyb2xlIjoid2VidXNlciJ9.vAN3uJSleb2Yj8RVPRsb1UBkokqmKlfl6lJ2bg3JfFg
curl -H "Authorization: Bearer $JWT_TOKEN" http://localhost:8080/rest/items
[{"id":1,"name":"item_2_2"},{"id":2,"name":"item_7_7_7_7_7"},{"id":3,"name":"item_6_6_6_"},{"id":4,"name":"item_7_7_7_7_7"},{"id":5,"name":"item_5_5"},{"id":6,"name":"item_10_10_10_1"},{"id":7,"name":"item_7_7_7_7_7"},{"id":8,"name":"item_8_8"},{"id":9,"name":"item_3_3_3_"},{"id":10,"name":"item_3_3_3_"}]
Notice the first item in the list {"id":1,"name":"item_2_2"}
.
Open the file sql/data/sample_data/data.sql
and change item_2_2
to updated
and save the file.
Look at the console window again, you should see in the bottom window the text Reset process complete
.
Run the last request again
curl -H "Authorization: Bearer $JWT_TOKEN" http://localhost:8080/rest/items
[{"id":1,"name":"updated"},{"id":2,"name":"item_7_7_7_7_7"},{"id":3,"name":"item_6_6_6_"},{"id":4,"name":"item_7_7_7_7_7"},{"id":5,"name":"item_5_5"},{"id":6,"name":"item_10_10_10_1"},{"id":7,"name":"item_7_7_7_7_7"},{"id":8,"name":"item_8_8"},{"id":9,"name":"item_3_3_3_"},{"id":10,"name":"item_3_3_3_"}]
This process works for any sql/**/*.sql
lua/**/*.lua
nginx/**/*.conf
file, you just make the change, save the file and you can run your next request (curl or the GraphiQL interface), assuming your changes were valid.