Add fastify

This commit is contained in:
Broks Randolfs Gailītis 2025-03-02 13:34:26 +02:00
parent a281a8f5de
commit 215f2ef9ec
31 changed files with 5850 additions and 35 deletions

5
.prettierignore Normal file
View File

@ -0,0 +1,5 @@
# Add files here to ignore them from prettier formatting
/dist
/coverage
/.nx/cache
/.nx/workspace-data

3
.prettierrc Normal file
View File

@ -0,0 +1,3 @@
{
"singleQuote": true
}

View File

@ -1,7 +1,8 @@
{
"recommendations": [
"nrwl.angular-console",
"esbenp.prettier-vscode"
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"firsttris.vscode-jest-runner"
]
}

View File

@ -0,0 +1,3 @@
import baseConfig from '../../eslint.config.mjs';
export default [...baseConfig];

View File

@ -0,0 +1,18 @@
export default {
displayName: 'fastify-api-e2e',
preset: '../../jest.preset.js',
globalSetup: '<rootDir>/src/support/global-setup.ts',
globalTeardown: '<rootDir>/src/support/global-teardown.ts',
setupFiles: ['<rootDir>/src/support/test-setup.ts'],
testEnvironment: 'node',
transform: {
'^.+\\.[tj]s$': [
'ts-jest',
{
tsconfig: '<rootDir>/tsconfig.spec.json',
},
],
},
moduleFileExtensions: ['ts', 'js', 'html'],
coverageDirectory: '../../coverage/fastify-api-e2e',
};

View File

@ -0,0 +1,17 @@
{
"name": "fastify-api-e2e",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"projectType": "application",
"implicitDependencies": ["fastify-api"],
"targets": {
"e2e": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/{e2eProjectRoot}"],
"options": {
"jestConfig": "apps/fastify-api-e2e/jest.config.ts",
"passWithNoTests": true
},
"dependsOn": ["fastify-api:build"]
}
}
}

View File

@ -0,0 +1,10 @@
import axios from 'axios';
describe('GET /', () => {
it('should return a message', async () => {
const res = await axios.get(`/`);
expect(res.status).toBe(200);
expect(res.data).toEqual({ message: 'Hello API' });
});
});

View File

@ -0,0 +1,10 @@
/* eslint-disable */
var __TEARDOWN_MESSAGE__: string;
module.exports = async function () {
// Start services that that the app needs to run (e.g. database, docker-compose, etc.).
console.log('\nSetting up...\n');
// Hint: Use `globalThis` to pass variables to global teardown.
globalThis.__TEARDOWN_MESSAGE__ = '\nTearing down...\n';
};

View File

@ -0,0 +1,7 @@
/* eslint-disable */
module.exports = async function () {
// Put clean up logic here (e.g. stopping services, docker-compose, etc.).
// Hint: `globalThis` is shared between setup and teardown.
console.log(globalThis.__TEARDOWN_MESSAGE__);
};

View File

@ -0,0 +1,9 @@
/* eslint-disable */
import axios from 'axios';
module.exports = async function () {
// Configure axios for tests to use.
const host = process.env.HOST ?? 'localhost';
const port = process.env.PORT ?? '3000';
axios.defaults.baseURL = `http://${host}:${port}`;
};

View File

@ -0,0 +1,13 @@
{
"extends": "../../tsconfig.base.json",
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.spec.json"
}
],
"compilerOptions": {
"esModuleInterop": true
}
}

View File

@ -0,0 +1,9 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"]
},
"include": ["jest.config.ts", "src/**/*.ts"]
}

View File

@ -0,0 +1,3 @@
import baseConfig from '../../eslint.config.mjs';
export default [...baseConfig];

View File

@ -0,0 +1,10 @@
export default {
displayName: 'fastify-api',
preset: '../../jest.preset.js',
testEnvironment: 'node',
transform: {
'^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
},
moduleFileExtensions: ['ts', 'js', 'html'],
coverageDirectory: '../../coverage/apps/fastify-api',
};

View File

@ -0,0 +1,63 @@
{
"name": "fastify-api",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "apps/fastify-api/src",
"projectType": "application",
"tags": [],
"targets": {
"build": {
"executor": "@nx/esbuild:esbuild",
"outputs": ["{options.outputPath}"],
"defaultConfiguration": "production",
"options": {
"platform": "node",
"outputPath": "dist/apps/fastify-api",
"format": ["cjs"],
"bundle": false,
"main": "apps/fastify-api/src/main.ts",
"tsConfig": "apps/fastify-api/tsconfig.app.json",
"assets": ["apps/fastify-api/src/assets"],
"generatePackageJson": true,
"esbuildOptions": {
"sourcemap": true,
"outExtension": {
".js": ".js"
}
}
},
"configurations": {
"development": {},
"production": {
"esbuildOptions": {
"sourcemap": false,
"outExtension": {
".js": ".js"
}
}
}
}
},
"serve": {
"executor": "@nx/js:node",
"defaultConfiguration": "development",
"dependsOn": ["build"],
"options": {
"buildTarget": "fastify-api:build",
"runBuildTargetDependencies": false
},
"configurations": {
"development": {
"buildTarget": "fastify-api:build:development"
},
"production": {
"buildTarget": "fastify-api:build:production"
}
}
},
"test": {
"options": {
"passWithNoTests": true
}
}
}
}

View File

@ -0,0 +1,20 @@
import Fastify, { FastifyInstance } from 'fastify';
import { app } from './app';
describe('GET /', () => {
let server: FastifyInstance;
beforeEach(() => {
server = Fastify();
server.register(app);
});
it('should respond with a message', async () => {
const response = await server.inject({
method: 'GET',
url: '/',
});
expect(response.json()).toEqual({ message: 'Hello API' });
});
});

View File

@ -0,0 +1,27 @@
import * as path from 'path';
import { FastifyInstance } from 'fastify';
import AutoLoad from '@fastify/autoload';
/* eslint-disable-next-line */
export interface AppOptions {}
export async function app(fastify: FastifyInstance, opts: AppOptions) {
// Place here your custom code!
// Do not touch the following lines
// This loads all plugins defined in plugins
// those should be support plugins that are reused
// through your application
fastify.register(AutoLoad, {
dir: path.join(__dirname, 'plugins'),
options: { ...opts },
});
// This loads all plugins defined in routes
// define your routes in one of these
fastify.register(AutoLoad, {
dir: path.join(__dirname, 'routes'),
options: { ...opts },
});
}

View File

@ -0,0 +1,12 @@
import { FastifyInstance } from 'fastify';
import fp from 'fastify-plugin';
import sensible from '@fastify/sensible';
/**
* This plugins adds some utilities to handle http errors
*
* @see https://github.com/fastify/fastify-sensible
*/
export default fp(async function (fastify: FastifyInstance) {
fastify.register(sensible);
});

View File

@ -0,0 +1,7 @@
import { FastifyInstance } from 'fastify';
export default async function (fastify: FastifyInstance) {
fastify.get('/', async function () {
return { message: 'Hello API' };
});
}

View File

View File

@ -0,0 +1,23 @@
import Fastify from 'fastify';
import { app } from './app/app';
const host = process.env.HOST ?? 'localhost';
const port = process.env.PORT ? Number(process.env.PORT) : 3000;
// Instantiate Fastify with some config
const server = Fastify({
logger: true,
});
// Register your application as a normal plugin.
server.register(app);
// Start listening.
server.listen({ port, host }, (err) => {
if (err) {
server.log.error(err);
process.exit(1);
} else {
console.log(`[ ready ] http://${host}:${port}`);
}
});

View File

@ -0,0 +1,10 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"types": ["node"]
},
"include": ["src/**/*.ts"],
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"]
}

View File

@ -0,0 +1,16 @@
{
"extends": "../../tsconfig.base.json",
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.app.json"
},
{
"path": "./tsconfig.spec.json"
}
],
"compilerOptions": {
"esModuleInterop": true
}
}

View File

@ -0,0 +1,15 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"moduleResolution": "node10",
"types": ["jest", "node"]
},
"include": [
"jest.config.ts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.d.ts"
]
}

42
eslint.config.mjs Normal file
View File

@ -0,0 +1,42 @@
import nx from '@nx/eslint-plugin';
export default [
...nx.configs['flat/base'],
...nx.configs['flat/typescript'],
...nx.configs['flat/javascript'],
{
ignores: ['**/dist'],
},
{
files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
rules: {
'@nx/enforce-module-boundaries': [
'error',
{
enforceBuildableLibDependency: true,
allow: ['^.*/eslint(\\.base)?\\.config\\.[cm]?js$'],
depConstraints: [
{
sourceTag: '*',
onlyDependOnLibsWithTags: ['*'],
},
],
},
],
},
},
{
files: [
'**/*.ts',
'**/*.tsx',
'**/*.cts',
'**/*.mts',
'**/*.js',
'**/*.jsx',
'**/*.cjs',
'**/*.mjs',
],
// Override or add rules here
rules: {},
},
];

5
jest.config.ts Normal file
View File

@ -0,0 +1,5 @@
import { getJestProjectsAsync } from '@nx/jest';
export default async () => ({
projects: await getJestProjectsAsync(),
});

3
jest.preset.js Normal file
View File

@ -0,0 +1,3 @@
const nxPreset = require('@nx/jest/preset').default;
module.exports = { ...nxPreset };

38
nx.json
View File

@ -1,14 +1,40 @@
{
"$schema": "./node_modules/nx/schemas/nx-schema.json",
"namedInputs": {
"default": [
"{projectRoot}/**/*",
"sharedGlobals"
],
"default": ["{projectRoot}/**/*", "sharedGlobals"],
"production": [
"default"
"default",
"!{projectRoot}/.eslintrc.json",
"!{projectRoot}/eslint.config.mjs",
"!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)",
"!{projectRoot}/tsconfig.spec.json",
"!{projectRoot}/jest.config.[jt]s",
"!{projectRoot}/src/test-setup.[jt]s",
"!{projectRoot}/test-setup.[jt]s"
],
"sharedGlobals": []
},
"nxCloudId": "67c43f4ee6f8f80a33a28a09"
"nxCloudId": "67c43f4ee6f8f80a33a28a09",
"targetDefaults": {
"@nx/esbuild:esbuild": {
"cache": true,
"dependsOn": ["^build"],
"inputs": ["production", "^production"]
}
},
"plugins": [
{
"plugin": "@nx/eslint/plugin",
"options": {
"targetName": "lint"
}
},
{
"plugin": "@nx/jest/plugin",
"options": {
"targetName": "test"
},
"exclude": ["apps/fastify-api-e2e/**/*"]
}
]
}

5430
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -4,10 +4,38 @@
"license": "MIT",
"scripts": {},
"private": true,
"dependencies": {},
"devDependencies": {
"@eslint/js": "^9.8.0",
"@nx/esbuild": "20.4.6",
"@nx/eslint": "20.4.6",
"@nx/eslint-plugin": "20.4.6",
"@nx/jest": "20.4.6",
"@nx/js": "20.4.6",
"@nx/node": "^20.4.6",
"@nx/workspace": "20.4.6",
"nx": "20.4.6"
"@swc-node/register": "~1.9.1",
"@swc/core": "~1.5.7",
"@swc/helpers": "~0.5.11",
"@types/jest": "^29.5.12",
"@types/node": "~18.16.9",
"esbuild": "^0.19.2",
"eslint": "^9.8.0",
"eslint-config-prettier": "^9.0.0",
"jest": "^29.7.0",
"jest-environment-node": "^29.7.0",
"nx": "20.4.6",
"prettier": "^2.6.2",
"ts-jest": "^29.1.0",
"ts-node": "10.9.1",
"tslib": "^2.3.0",
"typescript": "~5.7.2",
"typescript-eslint": "^8.19.0"
},
"dependencies": {
"@fastify/autoload": "~6.0.3",
"@fastify/sensible": "~6.0.2",
"axios": "^1.6.0",
"fastify": "~5.2.1",
"fastify-plugin": "~5.0.1"
}
}

20
tsconfig.base.json Normal file
View File

@ -0,0 +1,20 @@
{
"compileOnSave": false,
"compilerOptions": {
"rootDir": ".",
"sourceMap": true,
"declaration": false,
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"importHelpers": true,
"target": "es2015",
"module": "esnext",
"lib": ["es2020", "dom"],
"skipLibCheck": true,
"skipDefaultLibCheck": true,
"baseUrl": ".",
"paths": {}
},
"exclude": ["node_modules", "tmp"]
}