UNPKG

6.5 kBPlain TextView Raw
1import { HttpVerb } from "./http-verb";
2
3export interface LynxRouteBody {
4 name: string;
5 schema: any;
6}
7
8export interface LynxRouteMetadata {
9 type: HttpVerb;
10 path: string;
11 method: any;
12 body?: LynxRouteBody;
13 isAPI: boolean;
14 isMultipartForm: boolean;
15 verifiers: { fun: Function; isAsync: boolean }[];
16 isDisabledOn?: Function;
17 name?: string;
18}
19
20export interface LynxControllerMetadata {
21 controllerPath: string;
22 routes: LynxRouteMetadata[];
23}
24
25let routes: LynxRouteMetadata[] = [];
26
27/**
28 * Decorator to set the base route of a controller.
29 * @param path the route path for the controller.
30 */
31export function Route(path: string) {
32 return (target: any) => {
33 target.controllerPath = path;
34 target.routes = routes;
35 routes = [];
36 };
37}
38
39function setTarget(_: any, type: HttpVerb, path: string, method: any) {
40 routes.push({
41 type: type,
42 path: path,
43 method: method,
44 body: undefined,
45 isAPI: false,
46 isMultipartForm: false,
47 verifiers: [],
48 isDisabledOn: undefined
49 });
50}
51
52function setBody(_: any, name: string, schema: any) {
53 if (!routes) return;
54 routes[routes.length - 1].body = {
55 name: name,
56 schema: schema
57 };
58}
59
60function setApi(_: any) {
61 if (!routes) return;
62 routes[routes.length - 1].isAPI = true;
63}
64
65function setMultipartForm(_: any) {
66 if (!routes) return;
67 routes[routes.length - 1].isMultipartForm = true;
68}
69
70function setName(name: string) {
71 if (!routes) return;
72 routes[routes.length - 1].name = name;
73}
74
75function setVerify(_: any, func: Function) {
76 if (!routes) return;
77 routes[routes.length - 1].verifiers.push({ fun: func, isAsync: false });
78}
79
80function setAsyncVerify(_: any, func: Function) {
81 if (!routes) return;
82 routes[routes.length - 1].verifiers.push({ fun: func, isAsync: true });
83}
84
85function setIsDisabledOn(_:any, func: Function) {
86 if (!routes) return;
87 routes[routes.length - 1].isDisabledOn = func;
88}
89
90/**
91 * Set the decorated method to a GET endpoint with the specified path.
92 * @param path the endpoint path
93 */
94export function GET(path: string) {
95 return (target: any, method: any, _: any) => {
96 setTarget(target, HttpVerb.GET, path, method);
97 };
98}
99
100/**
101 * Set the decorated method to a POST endpoint with the specified path.
102 * @param path the endpoint path
103 */
104export function POST(path: string) {
105 return (target: any, method: any, _: any) => {
106 setTarget(target, HttpVerb.POST, path, method);
107 };
108}
109
110/**
111 * Set the decorated method to a PUT endpoint with the specified path.
112 * @param path the endpoint path
113 */
114export function PUT(path: string) {
115 return (target: any, method: any, _: any) => {
116 setTarget(target, HttpVerb.PUT, path, method);
117 };
118}
119
120/**
121 * Set the decorated method to a DELETE endpoint with the specified path.
122 * @param path the endpoint path
123 */
124export function DELETE(path: string) {
125 return (target: any, method: any, _: any) => {
126 setTarget(target, HttpVerb.DELETE, path, method);
127 };
128}
129
130/**
131 * Set the decorated method to a PATH endpoint with the specified path.
132 * @param path the endpoint path
133 */
134export function PATCH(path: string) {
135 return (target: any, method: any, _: any) => {
136 setTarget(target, HttpVerb.PATCH, path, method);
137 };
138}
139
140/**
141 * Add to the decorated method a body to be injected. The body will be validated
142 * using the specified schema.
143 * @param name the name of the argument in the method to map the body
144 * @param schema a JOI schema to validate the body object
145 */
146export function Body(name: string, schema: any) {
147 return (target: any, _: any, __: any) => {
148 setBody(target, name, schema);
149 };
150}
151
152/**
153 * Set the decorated method to an API endpoints.
154 * In this way, the returned value of the method will be encapsulated in a
155 * standard API envelope and serialized to JSON using the Lynx serialization system.
156 */
157export function API() {
158 return (target: any, _: any, __: any) => {
159 setApi(target);
160 };
161}
162
163/**
164 * Set the decorated method to accept MultipartForm requested.
165 */
166export function MultipartForm() {
167 return (target: any, _: any, __: any) => {
168 setMultipartForm(target);
169 };
170}
171
172/**
173 * Add to the decorated method a route name, in order to easely generate redirect
174 * or, more general, the execution of the `route` method.
175 * @param name the name of the route
176 */
177export function Name(name: string) {
178 return (_: any, __: any, ___: any) => {
179 setName(name);
180 };
181}
182
183/**
184 * Add to the decorated method a verification function that will be executed
185 * BEFORE the route. The function must NOT be an async function, and it shell
186 * return a boolean value. If true is returned, the method is then executed.
187 * This method is fundamental to implement authorization to a single endpoint.
188 * NOTE: this is the sync version of the AsyncVerify decorator.
189 * @param func the verification function to be executed. It must NOT be an async function, and return a boolean value.
190 */
191export function Verify(func: Function) {
192 return (target: any, _: any, __: any) => {
193 setVerify(target, func);
194 };
195}
196
197/**
198 * Add to the decorated method a verification function that will be executed
199 * BEFORE the route. The function must NOT be an async function, and it shell
200 * return a boolean value. If true is returned, the method is then executed.
201 * This method is fundamental to implement authorization to a single endpoint.
202 * NOTE: this is the async version of the Verify decorator.
203 * @param func the verification function to be executed. It MUST BE an async function, and return a boolean value.
204 */
205export function AsyncVerify(func: Function) {
206 return (target: any, _: any, __: any) => {
207 setAsyncVerify(target, func);
208 };
209}
210
211/**
212 * Add to the decorated method a "disabled" function, that is verified at startup
213 * time. If the function return a truly value, the decorated method is not registered
214 * as an endpoint.
215 * @param func the disabling function to be executed. It shall return a boolean value.
216 */
217export function IsDisabledOn(func: Function) {
218 return (target: any, _: any, __: any) => {
219 setIsDisabledOn(target, func);
220 };
221}
222
223/**
224 * Add to the decorated class a path to be executed as middleware.
225 * @param path the endpoint path
226 */
227export function Middleware(path: string) {
228 return (target: any) => {
229 target.middlewarePath = path;
230 };
231}