-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: added support for ECMAScript Decorators
- Loading branch information
Showing
41 changed files
with
1,023 additions
and
65 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
dist/ | ||
node_modules/ | ||
yarn.lock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
package-lock=false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
--install.no-lockfile true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
## ECMAScript Decorators | ||
|
||
Example how to use fastify-decorators with ES Decorators | ||
|
||
### Getting started | ||
|
||
1. Run `yarn install` or `npm install` | ||
1. Run `yarn build` or `npm run build` | ||
1. Run `yarn start` or `npm start` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import baseConfig from '../../jest.examples.config.js'; | ||
|
||
export default { | ||
...baseConfig, | ||
coverageDirectory: './coverage/integration/ecmascript-decorators', | ||
testRegex: 'examples/ecmascript-decorators/test/.*.test.ts$', | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
{ | ||
"private": true, | ||
"name": "@fastify-decorators-examples/ecmascript-decorators", | ||
"description": "Example how to use fastify-decorators with plain ES Decorators", | ||
"version": "1.0.0", | ||
"main": "dist/index.js", | ||
"type": "module", | ||
"license": "MIT", | ||
"scripts": { | ||
"start": "node dist/start.js", | ||
"build": "tsc -p tsconfig.app.json", | ||
"test": "cross-env NODE_OPTIONS=\"--experimental-vm-modules --no-warnings\" jest" | ||
}, | ||
"dependencies": { | ||
"fastify": "^4.24.3", | ||
"fastify-decorators": "^4.0.0-next.4" | ||
}, | ||
"devDependencies": { | ||
"@types/jest": "^29.5.6", | ||
"@types/node": "~18.18.6", | ||
"jest": "^29.7.0", | ||
"jest-resolve": "^29.7.0", | ||
"jest-ts-webcompat-resolver": "^1.0.0", | ||
"ts-jest": "^29.1.1", | ||
"typescript": "^5.2.2", | ||
"undici": "^5.26.3" | ||
}, | ||
"jest-junit": { | ||
"outputDirectory": "../../test-results", | ||
"outputName": "ecmascript-decorators.xml" | ||
} | ||
} |
6 changes: 6 additions & 0 deletions
6
examples/ecmascript-decorators/src/error-handling/error-type.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export const enum ErrorType { | ||
GENERIC, | ||
CUSTOM, | ||
TYPE, | ||
SYNTAX, | ||
} |
46 changes: 46 additions & 0 deletions
46
examples/ecmascript-decorators/src/error-handling/stateful.controller.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import { FastifyReply, FastifyRequest } from 'fastify'; | ||
import { Controller, ControllerType, ErrorHandler, GET } from 'fastify-decorators'; | ||
import { ErrorType } from './error-type.js'; | ||
|
||
@Controller({ | ||
route: '/stateful/error-handling', | ||
type: ControllerType.REQUEST, | ||
}) | ||
export default class StatelessController { | ||
@GET({ | ||
url: '/', | ||
options: { schema: { querystring: { type: 'object', properties: { errorType: { type: 'number' } } } } }, | ||
}) | ||
async getStateful(request: FastifyRequest<{ Querystring: { errorType: ErrorType } }>): Promise<never> { | ||
switch (request.query.errorType) { | ||
case ErrorType.GENERIC: | ||
throw new Error('Generic error happened'); | ||
case ErrorType.CUSTOM: | ||
throw { code: 'CUSTOM_ERROR_CODE' }; | ||
case ErrorType.SYNTAX: | ||
throw new SyntaxError('Syntax error happened'); | ||
case ErrorType.TYPE: | ||
throw new TypeError('Type error happened'); | ||
} | ||
} | ||
|
||
@ErrorHandler('CUSTOM_ERROR_CODE') | ||
customErrorHandler(error: Error, request: FastifyRequest, reply: FastifyReply): void { | ||
reply.status(503).send(error.message); | ||
} | ||
|
||
@ErrorHandler(TypeError) | ||
typeErrorHandler(error: TypeError, request: FastifyRequest, reply: FastifyReply): void { | ||
reply.status(502).send(error.message); | ||
} | ||
|
||
@ErrorHandler(SyntaxError) | ||
syntaxErrorHandler(error: SyntaxError, request: FastifyRequest, reply: FastifyReply): void { | ||
reply.status(501).send(error.message); | ||
} | ||
|
||
@ErrorHandler() | ||
genericErrorHandler(error: Error, request: FastifyRequest, reply: FastifyReply): void { | ||
reply.status(500).send(error.message); | ||
} | ||
} |
46 changes: 46 additions & 0 deletions
46
examples/ecmascript-decorators/src/error-handling/stateless.controller.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import { FastifyReply, FastifyRequest } from 'fastify'; | ||
import { Controller, ControllerType, ErrorHandler, GET } from 'fastify-decorators'; | ||
import { ErrorType } from './error-type.js'; | ||
|
||
@Controller({ | ||
route: '/stateless/error-handling', | ||
type: ControllerType.REQUEST, | ||
}) | ||
export default class StatelessController { | ||
@GET({ | ||
url: '/', | ||
options: { schema: { querystring: { type: 'object', properties: { errorType: { type: 'number' } } } } }, | ||
}) | ||
async getStateless(request: FastifyRequest<{ Querystring: { errorType: ErrorType } }>): Promise<never> { | ||
switch (request.query.errorType) { | ||
case ErrorType.GENERIC: | ||
throw new Error('Generic error happened'); | ||
case ErrorType.CUSTOM: | ||
throw { code: 'CUSTOM_ERROR_CODE' }; | ||
case ErrorType.SYNTAX: | ||
throw new SyntaxError('Syntax error happened'); | ||
case ErrorType.TYPE: | ||
throw new TypeError('Type error happened'); | ||
} | ||
} | ||
|
||
@ErrorHandler('CUSTOM_ERROR_CODE') | ||
customErrorHandler(error: Error, request: FastifyRequest, reply: FastifyReply): void { | ||
reply.status(503).send(error.message); | ||
} | ||
|
||
@ErrorHandler(TypeError) | ||
typeErrorHandler(error: TypeError, request: FastifyRequest, reply: FastifyReply): void { | ||
reply.status(502).send(error.message); | ||
} | ||
|
||
@ErrorHandler(SyntaxError) | ||
syntaxErrorHandler(error: SyntaxError, request: FastifyRequest, reply: FastifyReply): void { | ||
reply.status(501).send(error.message); | ||
} | ||
|
||
@ErrorHandler() | ||
genericErrorHandler(error: Error, request: FastifyRequest, reply: FastifyReply): void { | ||
reply.status(500).send(error.message); | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
examples/ecmascript-decorators/src/hooks/stateful.controller.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { FastifyReply, FastifyRequest } from 'fastify'; | ||
import { Controller, ControllerType, GET, Hook } from 'fastify-decorators'; | ||
|
||
@Controller({ | ||
route: '/stateful/hooks', | ||
type: ControllerType.SINGLETON, | ||
}) | ||
export default class StatefulController { | ||
@GET() | ||
async getStateful(request: FastifyRequest, reply: FastifyReply): Promise<void> { | ||
reply.status(204); | ||
} | ||
|
||
@Hook('onSend') | ||
async setPoweredBy(request: FastifyRequest, reply: FastifyReply): Promise<void> { | ||
reply.header('X-Powered-By', 'Tell me who'); | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
examples/ecmascript-decorators/src/hooks/stateless.controller.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { FastifyReply, FastifyRequest } from 'fastify'; | ||
import { Controller, ControllerType, GET, Hook } from 'fastify-decorators'; | ||
|
||
@Controller({ | ||
route: '/stateless/hooks', | ||
type: ControllerType.REQUEST, | ||
}) | ||
export default class StatelessController { | ||
@GET() | ||
async getStateless(request: FastifyRequest, reply: FastifyReply): Promise<void> { | ||
reply.status(204); | ||
} | ||
|
||
@Hook('onSend') | ||
async setPoweredBy(request: FastifyRequest, reply: FastifyReply): Promise<void> { | ||
reply.header('X-Powered-By', 'Tell me who'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { fastify } from 'fastify'; | ||
import { bootstrap } from 'fastify-decorators'; | ||
|
||
export const app = fastify({ pluginTimeout: 90_000 }); | ||
|
||
app.register(bootstrap, { | ||
directory: import.meta.url, | ||
}); |
15 changes: 15 additions & 0 deletions
15
examples/ecmascript-decorators/src/inheritance/abstract/abstract-parent.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { GET } from 'fastify-decorators'; | ||
|
||
export abstract class AbstractParent { | ||
abstract message: string; | ||
|
||
@GET('/ping') | ||
async ping() { | ||
return 'pong!'; | ||
} | ||
|
||
@GET('/ping-ping') | ||
async pingPing() { | ||
return this.message; | ||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
examples/ecmascript-decorators/src/inheritance/abstract/inherited.controller.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { Controller } from 'fastify-decorators'; | ||
import { AbstractParent } from './abstract-parent.js'; | ||
|
||
@Controller('/abstract/inherited') | ||
export default class InheritedController extends AbstractParent { | ||
message = 'Inherited'; | ||
} |
12 changes: 12 additions & 0 deletions
12
examples/ecmascript-decorators/src/inheritance/abstract/with-own-methods.controller.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { Controller, GET } from 'fastify-decorators'; | ||
import { AbstractParent } from './abstract-parent.js'; | ||
|
||
@Controller('/abstract/own-methods') | ||
export default class WithOwnMethodsController extends AbstractParent { | ||
message = 'Inherited'; | ||
|
||
@GET('/pong') | ||
async pingPong() { | ||
return 'PING!'; | ||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
examples/ecmascript-decorators/src/inheritance/parent/inherited.controller.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { Controller } from 'fastify-decorators'; | ||
import { Parent } from './parent.js'; | ||
|
||
@Controller('/parent/inherited') | ||
export default class InheritedController extends Parent { | ||
message = 'Inherited'; | ||
} |
15 changes: 15 additions & 0 deletions
15
examples/ecmascript-decorators/src/inheritance/parent/parent.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { GET } from 'fastify-decorators'; | ||
|
||
export class Parent { | ||
declare message: string; | ||
|
||
@GET('/ping') | ||
async ping() { | ||
return 'pong!'; | ||
} | ||
|
||
@GET('/ping-ping') | ||
async pingPing() { | ||
return this.message; | ||
} | ||
} |
12 changes: 12 additions & 0 deletions
12
examples/ecmascript-decorators/src/inheritance/parent/with-own-methods.controller.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { Controller, GET } from 'fastify-decorators'; | ||
import { Parent } from './parent.js'; | ||
|
||
@Controller('/parent/own-methods') | ||
export default class WithOwnMethodsController extends Parent { | ||
message = 'OwnMethods'; | ||
|
||
@GET('/pong') | ||
async pingPong() { | ||
return 'PING!'; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { app } from './index.js'; | ||
|
||
const hostname = '127.0.0.1'; | ||
const port = 3003; | ||
|
||
app.listen(port, hostname, (error, address) => { | ||
if (error != null) { | ||
console.error(error); | ||
process.exit(-1); | ||
} | ||
console.log(`Application start and listening at ${address}`); | ||
console.log(`Available routes: \n${app.printRoutes()}`); | ||
}); |
24 changes: 24 additions & 0 deletions
24
examples/ecmascript-decorators/src/states/stateful.controller.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { FastifyReply, FastifyRequest } from 'fastify'; | ||
import { Controller, ControllerType, GET, POST } from 'fastify-decorators'; | ||
|
||
type State = Record<string, unknown>; | ||
|
||
@Controller({ | ||
route: '/stateful', | ||
// This is default type, just here for consistency with stateless controller | ||
type: ControllerType.SINGLETON, | ||
}) | ||
export default class StatefulController { | ||
private state: State = {}; | ||
|
||
@POST() | ||
setState(request: FastifyRequest<{ Body: State }>, reply: FastifyReply): void { | ||
this.state = request.body; | ||
reply.status(201).send(); | ||
} | ||
|
||
@GET() | ||
getState(request: FastifyRequest, reply: FastifyReply): void { | ||
reply.status(200).send(this.state); | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
examples/ecmascript-decorators/src/states/stateless.controller.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { FastifyReply, FastifyRequest } from 'fastify'; | ||
import { Controller, ControllerType, GET, POST } from 'fastify-decorators'; | ||
|
||
type State = Record<string, unknown>; | ||
|
||
@Controller({ | ||
route: '/stateless', | ||
type: ControllerType.REQUEST, | ||
}) | ||
export default class StatelessController { | ||
private state: State = {}; | ||
|
||
@POST() | ||
setState(request: FastifyRequest<{ Body: State }>, reply: FastifyReply): void { | ||
this.state = request.body; | ||
reply.status(201).send(); | ||
} | ||
|
||
@GET() | ||
getState(request: FastifyRequest, reply: FastifyReply): void { | ||
reply.status(200).send(this.state); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export class UserError extends Error { | ||
constructor(public code: string) { | ||
super(); | ||
} | ||
} |
42 changes: 42 additions & 0 deletions
42
examples/ecmascript-decorators/src/user/user.controller.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { FastifyReply, FastifyRequest } from 'fastify'; | ||
import { Controller, DELETE, ErrorHandler, GET, POST } from 'fastify-decorators'; | ||
import { schema, users } from './user.js'; | ||
import { UserError } from './user-error.js'; | ||
|
||
@Controller('/user') | ||
export default class UserController { | ||
@GET('/:username', { schema }) | ||
public getUser(request: FastifyRequest<{ Params: { username: string } }>, reply: FastifyReply): void { | ||
const { username } = request.params; | ||
if (!users.has(username)) throw new UserError('USER_NOT_FOUND'); | ||
|
||
reply.send({ username }); | ||
} | ||
|
||
@DELETE('/:username') | ||
public deleteUser(request: FastifyRequest<{ Params: { username: string } }>, reply: FastifyReply): void { | ||
const { username } = request.params; | ||
if (!users.has(username)) throw new UserError('USER_NOT_FOUND'); | ||
|
||
users.delete(username); | ||
reply.status(204).send(); | ||
} | ||
|
||
@POST('/', { schema }) | ||
public createUser(request: FastifyRequest<{ Body: { username: string } }>, reply: FastifyReply): void { | ||
const { username } = request.body; | ||
if (users.has(username)) throw new UserError('USER_ALREADY_EXISTS'); | ||
|
||
reply.status(200).send({ username }); | ||
} | ||
|
||
@ErrorHandler('USER_ALREADY_EXISTS') | ||
userExists(error: Error, request: FastifyRequest, reply: FastifyReply): void { | ||
reply.status(422).send({ message: 'User already exists' }); | ||
} | ||
|
||
@ErrorHandler('USER_NOT_FOUND') | ||
public notExists(error: Error, request: FastifyRequest, reply: FastifyReply): void { | ||
reply.status(404).send({ message: 'User not found' }); | ||
} | ||
} |
Oops, something went wrong.