Routing & controllers

Nokron handles routing through the use of controllers and actions, which are one of the primary advantages of using Nokron. All incoming HTTP requests are mapped to specific actions in controllres and their corresponding method.


What are Controllers?

Controllers are an essential part of the Model-View-Controller (MVC) architecture, where they act as the bridge between the model (data) and the view (presentation). In the context of web development, controllers are responsible for handling incoming requests, processing the data, and returning a response.

Nokron builds controllers around classes, similar to ASP.NET, where each method inside a controller class represents an action that is mapped to a specific route. These methods are called action methods or handler functions, and they define the logic to be executed when a request is received at a specific URL.

Defining a Controller

To define a controller in Nokron, you need to create a new class and decorate it with the @Controller decorator. The decorator takes an argument that specifies the base route for all the actions defined inside the controller.

For example, the following code defines a CatController class with a base route of /cats:

import { Controller } from '@nokron/core';
 
@Controller('/cats')
export class CatController {
  // Actions defined here...
}

All the actions methods inside the CatController class will be accessible through URLs that begin with /cats.

Defining an Action Method

To define an action method in Nokron, you need to decorate it with an HTTP method decorator, such as @HttpGet, @HttpPost, @HttpPut, @HttpDelete, etc. The decorator specifies the HTTP method for which the action method should handle requests and takes an argument that specifies the route for the action.

For example, the following code defines a getCats method inside the CatController class that handles HTTP GET requests to the /cats route:

import { Controller, HttpGet, Ok } from '@nokron/core';
 
@Controller('/cats')
export class CatController {
  @HttpGet('/')
  public async getCats() {
    return Ok([
      { name: 'Garfield', age: 40 },
      { name: 'Tom', age: 45 },
    ]);
  }
}

In the above example, the getCats method returns an Ok response that contains an array of cat objects when the /cats route is accessed using an HTTP GET request.

Sending the response

All action methods must return an instance of IActionResult. The interface defines the contract that represents the result of the action method, which is used by Nokron to execute and generate the result that is returned with the HTTP response.

Now, we're not expecting you to ever create your own concrete implementation of IActionResult and return that. Instead, we've provided a series of helper methods which can be used to return a desired result, such as Ok(), Created(), NotFound(), and many more.

Some of the helper methods, such as Ok and Created, allows for an object value to be provided, so that the action method can return data as a response.

The example below shows how the called Ok helper methods takes an array of cats, which will be returned as JSON in the response body.

import { Controller, HttpGet, Ok } from '@nokron/core';
 
@Controller('/cats')
export class CatController {
  @HttpGet('/')
  public async getCats() {
    return Ok([
      { name: 'Garfield', age: 40 },
      { name: 'Tom', age: 45 },
    ]);
  }
}

Advanced response handling

Some cases calls for more advanced control of the response, like setting cookies or custom response headers. This can be achieved by adding a parameter decorated with @Res to the action function, like so:

@HttpPost('/refresh')
public async refreshSession(@Res() res: Response) {
  // Do some business logic..
 
  // Set refresh token in cookie
  res.cookie('refreshToken', token, {
    httpOnly: true,
    secure: true,
    sameSite: 'none',
    expires: new Date(refreshToken.expiration),
  });
 
  return Ok();
}

In the example above, the response instance is attached to the res parameter and can be altered before it is sent. In this case, a cookie is being set on the response with a token and some cookie settings. As soon as the Ok method is called and returned, the modified response will used in the execution of the action to create the action result.


Routing

Nokron makes use of Express.js' routing system for handling incoming requests, as Nokron is built on top of Express.js.

Defining route paths

A route path is a string that specifies the URL pattern that the controller action should handle. In Nokron, you can define route paths using the same conventions as in Express.js.

As mentioned previsouly, all Action Methods will use the controller class root path as a prefix for their route path. For example, the following code defines a route path for the listCats action method:

@Controller('/cats')
export class CatController {
  @HttpGet('/list')
  public async listCats() {
    // Logic to handle GET /cats/list
  }
}

The route path for the listCats method is /cats/list, which means that it handles GET requests to that url.

Route parameters

Route parameters are placeholders in the route path that capture values from the URL and pass them to the controller action as arguments. In Nokron, you can define route parameters using the same conventions as in Express.js.

For example, the following code defines a route parameter for the getCatById action method:

@Controller('/cats')
export class CatController {
  @HttpGet('/:id')
  public async getCatById(@Param('id') id: string) {
    // Logic to handle GET /cats/:id
  }
}

In the above example, the :id in the route path is a route parameter that captures the value from the URL and passes it to the getCatById method as an argument.