-
Notifications
You must be signed in to change notification settings - Fork 0
Controllers details
Create a new controller to expose a new entity API it's quietly simple.
You need to add the controller into the controllers folder and the file must follow this naming rule: mycontroller.controller.ts (details here 👍)
Your controller with all the endpoints will be loaded and initialized automatically.
The controller must extends the Controller
class to all the services (dbservices, logservices, whatever service you want) and it's also needed to execute the automatic build initialization.
So you must do something like this:
export class AuthController extends Controller {
public constructor(env: AppEnvironment) {
super(env, "auth");
}
}
I suggest you to add the Controller word to your classname, for example OrderController
. This way you can avoid collision with other object (for example an Order
object)
NOTE: when you pass the path
to the super
, it must end without "/" :exclamation
Where you get via dependency injection the app environment and you pass it to the super with the controller level routing path.
Now, the controller will be the entry point for your API. This happen via the classes' methods definition. The idea is that every method is an endpoint and return a Route
object.
NOTE: It's important that the endpoint returns the Route
object. If not, it will cause EXCEPTIONS
during the Server Initialization.
Route Object:
export type Method = "post" | "put" | "patch" | "get" | "delete";
export class Route {
/**
* Routing path
*/
public readonly path: string;
/**
* Endpoint roles
*/
public readonly roles: Roles[];
/**
* Routing regex test
*/
public readonly test: RegExp;
/**
* Routing method
*/
public readonly method: Method;
/**
* Create routing
* @param path Path
* @param roles roles
* @param test regex
* @param method method
* @returns routing object
*/
public constructor(
path: string,
roles: Roles[],
test: RegExp,
method: Method = "get"
) {
this.path = path;
this.roles = roles;
this.test = test;
this.method = method;
}
}
If you want add a method that is not an endpoint you can do it put the _
character before the method name, for example a built in common method is _registerEndpoint
(we will see soon what this method do).
/**
* Regiter a new endpoint
* @param path path of the endpoint
* @param roles roles for the endpoint
* @param method endopint method
* @returns endpoint object
*/
public _registerEndpoint(path: string, roles: Roles[], method: Method = "get"): Endpoint
{
return new Endpoint(this.server, this._buildRoute(path, roles, method));
}
or a your method:
export class AuthController extends Controller {
public constructor(env: AppEnvironment) {
super(env, "public/auth");
}
//this method will not be routed (if you check, you don't need to return Route object)
public _notRoutedMethod(name: string) {
this.log.info(`Hello ${name}`);
}
}
Like said before, create an endpoint it's very easy, lets see:
/**
* We are inside a Controller
* @returns
*/
public getEmail(): Route
{
// we register the endpoint and return the Route Object
return this._registerEndpoint(
"/checkmail/:email",
["public"]).endpoint(
async (req, res) =>
{
const response: IStandardResponse<any> = initSR();
try
{
const mail = req.params.email;
const aservice = this.initService<AuthService>(new AuthService());
const user = await aservice.getAuthByEmail(mail);
if (user)
{
response.Message = "Email già presente";
response.Data = true;
res.send(response);
}
else
{
response.Data = false;
res.status(200).send(response);
}
} catch (err)
{
this.log.fileLog(JSON.stringify(err));
response.Error.Desc = (err as any).message;
res.status(500).send(response);
}
}).route;
}
You can see in the code that to register our endpoint we use the function _registerEndpoint
.
This function accepts 3 arguments:
- The path;
- The roles (we will speak about this when we will talk about auth via the middleware);
- The method (default is
get
).
This function return an Endpoint
object. This one contains the endpoint
method that accept our express callback. To be clear, the one we will pass to app.get(callback)
in normal express use.
Note that at the end of the function endpoint
we return the Route
via dot notation .route
You can also add an handler to the endpoint, for example:
/**
* We are inside a Controller
* @returns
*/
public getEmail(): Route
{
// we register the endpoint and return the Route Object
return this._registerEndpoint(
"/checkmail/:email",
["public"])
.handler((e: AppEnvironment) =>
{
return (req, res, next) =>
{
console.log("This is an example of an handler");
next();
}
}).
endpoint(
async (req, res) =>
{
const response: IStandardResponse<any> = initSR();
try
{
const mail = req.params.email;
const aservice = this.initService<AuthService>(new AuthService());
const user = await aservice.getAuthByEmail(mail);
if (user)
{
response.Message = "Email già presente";
response.Data = true;
res.send(response);
}
else
{
response.Data = false;
res.status(200).send(response);
}
} catch (err)
{
this.log.fileLog(JSON.stringify(err));
response.Error.Desc = (err as any).message;
res.status(500).send(response);
}
}).route;
}
This is very useful if you want to add some middleware to your endpoint. An example is the multipart-formdata middleware that we will see in the next section. In this example we will use the connect-multiparty
package
/**
* We are inside a Controller
* @returns
*/
public addFile(): Route
{
return this._registerEndpoint("/id/:id/allegato", ["public"], "post", {isApi: true}).handler((req, res, next) =>
{
console.log("I'm the handler")
next();
}).handler(multipart()).endpoint(
async (req, res) =>
{
...
}).route;
}
In this method you can see that we use the handler
method twice. This is because we want to add two middlewares to our endpoint. You can also see the use of the custom data. This is an object that you can pass to the _registerEndpoint
method. This object will be passed to the Route
object and you can access it in the Route
object via the customData
property.
If you give a look to this row in the code above:
const pservice = this.initService<AuthService>(new AuthService());
This method consent you to initialize a service with all environment and basic subservices (like database or filesystem) in it. You will understand better this in the Services Wiki page.
Same for this code:
const response: IStandardResponse<any> = initSR();
This code consent you to init the StandardResponse
object that we'll use like response in all our endponts.
It's a shortcut instead to initialize every time the object.
if (!body.email || !REGEX_EMAIL.test(body.email)) return res.status(400).send(initSR({ Message: "Invalid email", Error: { Num: 400, Desc: "Bad Email" } }));
if (!body.pwd) return res.status(400).send(initSR({ Message: "Invalid password", Error: { Num: 400, Desc: "Bad Password" } }));
```
You'll undestand better the 'StandardObject' in the dedicated page.
I'm Andrea Vincenzo Abbondanza
and this is my email andreabbondanza.developer@outlook.com
Don't use it in vain 😂