A mostly complete example of an Express server with PostgreSQL db and a bunch of other features sprinkled on top.
Why do today what you can put off until tomorrow?
It's a joke, of course, don't take it seriously.
The whole idea behind this was to get my hands dirty with setting up APIs: best practices, scaling, maintenance and security vulnerabilities.
- Default quotes: https://wolfpilot-demotivator-rest-api.onrender.com/quotes
- Paginated quotes: https://wolfpilot-demotivator-rest-api.onrender.com/quotes?limit=2&page=3
- Single quote: https://wolfpilot-demotivator-rest-api.onrender.com/quotes/5
For more details and full CRUD examples, see API.
Postman
-
Architecture
- MVC
- RESTful API
- CRUD
-
Middleware
- Debug console logger
- Request and error loggers with daily rotated files
- Request body content type validation
- Schema-based error validation
- Rate limited
-
Config
- Automated seeding from SQL-like files
- Import path aliases using tsconfig-paths
- Localised .env files using dotenv-flow
- Prepared statements (security)
- Request throttling (rate limitting, CAPTCHA)
- Response document pagination (cursor)
- Protected routes (not necessary atm.)
- Reversible test transactions (no-stress DB testing)
- Languages
- TypeScript
- SQL (PostgreSQL)
- Server
- Database
- PostgreSQL
- Drizzle ORM
- Raw SQL
- Config
- Linting & formatting
- Validation
- Rate limiting
- Testing
- Logging
- CI/CD
Either start your own server and visit http://localhost:9000 or https://wolfpilot-demotivator-rest-api.onrender.com.
# Quotes
GET /quotes - fetch all quotes
POST /quotes - create new quote
GET /quotes/:id - fetch single quote
DELETE /quotes/:id - delete single quote
Simply copy-paste the following examples in your bash terminal making sure to separate newlines with "\" on Mac or "^" on Windows.
If running locally, please use "http://localhost:9000" instead. Alternatively, import the collection below in your own Postman instance and have some fun!
- GET /quotes
curl \
-H "Content-Type: application/json" \
-X GET \
https://wolfpilot-demotivator-rest-api.onrender.com/quotes?limit=2\&page=4
Query params:
limit
# The amount of records to be fetched from the DB.
type: string
min: 2
max: 100
page
# The index of the groupd of records being requested.
type: string
min: 1
max: dynamic
- GET /quotes
curl \
-X GET \
https://wolfpilot-demotivator-rest-api.onrender.com/quotes/3
- POST /quotes/:id
curl \
-H 'Content-Type: application/json' \
-X POST \
-d '{
"author": "Steven Wright",
"text": "The light at the end of the tunnel has been turned off due to budget cuts."
}' \
https://wolfpilot-demotivator-rest-api.onrender.com/quotes
Body:
# The author of the quote.
author
type: string
# The quote itself.
text
type: string
- DELETE /quotes/:id
curl \
-X DELETE \
https://wolfpilot-demotivator-rest-api.onrender.com/quotes/5
Although several precautions have been taken such as restricting user privileges (no "superuser" or "create role"), validating requests (ex: checking that ID strings only coerce to numbers and that they're higher than 0) and using parameterised queries, there are still plenty of improvements that can be made to a public API such as this.
Other measures that comes to mind are:
- Prepared statements
- Checking payloads for potentially dangerous SQL statements
- Throttling requests to prevent flooding
For the purpose of this exercise however, I will say this is enough. If you want to destroy the 10 rows of data being stored, be my guest, Mr. Robot! Just leave me a nice message afterwards.
Optionally, install Postico to get a visual on your DB structure, data and execute queries.
$ git clone https://github.com/wolfpilot/demotivator-rest-api.git
$ cd demotivator-rest-api
$ yarn
# 1. Update your env config, see .env for guidance.
# 2. Start an instance of PostgreSQL
# 3. Run the API service
$ yarn start:dev
PostgreSQL shell commands
"psql" to connect to your db and user
"\l" to list all databases
"\c db_name" to connect to db_name
"\dt" to inspect tables
"\du+" to see table of users
"\q" to quit
- Demotivational quotes referenced from Beverly Jenkins' Demotivational Quotes for Pessimists With a Sense of Humor
- Setup loosely based on Tania Rascia's Node.js, Express.js, and PostgreSQL: CRUD REST API example tutorial
- REST Resource Naming Guide
- Google Search Console API standard error messages
This project is licensed under the MIT License.