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'); } }
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.
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() { // ... } }
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.
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');