diff --git a/package.json b/package.json index 7962c22..2d293ec 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "scripts": { "prepare": "husky install", "dev": "nodemon", - "build": "esbuild src/index.ts --bundle --minify --platform=node --outdir=build", + "build": "rm -rf build && esbuild `find src \\( -name '*.ts' \\)` --platform=node --outdir=build --resolve-extensions=.js --bundle --minify", "format": "prettier --write 'src/**/*.{js,ts,json,md}'", "lint": "prettier --check 'src/**/*.{js,ts,json,md}' && eslint --ignore-path .gitignore .", "cz": "cz", @@ -34,6 +34,9 @@ "typescript": "^4.6.3" }, "dependencies": { - "fastify": "^3.28.0" + "fastify": "^3.28.0", + "fastify-autoload": "^3.12.0", + "fastify-plugin": "^3.0.1", + "fastify-sensible": "^3.1.2" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 023890d..d39f65c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,9 @@ specifiers: eslint-config-prettier: ^8.5.0 eslint-plugin-prettier: ^4.0.0 fastify: ^3.28.0 + fastify-autoload: ^3.12.0 + fastify-plugin: ^3.0.1 + fastify-sensible: ^3.1.2 husky: ^7.0.4 inquirer: ^8.2.2 lint-staged: ^12.4.0 @@ -24,6 +27,9 @@ specifiers: dependencies: fastify: 3.28.0 + fastify-autoload: 3.12.0 + fastify-plugin: 3.0.1 + fastify-sensible: 3.1.2 devDependencies: '@commitlint/cli': 16.2.3 @@ -1508,6 +1514,11 @@ packages: isobject: 3.0.1 dev: true + /depd/1.1.2: + resolution: {integrity: sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=} + engines: {node: '>= 0.6'} + dev: false + /detect-file/1.0.0: resolution: {integrity: sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=} engines: {node: '>=0.10.0'} @@ -2116,10 +2127,33 @@ packages: resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} dev: false + /fastify-autoload/3.12.0: + resolution: {integrity: sha512-qm8HG8V24A0AdcIjGMMTnyKQj6yzEbdcXHbWjzPtYPReGo4D4Ki7oRLDocYQJVpaOxlcLJSbadfMhZTu3+G6oQ==} + dependencies: + pkg-up: 3.1.0 + semver: 7.3.7 + dev: false + /fastify-error/0.3.1: resolution: {integrity: sha512-oCfpcsDndgnDVgiI7bwFKAun2dO+4h84vBlkWsWnz/OUK9Reff5UFoFl241xTiLeHWX/vU9zkDVXqYUxjOwHcQ==} dev: false + /fastify-plugin/3.0.1: + resolution: {integrity: sha512-qKcDXmuZadJqdTm6vlCqioEbyewF60b/0LOFCcYN1B6BIZGlYJumWWOYs70SFYLDAH4YqdE1cxH/RKMG7rFxgA==} + dev: false + + /fastify-sensible/3.1.2: + resolution: {integrity: sha512-fS8GeY6db3q38GzWOoZMggrw9yHOoXdHv1Pgnorvv18uDrmh1iL8gP9/cqdWzZRM1J3fYvcHsfV2t4BXQF2+sw==} + engines: {node: '>=10.0.0'} + dependencies: + fast-deep-equal: 3.1.3 + fastify-plugin: 3.0.1 + forwarded: 0.2.0 + http-errors: 1.8.1 + type-is: 1.6.18 + vary: 1.1.2 + dev: false + /fastify/3.28.0: resolution: {integrity: sha512-LAQtGllpkRe8L6Tpf3zdbvXzXFOrgaWV3Tbvp3xMv9ngcr9zht9U2/mo5zq9qp9kplSiBJ0w43aVAMqv6PBMbw==} dependencies: @@ -2218,7 +2252,6 @@ packages: engines: {node: '>=6'} dependencies: locate-path: 3.0.0 - dev: true /find-up/4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} @@ -2634,6 +2667,17 @@ packages: resolution: {integrity: sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==} dev: true + /http-errors/1.8.1: + resolution: {integrity: sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==} + engines: {node: '>= 0.6'} + dependencies: + depd: 1.1.2 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 1.5.0 + toidentifier: 1.0.1 + dev: false + /human-signals/2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} @@ -2702,7 +2746,6 @@ packages: /inherits/2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - dev: true /ini/1.3.8: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} @@ -3174,7 +3217,6 @@ packages: dependencies: p-locate: 3.0.0 path-exists: 3.0.0 - dev: true /locate-path/5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} @@ -3278,6 +3320,11 @@ packages: object-visit: 1.0.1 dev: true + /media-typer/0.3.0: + resolution: {integrity: sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=} + engines: {node: '>= 0.6'} + dev: false + /meow/8.1.2: resolution: {integrity: sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==} engines: {node: '>=10'} @@ -3335,6 +3382,18 @@ packages: picomatch: 2.3.1 dev: true + /mime-db/1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + dev: false + + /mime-types/2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: false + /mimic-fn/1.2.0: resolution: {integrity: sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==} engines: {node: '>=4'} @@ -3627,7 +3686,6 @@ packages: engines: {node: '>=6'} dependencies: p-try: 2.2.0 - dev: true /p-limit/3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} @@ -3648,7 +3706,6 @@ packages: engines: {node: '>=6'} dependencies: p-limit: 2.3.0 - dev: true /p-locate/4.1.0: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} @@ -3698,7 +3755,6 @@ packages: /p-try/2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} - dev: true /package-json/6.5.0: resolution: {integrity: sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==} @@ -3752,7 +3808,6 @@ packages: /path-exists/3.0.0: resolution: {integrity: sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=} engines: {node: '>=4'} - dev: true /path-exists/4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} @@ -3828,6 +3883,13 @@ packages: sonic-boom: 1.4.1 dev: false + /pkg-up/3.1.0: + resolution: {integrity: sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==} + engines: {node: '>=8'} + dependencies: + find-up: 3.0.0 + dev: false + /posix-character-classes/0.1.1: resolution: {integrity: sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=} engines: {node: '>=0.10.0'} @@ -4227,6 +4289,10 @@ packages: split-string: 3.1.0 dev: true + /setprototypeof/1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + dev: false + /shebang-command/2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -4413,6 +4479,11 @@ packages: object-copy: 0.1.0 dev: true + /statuses/1.5.0: + resolution: {integrity: sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=} + engines: {node: '>= 0.6'} + dev: false + /string-argv/0.3.1: resolution: {integrity: sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==} engines: {node: '>=0.6.19'} @@ -4628,6 +4699,11 @@ packages: safe-regex: 1.1.0 dev: true + /toidentifier/1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + dev: false + /touch/3.1.0: resolution: {integrity: sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==} hasBin: true @@ -4721,6 +4797,14 @@ packages: engines: {node: '>=8'} dev: true + /type-is/1.6.18: + resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} + engines: {node: '>= 0.6'} + dependencies: + media-typer: 0.3.0 + mime-types: 2.1.35 + dev: false + /typedarray-to-buffer/3.1.5: resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} dependencies: @@ -4845,6 +4929,11 @@ packages: spdx-expression-parse: 3.0.1 dev: true + /vary/1.1.2: + resolution: {integrity: sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=} + engines: {node: '>= 0.8'} + dev: false + /wcwidth/1.0.1: resolution: {integrity: sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=} dependencies: diff --git a/src/index.ts b/src/index.ts index fd2fbaf..e4bca94 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,11 +1,17 @@ +import { join } from 'path' import Fastify from 'fastify' +import autoLoad from 'fastify-autoload' const fastify = Fastify({ logger: true }) -fastify.get('/', async () => { - return { hello: 'world' } +fastify.register(autoLoad, { + dir: join(__dirname, 'plugins') +}) + +fastify.register(autoLoad, { + dir: join(__dirname, 'routes') }) const start = async () => { diff --git a/src/plugins/README.md b/src/plugins/README.md new file mode 100644 index 0000000..d36cb53 --- /dev/null +++ b/src/plugins/README.md @@ -0,0 +1,16 @@ +# Plugins Folder + +Plugins define behavior that is common to all the routes in your +application. Authentication, caching, templates, and all the other cross +cutting concerns should be handled by plugins placed in this folder. + +Files in this folder are typically defined through the +[`fastify-plugin`](https://github.com/fastify/fastify-plugin) module, +making them non-encapsulated. They can define decorators and set hooks +that will then be used in the rest of your application. + +Check out: + +- [The hitchhiker's guide to plugins](https://www.fastify.io/docs/latest/Plugins-Guide/) +- [Fastify decorators](https://www.fastify.io/docs/latest/Decorators/). +- [Fastify lifecycle](https://www.fastify.io/docs/latest/Lifecycle/). diff --git a/src/plugins/sensible.ts b/src/plugins/sensible.ts new file mode 100644 index 0000000..f3d3245 --- /dev/null +++ b/src/plugins/sensible.ts @@ -0,0 +1,13 @@ +import fp from 'fastify-plugin' +import sensible, { SensibleOptions } from 'fastify-sensible' + +/** + * This plugins adds some utilities to handle http errors + * + * @see https://github.com/fastify/fastify-sensible + */ +export default fp(async (fastify, opts) => { + fastify.register(sensible, { + errorHandler: false + }) +}) diff --git a/src/plugins/support.ts b/src/plugins/support.ts new file mode 100644 index 0000000..10dc82e --- /dev/null +++ b/src/plugins/support.ts @@ -0,0 +1,21 @@ +import fp from 'fastify-plugin' + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface SupportPluginOptions { + // Specify Support plugin options here +} + +// The use of fastify-plugin is required to be able +// to export the decorators to the outer scope +export default fp(async (fastify, opts) => { + fastify.decorate('someSupport', function () { + return 'hugs' + }) +}) + +// When using .decorate you have to specify added properties for Typescript +declare module 'fastify' { + export interface FastifyInstance { + someSupport(): string + } +} diff --git a/src/routes/README.md b/src/routes/README.md new file mode 100644 index 0000000..61323c6 --- /dev/null +++ b/src/routes/README.md @@ -0,0 +1,24 @@ +# Routes Folder + +Routes define endpoints within your application. Fastify provides an +easy path to a microservice architecture, in the future you might want +to independently deploy some of those. + +In this folder you should define all the routes that define the endpoints +of your web application. +Each service is a [Fastify +plugin](https://www.fastify.io/docs/latest/Plugins/), it is +encapsulated (it can have its own independent plugins) and it is +typically stored in a file; be careful to group your routes logically, +e.g. all `/users` routes in a `users.js` file. We have added +a `root.js` file for you with a '/' root added. + +If a single file become too large, create a folder and add a `index.js` file there: +this file must be a Fastify plugin, and it will be loaded automatically +by the application. You can now add as many files as you want inside that folder. +In this way you can create complex routes within a single monolith, +and eventually extract them. + +If you need to share functionality between routes, place that +functionality into the `plugins` folder, and share it via +[decorators](https://www.fastify.io/docs/latest/Decorators/). diff --git a/src/routes/examples/index.ts b/src/routes/examples/index.ts new file mode 100644 index 0000000..68a0ea1 --- /dev/null +++ b/src/routes/examples/index.ts @@ -0,0 +1,9 @@ +import { FastifyPluginAsync } from 'fastify' + +const example: FastifyPluginAsync = async (fastify, opts): Promise => { + fastify.get('/', async function (request, reply) { + return 'this is an example' + }) +} + +export default example diff --git a/src/routes/root.ts b/src/routes/root.ts new file mode 100644 index 0000000..27918c7 --- /dev/null +++ b/src/routes/root.ts @@ -0,0 +1,9 @@ +import { FastifyPluginAsync } from 'fastify' + +const root: FastifyPluginAsync = async (fastify, opts): Promise => { + fastify.get('/', async function (request, reply) { + return { root: true } + }) +} + +export default root