Controllers

Controllers allow you to define routes for your app. A method inside a controller can be a route if it is annotated with one of the available routing decorators @Get(), @Post(), @Patch(), @Put(), @Delete() etc. Below is an example of a controller:

import { Controller, Get } from '@Typetron/Router'

@Controller('articles')
class ArticleController {

    @Get()
    index() {
        return 'This route will show a list of all articles'
    }

    @Get('top')
    top() {
        return 'This route will show a list of top articles'
    }
}

This will create two routes that can be accessed at http://localhost:8000/articles and http://localhost:8000/articles/top

Route parameters

It is often the case when sometimes you will need the get some parts of the request path. For example, you may want to show a particular article based on an ID from the following route: /articles/1. In order to get the value 1 in your controller’s method you can use route parameters like in the example below:

import { Controller, Get } from '@Typetron/Router'

@Controller('articles')
class ArticleController {

    @Get(':id')
    read(id: number) {
        return `This route will show the article with id ${id}`
    }
}

Note Route parameters, by default, are of type string. Typetron will automatically convert parameters from string to number if you write the type to number.

Named routes

You can set a name for a route by providing a second parameter in the annotations that resemble the HTTP methods @Get(), @Post() etc.:

import { Controller, Get } from '@Typetron/Router'

@Controller()
class HomeController {

    @Get('', 'home')
    home() {
        return `Home page`
    }
}

This is helpful when you want to redirect a user to a route when you don’t want to use its full path.

By default, Typetron will set the routes names using the @Controller path and the name of the controller method, separating the two with a dot. For example, take the bellow controller:

import { Controller, Get } from '@Typetron/Router'

@Controller('articles')
class ArticleController {

    @Get()
    read() {}
}

This will create a route with the endpoint /articles having the name articles.read.

If you want to overwrite the prefix you can do it by setting the prefix property inside @Controller:

import { Controller } from '@Typetron/Router'

@Controller('articles', {
    prefix: "posts"
})
class ArticleController {

    @Get()
    read() {}
}

This will set the route’s name to posts.read.

Middleware

Middleware provide a way of intercepting the client’s request and operate on it based on your needs. For example, Typetron provides an Authentication middleware responsible for verifying if the user is authenticated in your app or not. You can also create you own middleware by implementing MiddlewareInterface. He is an example of a custom authentication middleware:

import { Injectable } from '../../Container'
import { MiddlewareInterface, RequestHandler } from '../../Router'
import { Request } from '@Typetron/Web'

@Injectable()
export class MyAdmin implements MiddlewareInterface {

    async handle(request: Request, next: RequestHandler) {

        // processing here

        return next(request)
    }
}

You can then use this middleware inside config/app.ts configuration file:

export default new AppConfig({
    middleware: [
        MyMiddleware
    ],
})

Controller middleware

Adding middleware inside AppConfig will run them on every request. If you want to add a middleware only to a single controller you can use the controller’s middleware option to do that:

import { Controller, Middleware } from '@Typetron/Router'
import { MyMiddleware } from 'App/Middleware/MyMiddleware'

@Controller('articles')
@Middleware(MyMiddleware)
class ArticleController {}

In this case, the middleware will run only if the client makes a request that begins with /articles.

Method middleware

If you want to be more specific with your middleware, you can add it to the method using the @Middleware() decorator:

import { Controller, Middleware } from '@Typetron/Router'
import { MyMiddleware } from 'App/Middleware/MyMiddleware'

@Controller('articles')
class ArticleController {

    @Get('top')
    @Middleware(MyMiddleware)
    top() {}

}

Request

In order to get the request instance you should type-hint the Request class from @Typetron/Web module:

import { Controller } from '@Typetron/Router'
import { Request } from '@Typetron/Web'

@Controller('articles')
class ArticleController {

    @Get()
    all(request: Request) {
        return request.uri
    }
}

You can also get the query parameters from the request instance using the request.query property:

import { Controller } from '@Typetron/Router'
import { Request } from '@Typetron/Web'

@Controller('articles')
class ArticleController {

    @Get()
    all(request: Request) {
        return request.query
    }
}

A request like /articles?topic=programming will create an object like the following:

{
    'programming'
}

If you want to get a specific query parameter, you can use the request.query.parameterName. Typetron also provides a handy decorator for such a job:

import { Controller } from '@Typetron/Router'

@Controller('articles')
class ArticleController {

    @Get()
    all(@Query('topic') topic: string) {
        return `Showing articles from ${topic}`
    }
}

Route Entity binding

Many times you will face the situation where you have to find an entity based on its id, like in the example below:

import { Controller, Get } from '@Typetron/Router'
import { Article } from 'App/Entities/Article'

@Controller('articles')
class ArticleController {

    @Get(':id')
    async read(id: number) {
        const article = await Article.find(id)
        // processing here
        return article
    }
}

Typetron’s Route Entity binding makes finding entities easier by automatically injecting the entity in the method’s parameters. All you have to do is type-hint it and make sure the route parameter’s name matches the entity’s name:

import { Controller, Get } from '@Typetron/Router'
import { Article } from 'App/Entities/Article'

@Controller('articles')
class ArticleController {

    @Get(':Article')
    read(article: Article) {
        // processing here
        return article
    }
}