Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create basic architecture #1

Merged
merged 107 commits into from
Jul 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
107 commits
Select commit Hold shift + click to select a range
f280c16
chore: create basic architecture
jean-michelet Jun 3, 2024
215955f
fix: typo in comment
jean-michelet Jun 3, 2024
7f7392c
chore: add server.js to show how to not depend on cli
jean-michelet Jun 3, 2024
39c46b7
fix: should not try to parser string as json
jean-michelet Jun 3, 2024
1eca5f7
fix: typo comment
jean-michelet Jun 3, 2024
a707ce9
chore: add helmet plugin
jean-michelet Jun 3, 2024
0289553
chore: add cors plugin
jean-michelet Jun 3, 2024
a382257
chore: add env plugin
jean-michelet Jun 3, 2024
36156f4
refactor: reorganize plugin structure
jean-michelet Jun 3, 2024
bbc21ac
chore: add swagger
jean-michelet Jun 3, 2024
fa32133
fix: typo comment
jean-michelet Jun 3, 2024
5da2429
fix: comment typo
jean-michelet Jun 3, 2024
1494030
fix: swagger tag Example in /example
jean-michelet Jun 3, 2024
8ea43b3
refactor: simplify plugin structure folder
jean-michelet Jun 5, 2024
1f899f7
refactor: put swagger registration in /plugins
jean-michelet Jun 5, 2024
54807be
refactor: add pino-pretty to server.js
jean-michelet Jun 5, 2024
006ccd1
chore: add error handlers
jean-michelet Jun 5, 2024
5ed556f
refactor: unecessary await setNotFoundHandler
jean-michelet Jun 5, 2024
d48b86c
test: root not found handler
jean-michelet Jun 5, 2024
d8101c4
chore: reuse existing workflow
jean-michelet Jun 5, 2024
d41849b
test on v4
jean-michelet Jun 5, 2024
84bf9f9
chore: use ci v4
jean-michelet Jun 5, 2024
b4981ed
fix: run lint fix
jean-michelet Jun 5, 2024
05ffbab
fix: cant use import.meta.dirname for now
jean-michelet Jun 5, 2024
3d58075
update readme getting-started
jean-michelet Jun 5, 2024
31d0e15
fix: node imports
jean-michelet Jun 5, 2024
0a91f6b
merge
jean-michelet Jun 5, 2024
6653a37
chore: use glob to launch tests
jean-michelet Jun 5, 2024
1baf9b7
fix: invalid workflow file
jean-michelet Jun 5, 2024
4cbf9c2
chore: use glob to run test suite
jean-michelet Jun 5, 2024
10e8571
chore: use typescript
jean-michelet Jun 5, 2024
7d0829e
chore: use typescript-eslint with prettier
jean-michelet Jun 5, 2024
45cf1cb
fix: add blank line to .prettierignore
jean-michelet Jun 5, 2024
f0f8d5c
chore: add under-pressure plugin
jean-michelet Jun 7, 2024
727d5e2
docs: add links to under-pressure plugin
jean-michelet Jun 7, 2024
57dce97
refactor: custom plugins should have a name
jean-michelet Jun 7, 2024
2c5595c
chore: setup db
jean-michelet Jun 7, 2024
6859421
merge
jean-michelet Jun 7, 2024
607910f
chore: remove phpmyadmin from docker composition
jean-michelet Jun 7, 2024
67f12f7
fix: typo
jean-michelet Jun 7, 2024
1f4d3c8
refactor: create src folder and run test folder with tap
jean-michelet Jun 7, 2024
33f5fcc
chore: remove glob
jean-michelet Jun 7, 2024
30a7a57
test: error-handler still todo
jean-michelet Jun 7, 2024
bc83e71
fix: remove @types from tsconfig include
jean-michelet Jun 7, 2024
e61a1b7
fix: compiler config
jean-michelet Jun 7, 2024
f0c8645
chore: get rid of NODE_ENV
jean-michelet Jun 7, 2024
540e60a
fix: remove commented code
jean-michelet Jun 7, 2024
08076bf
refactor: move under-pressure options configuration inside plugin def…
jean-michelet Jun 7, 2024
afa52ec
refactor: leverage import.meta.dirname
jean-michelet Jun 7, 2024
e4dce34
test: POST /example and error-handler
jean-michelet Jun 7, 2024
c7379ab
chore: pretty-logger only if the program is running in an interactive…
jean-michelet Jun 9, 2024
831d593
fix: fp must be used to override default error handler
jean-michelet Jun 9, 2024
243b2e0
chore: update CI
jean-michelet Jun 9, 2024
ec1230a
Merge branch 'base-architecture' into test
jean-michelet Jun 9, 2024
9e3fcd6
support only ubuntu
jean-michelet Jun 9, 2024
b022486
dont wait for mysql to be ready
jean-michelet Jun 9, 2024
58e0380
lint
jean-michelet Jun 9, 2024
d7c2cd3
refactor: uninstall global listeners is not needed
jean-michelet Jun 10, 2024
fb902bc
refactor: use neostandard
jean-michelet Jun 10, 2024
a39812c
refactor: add external plugins in their own folder
jean-michelet Jun 11, 2024
a460b70
docs: highlights the concept of modular monolyth
jean-michelet Jun 11, 2024
7d1a0e9
chore: dont wait for MySQL to be ready in ci
jean-michelet Jun 11, 2024
a43ea65
chore: support only ubuntu-latest os
jean-michelet Jun 11, 2024
04c1b13
refactor: leverage autoConfig
jean-michelet Jun 11, 2024
2cd901d
fix: add blank line
jean-michelet Jun 11, 2024
9993ede
chore: raise maxRssBytes to 1GB
jean-michelet Jun 11, 2024
c4fac81
chore: dhould not log during tests
jean-michelet Jun 11, 2024
7110c13
refactor: launch server with await instead of callback
jean-michelet Jun 12, 2024
5502682
docs: add .env.example file
jean-michelet Jun 12, 2024
238698a
merge
jean-michelet Jun 12, 2024
66f3664
fix: remove body-limit test
jean-michelet Jun 17, 2024
f88fd1c
refactor: leverage autoConfig callback feature
jean-michelet Jun 17, 2024
5529b8d
fix: add blank line
jean-michelet Jun 17, 2024
0ea8f26
chore: remove build command before starting server related scripts
jean-michelet Jun 17, 2024
3703d87
feat: add basic jwt authentication
jean-michelet Jun 18, 2024
02ffde1
refactor: return username in /api response
jean-michelet Jun 18, 2024
fb82c1e
chore: use of postgrator for db migrations
jean-michelet Jun 18, 2024
e5a6775
merge
jean-michelet Jun 18, 2024
256bb38
chore: add JWT_SECRET generation step for CI env
jean-michelet Jun 18, 2024
a15de0b
feat: create repository plugin to simplify queries
jean-michelet Jun 22, 2024
6c24c39
fix: remove unused param con of doMigration
jean-michelet Jun 22, 2024
81d5950
refactor: no need for seed database at the beggining of a test
jean-michelet Jun 22, 2024
a84e0a3
test: ignore seed:db catch blocks
jean-michelet Jun 25, 2024
dfde7ee
fix: typo
jean-michelet Jun 25, 2024
abe4809
refactor: move type declarations outside plugin declaration
jean-michelet Jun 25, 2024
3ad48a0
Merge branch 'test' into base-architecture
jean-michelet Jun 25, 2024
044baea
chore: generate dummy .env during CI for scripts using -env-file=.env…
jean-michelet Jun 25, 2024
e1ee800
chore: can't --ignore-scripts if using bcrypt during CI
jean-michelet Jun 25, 2024
0366dac
refactor: use IAuth interface tp type user on request
jean-michelet Jun 25, 2024
8897a41
fix: add blank line to migration files
jean-michelet Jun 25, 2024
ec8005f
fix: remove useless comments
jean-michelet Jun 25, 2024
3a6dfa5
refactor: declare type decoration of fastify instance in plugin files
jean-michelet Jun 25, 2024
95a1b1d
fix: add blank line
jean-michelet Jun 25, 2024
776086b
feat: create scrypt plugin
jean-michelet Jun 25, 2024
59d9484
feat: create scrypt plugin
jean-michelet Jun 25, 2024
6bce950
fix: add blank line
jean-michelet Jun 25, 2024
c2c0f86
fix: git conflict
jean-michelet Jun 25, 2024
5cd29c8
fix: revert timingSafeEqual in error branch
jean-michelet Jun 25, 2024
4031f28
Update src/plugins/custom/repository.ts
jean-michelet Jun 26, 2024
26acff6
refactor: remove I prefix from ts interface
jean-michelet Jun 26, 2024
ccbecd4
fix: identifier typo
jean-michelet Jun 29, 2024
1e16652
fix: remove useless comment
jean-michelet Jun 29, 2024
c6e7cd9
fix: run migration before test
jean-michelet Jun 29, 2024
43136ed
test: ensure access-control-allow-methods contains the expected methods
jean-michelet Jul 14, 2024
1af3f0a
docs: add @link tag to urls
jean-michelet Jul 14, 2024
8fb8618
Update src/app.ts
jean-michelet Jul 14, 2024
6eb86ba
fix: test name
jean-michelet Jul 14, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Must always set to production
# @see {@link https://www.youtube.com/watch?v=HMM7GJC5E2o}
NODE_ENV=production

# Database
MYSQL_HOST=localhost
MYSQL_PORT=3306
MYSQL_DATABASE=test_db
MYSQL_USER=test_user
MYSQL_PASSWORD=test_password

# Server
FASTIFY_CLOSE_GRACE_DELAY=1000
LOG_LEVEL=info

# Security
JWT_SECRET=
13 changes: 13 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"
open-pull-requests-limit: 10

- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
21 changes: 21 additions & 0 deletions .github/stale.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 15
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- "discussion"
- "feature request"
- "bug"
- "help wanted"
- "plugin suggestion"
- "good first issue"
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false
70 changes: 70 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: CI

on:
push:
branches:
- main
- next
- "v*"
paths-ignore:
- "docs/**"
- "*.md"
pull_request:
paths-ignore:
- "docs/**"
- "*.md"

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [22]

services:
mysql:
image: mysql:8.4
ports:
- 3306:3306
env:
MYSQL_ROOT_PASSWORD: root_password
MYSQL_DATABASE: test_db
MYSQL_USER: test_user
MYSQL_PASSWORD: test_password
options: >-
--health-cmd="mysqladmin ping -u$MYSQL_USER -p$MYSQL_PASSWORD"
--health-interval=10s
--health-timeout=5s
--health-retries=3

steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}

- name: Install dependencies
run: npm i

- name: Lint Code
run: npm run lint

- name: Generate JWT Secret
id: gen-jwt
run: |
JWT_SECRET=$(openssl rand -hex 32)
echo "JWT_SECRET=$JWT_SECRET" >> $GITHUB_ENV

- name: Generate dummy .env for scripts using -env-file=.env flag
run: touch .env
jean-michelet marked this conversation as resolved.
Show resolved Hide resolved

- name: Test
env:
MYSQL_HOST: localhost
MYSQL_PORT: 3306
MYSQL_DATABASE: test_db
MYSQL_USER: test_user
MYSQL_PASSWORD: test_password
# JWT_SECRET is dynamically generated and loaded from the environment
run: npm run db:migrate && npm run test
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ coverage
# nyc test coverage
.nyc_output

# tap test coverage
.tap

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt

Expand Down Expand Up @@ -128,3 +131,9 @@ dist
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*

# lock files
bun.lockb
package-lock.json
pnpm-lock.yaml
yarn.lock
7 changes: 7 additions & 0 deletions @types/fastify/fastify.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Auth } from "../../src/schemas/auth.ts";

declare module "fastify" {
export interface FastifyRequest {
user: Auth
}
}
16 changes: 16 additions & 0 deletions @types/node/environment.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
declare global {
namespace NodeJS {
interface ProcessEnv {
PORT: number;
LOG_LEVEL: string;
FASTIFY_CLOSE_GRACE_DELAY: number;
MYSQL_HOST: string
MYSQL_PORT: number
MYSQL_DATABASE: string
MYSQL_USER: string
MYSQL_PASSWORD: string
}
}
}

export {};
40 changes: 39 additions & 1 deletion README.md
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will be nice here to develop a bit more about the methodology or decisions made that lead to this repository; that backstory sometimes helps companies to decide wether or not to adopt a given technology (I've faced that in the past)

Original file line number Diff line number Diff line change
@@ -1 +1,39 @@
# demo
# Fastify Official Demo

![CI](https://github.com/fastify/demo/workflows/CI/badge.svg)
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](https://standardjs.com/)

> :warning: **Please note:** This repository is still under active development.

The aim of this repository is to provide a concrete example of a Fastify application using what are considered best practices by the Fastify community.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe explain which Fastify plugins are part of this demo?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to maintain a list of plugins used in the doc.

To be honest, I'm not really sure what the documentation should contain, although I'm aware that I should be working on it. IMO, I think it should be very minimalist, explaining the purpose of the demo and how to configure the application. The purpose of the demo is to show concrete code, so people should look at the code and comments.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK then not

**Prerequisites:** You need to have Node.js version 22 or higher installed.

## Getting started

Install the dependencies:

```bash
npm install
```

## Available Scripts

In the project directory, you can run:

### `npm run dev`

To start the app in dev mode.\
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.

### `npm start`

For production mode

### `npm run test`

Run the test cases.

## Learn More

To learn Fastify, check out the [Fastify documentation](https://fastify.dev/docs/latest/).
14 changes: 14 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
services:
db:
image: mysql:8.4
environment:
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
ports:
- 3306:3306
volumes:
- db_data:/var/lib/mysql

volumes:
db_data:
20 changes: 20 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use strict'

import neo from 'neostandard'

export default [
...neo({
ts: true
}),
{
rules: {
'@stylistic/comma-dangle': ['error', {
arrays: 'never',
objects: 'never',
imports: 'never',
exports: 'never',
functions: 'never'
}]
}
}
]
7 changes: 7 additions & 0 deletions migrations/001.do.users.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(255) NOT NULL,
password VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
1 change: 1 addition & 0 deletions migrations/001.undo.users.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DROP TABLE IF EXISTS users;
11 changes: 11 additions & 0 deletions migrations/002.do.tasks.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
CREATE TABLE tasks (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
author_id INT NOT NULL,
assigned_user_id INT,
status VARCHAR(50) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (author_id) REFERENCES users(id),
FOREIGN KEY (assigned_user_id) REFERENCES users(id)
);
1 change: 1 addition & 0 deletions migrations/002.undo.tasks.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DROP TABLE IF EXISTS tasks;
7 changes: 7 additions & 0 deletions migrations/003.do.user_tasks.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CREATE TABLE user_tasks (
user_id INT NOT NULL,
task_id INT NOT NULL,
PRIMARY KEY (user_id, task_id),
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (task_id) REFERENCES tasks(id)
);
1 change: 1 addition & 0 deletions migrations/003.undo.user_tasks.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DROP TABLE IF EXISTS user_tasks;
52 changes: 52 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"name": "fastify-demo",
"version": "0.0.0",
"description": "The official Fastify demo!",
"main": "app.js",
"type": "module",
"directories": {
"test": "test"
},
"scripts": {
"build": "rm -rf dist && tsc",
"watch": "npm run build -- --watch",
"test": "npm run db:seed && tap --jobs=1 test/**/*",
"start": "fastify start -l info dist/app.js",
"dev": "fastify start -w -l info -P dist/app.js",
"standalone": "node --env-file=.env dist/server.js",
"lint": "eslint --ignore-pattern=dist",
"lint:fix": "npm run lint -- --fix",
"db:migrate": "node --env-file=.env scripts/migrate.js",
"db:seed": "node --env-file=.env scripts/seed-database.js"
},
"keywords": [],
"author": "Michelet Jean <[email protected]>",
"license": "MIT",
"dependencies": {
"@fastify/autoload": "^5.10.0",
"@fastify/cors": "^9.0.1",
"@fastify/env": "^4.3.0",
"@fastify/helmet": "^11.1.1",
"@fastify/jwt": "^8.0.1",
"@fastify/mysql": "^4.3.0",
"@fastify/sensible": "^5.0.0",
"@fastify/swagger": "^8.14.0",
"@fastify/swagger-ui": "^3.0.0",
"@fastify/type-provider-typebox": "^4.0.0",
"@fastify/under-pressure": "^8.3.0",
"@sinclair/typebox": "^0.32.31",
"fastify": "^4.26.1",
"fastify-cli": "^6.1.1",
"fastify-plugin": "^4.0.0",
"postgrator": "^7.2.0"
},
"devDependencies": {
"@types/node": "^20.14.2",
"eslint": "^9.4.0",
"fastify-tsconfig": "^2.0.0",
"mysql2": "^3.10.1",
"neostandard": "^0.7.0",
"tap": "^19.2.2",
"typescript": "^5.4.5"
}
}
39 changes: 39 additions & 0 deletions scripts/migrate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import mysql from 'mysql2/promise'
import path from 'path'
import Postgrator from 'postgrator'

async function doMigration () {
const connection = await mysql.createConnection({
multipleStatements: true,
host: process.env.MYSQL_HOST,
port: process.env.MYSQL_PORT,
database: process.env.MYSQL_DATABASE,
user: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD
})

const postgrator = new Postgrator({
migrationPattern: path.join(import.meta.dirname, '../migrations', '*'),
driver: 'mysql',
database: process.env.MYSQL_DATABASE,
execQuery: async (query) => {
const [rows, fields] = await connection.query(query)

return { rows, fields }
},
schemaTable: 'schemaversion'
})

await postgrator.migrate()

await new Promise((resolve, reject) => {
connection.end((err) => {
if (err) {
return reject(err)
}
resolve()
})
})
}

doMigration().catch(err => console.error(err))
Loading