I like to dab into a lot of different languages and frameworks to see how the grass is on the other side and when trying out a new framework for the first time I usually make a simple CRUD app with authentication like a todo MVC or a live chat. I figured it'd help me keep things organized if I stocked all of those examples within a single repository so here it is.
The client directory stores my fronted app. Made in Vue, purposely very basic because the point of this repo is to test different backend solutions so I don't really care what the two forms I have look like.
The APIs connect to a PostgreSQL Database. The connection preferably is abstracted to an ORM that handles database management through a CLI (create, migrate, seed, drop) and database queries.
-
Task
-
The
Taskmodel belongs to auserrecord -
It has a required
title -
It has a
completedstatus that isfalseby default
-
-
User
-
The
Usermodel has manytasksrecords -
It has a required
emailwhich matches the pattern/\A[^@\s]+@[^@\s]+\.[a-z]{2,}\z/ -
It has a required
passwordwhich is encrypted before being saved to the database and is hidden from logs
For example
#!/usr/bin/env ruby puts User.first # => #<User id: 1 email: "[email protected]", password: [FILTERED]> puts User.first.to_json # => { id: 1, email: "[email protected]" }
-
It can be created with a
password_confirmationthat matches thepassword -
It has a
jtithat is automatically assigned on creation, is reset when signing in and out and is hidden from logs (seepasswordexample) -
It is authenticable with the
emailandpassword -
It is authenticable with a JWT token
-
-
/tasks
-
GET /tasksrequires aAuthorizationheader with auser's JWT and renders itstasksrecords as json and astatus :ok -
POST /tasksrequires aAuthorizationheader with auser's JWT and creates a newTaskrecord for that user
If thetaskis persisted then it renders thetaskas json and astatus: :created
Else it renders an array of error messages and astatus: :unprocessable_entity -
DELETE /tasks/:idrequires aAuthorizationheader with auser's JWT, deletes theTaskrecord and renders astatus: :ok -
PATCH /tasks/:id/completeaAuthorizationheader with auser's JWT, updates theTaskrecord'scompletedstatus totrueand renders thatTaskas json and astatus: :ok
-
-
/users
-
POST /userscreates a newUserrecord
If theuseris persisted then it renders theuseras json with astatus: :createdand aAuthorizationheader with theuser's JWT
Else it renders an array of error messages and astatus: :unprocessable_entity -
POST /users/sign_infinds aUserfrom the givenemailandpassword
If theuserexists then it updates theuser'sjti, renders theuseras json with astatus: :okand aAuthorizationheader with theuser's JWT
Else it renders an array of error messages and astatus: :unprocessable_entity -
DELETE /users/sign_outrequires aAuthorizationheader with auser's JWT, updates theuser'sjtiand renders astatus: :ok
-
-
/current_user
GET /current_userrequires aAuthorizationheader with auser's JWT and renders theuseras json with astatus: :createdand aAuthorizationheader with theuser's JWT
A testing environment is setup and connected to a testing database. The tests are transactional, meaning any changes to the database done inside an example is rollbacked after each test in order to isolate each test example. They are also randomised, meaning tests are run in a random order at each itterations.
The tests also include a fixture system to quickly generate record instances.
The coverage for test suite is measured and as close as possible to 100%
Each APIs have their own formatter/linter as well as a CLI task runner. They also have Github actions for specs, formatting and performance if available.
- Express (Work in progress)