src -> Application main folder.
|_ api -> Server API folder.
| |_ middlewares -> API route middleware folder.
| | |_ [files].ts -> Middleware files.
| |_ models -> Table or document models folder.
| | |_ [databases] -> Specified database.
| | | |_ [files].ts -> Mapped related database table or document.
| |_ repositories -> Bridge for service to interact with a database or other resources.
| | |_ [RouteRepository].ts -> Repository for each route.
| |_ routes -> API routes folder.
| | |_ [routes-name] -> Route name folder.
| | | |_ controller.ts -> Route controller. Handle client request and send feedback to client.
| | | |_ index.ts -> Router for controllers.
| | | |_ schemas.ts -> Route request and response schema.
| | | |_ service.ts -> Route handle logic and process.
| | |_ index.ts -> Every API version entry point. Register API router for each version.
| |_ types -> All defined TypeScript types used in API process.
| | |_ fastify.ts -> Custom fastify type.
| | |_ model.ts -> Database select query type.
| | |_ schema.ts -> Schema type.
| | |_ utils.ts -> Some type used for utility functions.
| |_ utils -> API utilities folder.
| | |_ [files].ts -> Utility files.
| |_ index.ts -> API starting point. Register API version entry point.
|_ config -> Global or server configuration variables.
| |_ app.ts -> Server entry point. Fastify server, plugin registering process, global server hook and decorator, and schema definitions.
| |_ env-setup.ts -> Load .env file.
| |_ validateEnv.ts -> Validation for needed global variable in application.
| |_ [files].ts -> Any config files.
|_ databases -> Databases loader folder.
| |_ [files].ts -> Databases connection configuration.
|_ definitions -> Global JSON-Schema Definition for reusable.
| |_ index.ts -> Defined structured JSON-Schemas definition to use as a responses route.
|_ utils -> Global (server) utility folder.
| |_ [files].ts -> Utility config or utility process files.
|_ index.ts -> Application starting point. Contain Fastify server startup and server options, global process exception, environment variable loader, and another loader such as database connection.
- The
API
folder is expected to change the most, so this folder will become a hot area, and getting hotter inside. - Naming file using
kebab-case
style like on Google JavaScript Style Guide - Naming import using
lowerCamelCase
style like on Google JavaScript Style Guide - Other references airbnb / javascript & google / styleguide. Most of code style follow the Airbnb one
- Using
make-promise-safe
on the top of process, refer to Fastify documentation. - Using asynchronous logger, with Pino logger, and handle Log loss prevention and Reopening log files.
- Configure Fastify option on root
index.ts
, and other application loader. - Use setNotFoundHandler to give feedback to client if requested route not exist.
- Use setErrorHandler to centralize error handler
- Could use Encapsulation if necessary, could set in global if all server needed or on the specified plugin or scope.
- Always call
done()
function after registering custom plugin. - Using schema (
JSON-Schema
) as recommended by Fastify on they Core Features. - Preferred using
JSON-Schema
rather than using Fluent Schema. - Write schema definition close to another same
schema definition
(schema grouping). For example, theschema definition
that used forParams
is written on thetop
of the definition. For example all keys for<prefix>Param
on the top and all keys forGet<postfix>
on the bottom, etc. Use key identifier for definition used where,<prefix>Header
mean used forheader
,<prefix>Query
used forquery
,Get<postfix>
forresponses
, etc, and just<key-name>
for shared definition which mean can used onheader
,param
, etc. - Preferred async function if possible.
- Using Ajv schema validation for validate client request.
- Using ajv-errors to add custom message for client request validation.
- Preferred using arrow function if possible and doesn't need
this
keyword. Because in Fastify there is several function handler that more good withnormal function
because usethis
and there is more good usingarrow function
. - Preferred using
arrow function
for function handler on Fastify Hooks - Preferred using
normal function
for function handler on Fastify Routes. - Authentication route level specified on preValidation route option.
- Use
reply.send()
for response - [optional] Declare
import from <dependencies>
aboveimport from <custom-module/file>
- [optional] Declare
import from <most outer custom-module/file>
aboveimport from <closest custom-module/file>
. if import different module with the same level, a module with one and only export default or there is export default and used the export default above the sibling. - [optional] Declare
import type
aboveimport
This application structure, architecture, or style reference to this source:
Adopt the following check (for now):
- 1.2 Layer your components, keep the web layer within its boundaries
- 1.3 Wrap common utilities as npm packages
- 1.4 Separate Express 'app' and 'server'
- 1.5 Use environment aware, secure and hierarchical config
- 2.1 Use Async-Await or promises for async error handling
- 2.4 Handle errors centrally, not within a middleware
- 2.5 Document API errors using Swagger or GraphQL
- 2.7 Use a mature logger to increase error visibility
- 2.8 Test error flows using your favorite test framework
- 2.10 Catch unhandled promise rejections
- 2.11 Fail fast, validate arguments using a dedicated library
- 2.12 Always await promises before returning to avoid a partial stacktrace
- 3.11 Use Async Await, avoid callbacks
- 3.12 Use arrow function expressions (=>)
- 4.1 At the very least, write API (component) testing
- 4.2 Include 3 parts in each test name
- 4.3 Structure tests by the AAA pattern
- 4.5 Avoid global test fixtures and seeds, add data per-test
- 4.8 Check your test coverage, it helps to identify wrong test patterns
- 4.13 Test your middlewares in isolation