Rotas
Rotas são basicamente um mecanismo para definir qual funcionalidade chamar com base na URL e parâmetros fornecidos. Ou seja, o roteamento é um mapeamento entre uma URL e a sua ação.
A JSagon Framework disponibiliza duas maneiras para definição de rotas, uma definida como padrão que utiliza decorators, e a outra utilizando construtores. Abaixo se encontra a documentação de ambas.
Decorators
Digamos que gostaríamos de acessar a página de contato através da seguinte url financas.com/contato e para salvar o formulário a url financas.com/contato/cadastrar.
Um exemplo de código bem simples implementando decorators ficaria assim:
import { ControllerBase, Request, Response, Controller, Post, Get} from '@jsagon/core'
@Controller('/contato')
class HomeController extends ControllerBase {
@Get()
public async contato(req: Request, res: Response) {
return this.render({email: "contato@exemplo.com"})
}}
@Post('/cadastrar')
public async salvarContato(req: Request, res: Response) {
// código de persistência de contato
}
}
export default HomeController
Para que a aplicação registre esses controladores e rotas automaticamente, é preciso que o controlador criado seja inserido no Module.ts do seu módulo que fica em Config.
O Module.ts ficará da seguinte maneira:
import { ModuleBase } from '@jsagon/core'
import HomeController from '../Controller/HomeController'
export default class Module extends ModuleBase {
public static controllers = [
HomeController
]
}
Devido as automatizações que a framework disponibiliza, quando se deseja renderizar uma tela com o this.render, o mecanismo interno entende o nome do método, da action, como o nome da view que se deseja renderizar. É possível alterar esse nome utilizando o decorator de View, como a seguir:
@Get()
@View('contato-portfolio')
public async contato(req: Request, res: Response) {
return this.render({email: "contato@exemplo.com"})
}}
No exemplo anterior, o this.render passará a interpretar a view 'contato-portfolio' como a view do método 'contato'.
E caso queira definir um arquivo que se encontra em um local que não seja o padrão de mapeamento (projeto, módulo e controlador), é possível definir:
@Get()
@View('/novo/local/contato-portfolio', true)
public async contato(req: Request, res: Response) {
return this.render({email: "contato@exemplo.com"})
}}
Decorators disponíveis:
Controller(string: opcional) | Define que um controlador deve ter sua rota mapeada. E caso queira definir uma uri de prefixo, utilizar a parametrização. |
Get(string: opcional) | Definição da rota e método http atribuído. E caso queira definir uma uri de prefixo, utilizar a parametrização. |
Post(string: opcional) | Definição da rota e método http atribuído. E caso queira definir uma uri de prefixo, utilizar a parametrização. |
Put(string: opcional) | Definição da rota e método http atribuído. E caso queira definir uma uri de prefixo, utilizar a parametrização. |
Patch(string: opcional) | Definição da rota e método http atribuído. E caso queira definir uma uri de prefixo, utilizar a parametrização. |
Delete(string: opcional) | Definição da rota e método http atribuído. E caso queira definir uma uri de prefixo, utilizar a parametrização. |
View(string, boolean): opcional | Define a view de um método. Primeiro parâmetro, nome da view. Segundo parâmetro, informar true caso queria definir uma view com path completo. |
Middleware(string | string[] | Function | Function[], string | string[]) | Primeiro parâmetro, middlewares a serem executados na chamada da rota. Segundo parâmetro, middlewares que deverão ser pulados na execução da rota. |
Construtor de Rotas
Abaixo será apresentado um exemplo de código bem simplificado.
Temos o seguinte controlador:
import { AbstractController, Request, Response } from '@jsagon/core'
class HomeController extends AbstractController {
public async salvarContato(req: Request, res: Response) {
// código de persistência de contato
}
public async contato(req: Request, res: Response) {
return this.render({email: "contato@exemplo.com"})
}}
export default HomeController
Digamos que gostaríamos de acessar a página de contato através da url financas.com/contato e para salvar o formulário a url financas.com/contato/cadastrar.
Poderíamos conseguir o mesmo resultado de diferentes maneiras, mas por enquanto faremos da maneira mais didática. O arquivo de rota ficará da seguinte maneira:
import { Route } from '@jsagon/core'
import HomeController from '../Controller/HomeController'
const route = Route('/contato', HomeController)
.get({uri:'', action:'contato'})
.post({uri:'/cadastrar', action:'salvarContato'})
export default route
No exemplo anterior, primeiro importamos o construtor de rotas e logo em seguida o controlador. Utilizando o criador de rotas, passamos uma URI base e o controlador base em questão, depois definimos utilizando métodos específicos que simbolizam o modelo de requisição HTTP, e suas respectivas uri e ações a serem chamadas.
Cada ação(action) corresponde ao método implementado no controlador.
Ao iniciar a aplicação, o mecanismo interno se encarregará de ler os arquivos de rotas (Routes.ts) e registrará automaticamente as rotas criadas. Os arquivos responsáveis pelas rotas ficam armazenados dentro da pasta Config de cada módulo.
Construtores
Atualmente existem dois tipos de construtores de rotas que é possível importar de @jsagon/core, Route e RestRoute.
Ambos compartilham a mesma interface de Route. São elas:
construtor(uri, controller, middleware(s)) | uri string: nome da uri base, será usado para concatenação com todas as uris posteriores definidas; controller: controlador base das ações; middleware(s): função única ou um array de funções a serem executados antes da execução das rotas. Será melhor explicado em Middlewares) |
setBaseUri(string) | Seta e altera a uri base definida no construtor. |
setBaseController(Controller) | Seta e altera o controlador base definido no construtor. |
setBaseMiddleware(function | [functions]) | Seta e altera o(s) middleware(s) base definido no construtor. |
addBaseMiddleware(function) | Adicionar um novo middleware a lista de middlewares. |
get({uri, action}) | uri específica da rota, action específica da rota. Método http GET. |
post({uri, action}) | uri específica da rota, action específica da rota. Método http POST. |
patch({uri, action}) | uri específica da rota, action específica da rota. Método http PATCH. |
put({uri, action}) | uri específica da rota, action específica da rota. Método http PUT. |
del({uri, action}) | uri específica da rota, action específica da rota. Método http DELETE. |
Métodos padrões de acordo com convenções MVC.
Obs.: as URIs padrões serão adicionadas àquela URI definida como base.
Exemplo: uri base = /produto, ao chamar método list. A rota gerada será "/produto/list"
index | parametrização opcional, mas idêntica a anterior. uri padrão: '/', action padrão 'index' |
list | uri padrão: '/list', action padrão 'list' |
show | uri padrão: '/show/:id', action padrão 'show' |
detail | uri padrão: '/detail/:id', action padrão 'detail' |
create | uri padrão: '/create', action padrão 'create' |
edit | uri padrão: '/edit:id', action padrão 'edit' |
store | uri padrão: '/store', action padrão 'store' |
allDefaults | Registra todas as rotas padrões: index, list, create, store, edit, patch, detail, del. |
Comportamento específico para RestRoute.
Ao utilizar o RestRoute teremos métodos padrões de acordo com convenções Restful.
Obs.: as URIs padrões serão adicionadas àquela URI definida como base.
Exemplo: uri base = /produto, ao chamar método edit, a rota gerada será "/produto/:id/edit". E o método list neste caso será '/produto'.
index | parametrização opcional, mas idêntica a anterior. uri padrão: '/', action padrão 'index' |
list | uri padrão: '/', action padrão 'list' |
show | uri padrão: '/:id', action padrão 'show' |
detail | uri padrão: '/:id', action padrão 'detail' |
create | uri padrão: '/', action padrão 'create' |
edit | uri padrão: '/:id/edit', action padrão 'edit' |
put | patch | uri padrão: '/:id', action padrão 'update' |
allDefaults | Registra todas as rotas padrões: store, patch, del, show, edit, index. |
Um exemplo mais elaborado de criação de rotas
import { RestRoute, Route } from '@jsagon/core'
import HomeController from '../Controller/HomeController'
import ProdutoController from '../Controller/ProdutoController'
import { authMiddleware } from '../Middlewares'
const route = Route('/', HomeController)
.index()
.get({uri: '/login', action: 'viewLogin'})
.post({uri: '/login/entrar', action: 'logar'})
.setBaseMiddleware(authMiddleware)
.post({uri:'/sair', action: 'logout'})
const restRoute = RestRoute('/produto', ProdutoController, authMiddleware)
.allDefaults()
.get({uri: '/:id/photos', action: 'recuperarFotos'})
export default [ route, restRoute ]
Descrição comportamental do código anterior:
URIs criadas Route
- financas.com/ ⇒ rota da página inicial
- financas.com/login ⇒ rota da tela de login
- financas.com/login/entrar ⇒ post de login
- Definido middleware de autenticação. Em todas as rotas posteriores o usuário deverá estar logado para executar a ação.
- financas.com/sair ⇒ rota de logout do sistema
URIs criadas RestRoute
- Como definido o authMiddleware todas as rotas precisarão de acesso
- get financas.com/produto
- get financas.com/produto/:id
- post financas.com/produto
- patch financas.com/produto/:id
- delete financas.com/produto/:id
- get financas.com/produtos/:id/photos
Definindo rota base por aplicação
No arquivo de configuração específico do projeto por aplicação (app/WebApp/app.config.ts), é possível definir uma URI base. Ou seja, todas as rotas da aplicação em questão automaticamente terão a URI inserida.
// ...
module.exports = {
// App's uri base. Example if uri: "test", example.com/test root url for all routes
// Uri base da aplicação. Se uri: "test", example.com/test será a url base para todas as rotas definidas
uri: '/app'
// ...
}
Digamos que no arquivo app.config.ts definimos a uri base como "/app". Se internamente criarmos uma rota para listar produtos. Automaticamente, a rota ficará como website.com/app/produto/list.
Tendo entendido e implementado o Controlador e a Rota, agora caso esteja implementado MVC, é preciso entender View.