Controllers and Routes

Typically, web applications are based on route mappings. Route, or an endpoint is an URL with assigned function called when user asks for the URL.

Routing system in Entropy is based on controller classes.

Controllers

Basically, a controller is just a class with methods assigned to URLs. Each route handles incoming requests. Controllers contain methods decorated with appropriate HTTP verbs.

Controller Structure

Entropy comes with one controller in src/root.controller.ts file by default.

The root controller defines an index method which is placed with the Route.Get decorator. This decorator tells Entropy that the index method should be called when the user requests for the / route. In the same way you can define your own routes like /login etc.

      

src/root.controller.ts

import { Controller, Route } from '@entropy/router'; import { HttpStatus } from '@entropy/http'; export class RootController extends Controller { @Route.Get('/') public async index() { return await this.render('home', { message: 'Hello, world!', }); } @Route.Error(HttpStatus.NotFound) public async notFound() { return await this.render('404'); } }
Controller methods should always return some value. Entropy automatically sends proper headers based on returned data. In case of object or array, the response has the JSON type. When returned value is text or a view object, it will be rendered as HTML.

Creating and Registering Controllers

It is recommended to use the CLI to create new controllers:

      

terminal

entropy make controller post

The place where every controller should be registered are modules. Every time you create a new controller, you need to import it into a module:

      

src/posts/post.module.ts

import { Module } from '@entropy/server'; import { PostController } from './post.controller.ts'; export class PostModule implements Module { public readonly channels = []; public readonly controllers = [ PostController, ]; }

Routes

In order to declare application routes, add new controller method and decorate it with a proper HTTP verb decorator like so:

      

src/users/user.controller.ts

import { Controller, Route } from '@entropy/router'; export class UserController extends Controller { @Route.Get('/users') public index() { // ... } @Route.Post('/users') public store() { // ... } @Route.Delete('/users/:id') public destroy() { // ... } }

Route Methods

Entropy supports all available HTTP methods. Each method has a corresponding route decorator.

Use the Route.Any decorator to accept all HTTP verbs and the Route.Methods decorator to handle multiple chosen HTTP verbs like so:
      

src/users/user.controller.ts

import { Controller, Route } from '@entropy/router'; import { HttpMethod } from '@entropy/http'; export class UserController extends Controller { @Route.Methods([HttpMethod.Get, HttpMethod.Head], '/users') public index() { // ... } }
Since HTML forms only support GET and POST HTTP methods, when you're defining a route with a different method, your form (or AJAX request) will need to spoof the HTTP verb. You can achieve this by adding <input type="hidden" name="_method" value="DELETE"> or @method('DELETE') snippet inside your form:
        

views/home.atom.html

<form action="/users" method="post"> @method('DELETE') <button>Delete user</button> </form>

Route Actions

Route actions are methods of a controller class with associated route decorator. They are responsible for handling incoming requests and returning a response.

      

src/users/user.controller.ts

import { Controller, Route } from '@entropy/router'; export class UserController extends Controller { @Route.Get('/users') public index() { return [ { name: 'James Bond' }, { name: 'Luke Skywalker' }, ]; } }

When user enters http://localhost:5050/users route, they will see a JSON list of provided users.

Controller action methods should be as short as possible - they are only responsible for handling web requests and returning a response. To add more business logic you can familiarize yourself with the concept of services.

URL Patterns

Routes in Entropy can be dynamic. This means that you can use the :param syntax to declare a dynamic route URL that accepts multiple values:

      

src/users/user.controller.ts

// Match paths like `/users/james_bond` or `/users/56328` @Route.Get('/users/:name')

Optional Parameters

To make a paramater optional, use the question mark. The following route will match both /users and /users/luke_skywalker paths:

      

src/root.controller.ts

@Route.Get('/users/:name?')

Regular Expressions

You can also define RegExp patterns for route parameters:

      

src/root.controller.ts

// This route will accept only numeric params @Route.Get('/posts/:id(^\\d+)') // This route will accept IDs in form of `aaa-bbb` @Route.Get('/users/:id(^\\d{3}-\\d{3})')

Error Handler Routes

A typical web app often returns errors like 404 Not Found or 500 Internal Server Error. The framework exposes a simple API for custom error handling logic.

You can customize the 404 page by adding a special Error route:

      

src/root.controller.ts

import { Controller, Route } from '@entropy/router'; import { HttpStatus } from '@entropy/http'; export class RootController extends Controller { @Route.Error(HttpStatus.NotFound) public async notFound() { return await this.render('404'); } }

Route Options

You can pass additional options to the Route decorator:

      

src/users/user.controller.ts

export class UserController extends Controller { @Route.Get('/users', { name: 'users.index', redirectTo: '/users/create', statusCode: StatusCode.Ok, middleware: [AuthMiddleware], headers: { 'X-Custom-Header': 'Value', }, }) public index() { // ... } }

This way you can define a custom route names, status codes, and more. You can use it later to generate URLs and redirects:

      

src/users/user.controller.ts

return this.redirect({ name: 'users.index' }});

Response Types

Entropy automatically discovers response type based on the returned value from the controller.

The following data will set the response type to JSON:

      

src/users/user.controller.ts

// text/json MIME type return { name: 'Bond. James Bond', };
      

src/users/user.controller.ts

// text/json MIME type return [1, 2, 3];

But this will return an HTML page:

      

src/users/user.controller.ts

// text/html MIME type return '

Hello World

';

This will return a rendered view template:

      

src/users/user.controller.ts

// HTML response (text/html MIME type) return await this.render('./views/profile');

And this will redirect the user to the /login page:

      

src/users/user.controller.ts

// Redirect response return this.redirect('/login');
Modules Requests