DEV Community

Cover image for Criando uma API SQL para Twitter com Typescript - Parte 2: Configurando as Rotas do Express
Augusto Silva
Augusto Silva

Posted on • Updated on

Criando uma API SQL para Twitter com Typescript - Parte 2: Configurando as Rotas do Express

Na Parte 1: Configurando o servidor Express eu mostrei como montar um servidor rápido em Express, como colocar os types e converter o projeto para Typescript. Hoje eu irei mostrar 3 maneiras de adicionar rotas no nosso projeto, onde iremos do jeito funcional e depois iremos para orientação à objetos.

Adicionando rotas: modificando o arquivo index.js na raíz do projeto!

A maneira mais fácil de adicionar rotas, seria adicionando-as diretamente no arquivo de entrada da nossa aplicação, como a seguir:

import express from 'express'

const app = express()
const PORT: number = 3000 // Aqui você pode usar outra porta caso a 3000 esteja sendo utilizada.

// Aqui estão nossas rotas!
app.get('/', (req,res) => res.send('Servidor com Express + Typescript!'))

app.listen(PORT, () => {
  console.log(`O servidor está rodando em http://localhost:${PORT}`)
})
Enter fullscreen mode Exit fullscreen mode

Esta é a maneira mais fácil de adicionar as rotas. Um contra ponto desta maneira é que o nosso arquivo index.js pode crescer muito rápido com as rotas e outras configurações que possamos adicionar. Sendo assim, vamos para uma próxima aproximação à este problema.

Adicionando rotas: criando uma pasta com as rotas separadas!

Na pasta raiz do nosso projeto vamos criar uma pasta chamada routes com um arquivo dentro chamado index.js. Nossa estrutura deve estar algo mais ou menos assim:

  • node_modules/
  • routes/
    • index.js
  • index.js
  • packge.json
  • packge-lock.json
  • tsconfig.json

Agora vamos editar o nosso arquivo routes/index.js

import { Router } from 'express'

// Aqui passamos o Router do express.
const router = Router()

// Aqui estamos adicionando nossa rota ao Router.
router.get('/', (req,res) => res.send('Servidor com Express + Typescript!'))

// E finalmente aqui estamos exportando para usar o nosso Router em outro arquivo.
export default router

Enter fullscreen mode Exit fullscreen mode

Voltando para o nosso arquivo principal, faremos a seguinte modificação:

import express from 'express'
import indexRoutes from './routes/index' // Importamos nosso arquivo de rotas.

const app = express()
const PORT: number = 3000 // Aqui você pode usar outra porta caso a 3000 esteja sendo utilizada.

// Aqui estão nossas rotas e colocaremos para que a nossa aplicação possa usá-las!
app.use(indexRoutes)


app.listen(PORT, () => {
  console.log(`O servidor está rodando em http://localhost:${PORT}`)
})
Enter fullscreen mode Exit fullscreen mode

Pronto, dessa maneira temos um arquivo de rotas separado! Isso já melhora as coisas, não é mesmo? Mas existe o caso em que nosso arquivo de rotas também pode ficar muito grande caso criemos uma API com vários endpoints. Vamos então para a terceira e última forma de criar rotas, usando agora orientação à objetos. Estamos usando typescript para isso, não é mesmo?

Adicionando rotas: criando um classe mãe para as rotas e também as classes de rotas!

Dentro da nossa pasta routes vamos criar 3 novos arquivos:

  1. base-routes.ts
  2. home-routes.ts
  3. query-routes.ts

Nossa nova estrutra deve estar parecendo com algo assim:

  • node_modules/
  • routes/
    • index.ts
    • base-routes.ts
    • home-routes.ts
    • query-routes.ts
  • index.ts
  • packge.json
  • packge-lock.json
  • tsconfig.json

No nosso arquivo base-routes.ts teremos:

/**
 * Interface criando o tipo Route.
 * 
 * O tipo Route deve seguir essa estrutura:
 * { 
 *   path: string, 
 *   type: string, 
 *   middlewares: Array<any>, 
 *   controllerFunction: any
 * }
 * 
 */
export interface Route {
  path: string,
  type: string,
  middlewares: Array<any>,
  controllerFunction: any
}

/**
 * Classe mãe para servir de base para a criação das rotas.
 */
export class BaseRoutes {
  /**
   * Variável que guarda o caminho da URL base.
   * 
   * Exemplo, se a url for www.meusite.com, e o basePath for '/api', a url criada será:
   * www.meusite.com/api
   * 
   * Esse basePath, será preposto às rotas que criaremos. Se tivermos uma rota: '/users' a rota do exemplo ficará:
   * www.meusite.com/api/users
   */
  private basePath: string
  // private router: Router = Router()

  public constructor(basePath: string) {
    this.basePath = basePath
  }

  /**
   * Método getter para a variável basePath.
   */
  public getBasePath (): string {
    return this.basePath
  }

  /**
   * Método setter para a variável basePath.
   * 
   * Deve ser utilizado antes de setar as rotas na inicialização da aplicação.
   * 
   * @param newBasePath novo basePath para ser utilizado.
   */
  public setBasePath (newBasePath: string): string {
    return this.basePath = newBasePath
  }

}
Enter fullscreen mode Exit fullscreen mode

Agora criaremos em seguida os arquivos home-routes.ts:

import { Router, Request, Response } from 'express'
import { Route, BaseRoutes } from './base-routes'

/**
 * Classe que conterá as rotas referentes à home/raiz, ou path '/'.
 */
export class HomeRoutes extends BaseRoutes {

  /**
   * Variável que receberá o Router do express.
   */
  private router: Router = Router()

  /**
   * Array contendo as rotas com o path, tipo, middlewares e funções.
   *
   * Declaramos aqui todas as nossas rotas referente ao path '/'.
   */
  private routes: Array<Route> = [
    {
      path: "/",
      type: "get",
      middlewares: [],
      controllerFunction: (req: Request, res: Response) => {
        res.send({ message: "Rota \'/api/v1/\' recebeu o método GET !" })
      }
    },
    {
      path: "/",
      type: "post",
      middlewares: [],
      controllerFunction: (req: Request, res: Response) => {
        res.send({ message: "Rota \'/api/v1\' recebeu o método POST !" })
      }
    }
  ]

  constructor(basePath: string) {
    super(basePath)
  }

  /**
   * Seta as rotas e as coloca no Router do express.
   * 
   * @param router Router da aplicação Express para adicionar rotas nele.
   * @returns uma flag que indica se o setup aconteceu 'true', ou não aconteceu 'false'.
   */
  public setup (router: Router): boolean {
    this.router = router
    const routes: Array<Route> = this.routes

    if (routes.length === 0) {
      return false
    }

    routes.forEach((element: Route) => {
      if (element.type === "get") {
        router.route(element.path).get(element.middlewares, element.controllerFunction)
      }

      if (element.type === "post") {
        router.route(element.path).post(element.middlewares, element.controllerFunction)
      }

      if (element.type === "put") {
        router.route(element.path).put(element.middlewares, element.controllerFunction)
      }

      if (element.type === "delete") {
        router.route(element.path).delete(element.middlewares, element.controllerFunction)
      }

    });

    return true
  }

  /**
   * Método getter da variável router.
   * 
   * @returns o objeto Router do Express relacionado às rotas da classe.
   */
  public getRouter (): Router {
    return this.router
  }

  /**
   * Método getter da variável routes.
   * 
   * @returns as rotas relacionadas à classe.
   */
  public getRoutes (): Array<Route> {
    return this.routes
  }

  /**
   * Método setter para a variável basePath.
   * 
   * Deve ser utilizado antes de setar as rotas na inicialização da aplicação.
   * 
   * @param newRoutes array que contém as novas rotas a serem utilizadas.
   */
  public setRoutes (newRoutes: Array<Route>): void {
    this.routes = newRoutes
  }

}
Enter fullscreen mode Exit fullscreen mode

E query-routes.ts:

import { Router } from 'express'
import { Route, BaseRoutes } from './base-routes'

export class QueryRoutes extends BaseRoutes {

  /**
   * Variável que receberá o Router do express.
   */
  private router: Router = Router()

  /**
   * Array contendo as rotas com o path, tipo, middlewares e funções.
   * 
   * Declaramos aqui todas as nossas rotas referente ao path '/query'.
   */
  private routes: Array<Route> = [
    {
      path: "/query",
      type: "get",
      middlewares: [],
      controllerFunction: (req: Request, res: Response) => {
        res.send({ message: "Rota \'/api/v1/query/\' recebeu o método GET !" })
      }
    }
  ]

  constructor(basePath: string) {
    super(basePath)
  }

  /**
   * Seta as rotas e as coloca no Router do express.
   * 
   * @param router Router da aplicação Express para adicionar rotas nele.
   * @returns uma flag que indica se o setup aconteceu 'true', ou não aconteceu 'false'.
   */
  public setup (router: Router): boolean {
    this.router = router
    const routes: Array<Route> = this.routes

    if (routes.length === 0) {
      return false
    }

    routes.forEach((element: Route) => {
      if (element.type === "get") {
        router.route(element.path).get(element.middlewares, element.controllerFunction)
      }

      if (element.type === "post") {
        router.route(element.path).post(element.middlewares, element.controllerFunction)
      }

      if (element.type === "put") {
        router.route(element.path).put(element.middlewares, element.controllerFunction)
      }

      if (element.type === "delete") {
        router.route(element.path).delete(element.middlewares, element.controllerFunction)
      }

    });

    return true
  }

  /**
   * Método getter da variável router.
   * 
   * @returns o objeto Router do Express relacionado às rotas da classe.
   */
  public getRouter (): Router {
    return this.router
  }

  /**
   * Método getter da variável router.
   * 
   * @returns o objeto Router do Express relacionado às rotas da classe.
   */
  public getRoutes (): Array<Route> {
    return this.routes
  }

  /**
   * Método setter para a variável basePath.
   * 
   * Deve ser utilizado antes de setar as rotas na inicialização da aplicação.
   * 
   * @param newRoutes array que contém as novas rotas a serem utilizadas.
   */
  public setRoutes (newRoutes: Array<Route>) {
    return this.routes = newRoutes
  }

}
Enter fullscreen mode Exit fullscreen mode

Agora modificamos o nosso arquivo routes/index.ts para:

import { Express, Router } from 'express'
import { HomeRoutes } from './home-routes'
import { QueryRoutes } from './query-routes'

// Setamos o nosso basePath padrão da nossa API
const basePath = "/api/v1"

// Criamos os nossos objetos que conterão as nossas rotas.
const homeRoutes: HomeRoutes = new HomeRoutes(basePath)
const queryRoutes: QueryRoutes = new QueryRoutes(basePath)

/**
 * Inicializa as rotas.
 * 
 * @param app objeto que contém a aplicação do Express.
 */
function initialize (app: Express): void {

  // Setando as rotas no Router do Express.
  homeRoutes.setup(Router())
  queryRoutes.setup(Router())

  // Colocando nossa aplicação para utilizar as nossas rotas recém adicionadas ao Router.
  app.use(homeRoutes.getBasePath(), homeRoutes.getRouter())
  app.use(queryRoutes.getBasePath(), queryRoutes.getRouter())
}

export { initialize }
Enter fullscreen mode Exit fullscreen mode

E por fim alteramos nosso arquivo de entrada da aplicação para:

import express from 'express'
import * as routes from './routes/index'

const app = express()
const PORT: number = 3000

// Inicializando o arquivo de rotas.
routes.initialize(app)

app.listen(PORT, () => {
  console.log(`Servidor rodando em http://localhost:${PORT}`)
})
Enter fullscreen mode Exit fullscreen mode

Bônus: adicionando o BodyParser ao nosso projeto.

Agora que temos as nossas rotas prontas, e também podemos adicionar mais se quisermos, iremos adicionar o BodyParser ao nosso projeto. Agora que estamos aptos à receber requisições em nossa aplicação vamos analises o body das solicitações que recebermos através desse middleware do Express.

Vamos rodar o seguinte comando para instalar a bibloteca body-parser

npm install --save body-parser
Enter fullscreen mode Exit fullscreen mode

Agora no nosso arquivo de entrada, faremos as seguintes modificações:

import express from 'express'
import bodyParser from 'body-parser'
import * as routes from './routes/index'

const app = express()
const PORT: number = 3000

// Aplicando o parser de JSON em todas as rotas.
app.use(bodyParser.json())

// Inicializando o arquivo de rotas.
routes.initialize(app)

app.listen(PORT, () => {
  console.log(`Servidor rodando em http://localhost:${PORT}`)
})
Enter fullscreen mode Exit fullscreen mode

E agora, qual o próximo passo?

O próximo passo agora é adicionarmos os controllers para acessarmos a API do twitter.

Caso queira acompanhar o projeto em tempo real, você pode acessar o repositório no Github aqui onde faço atualizações no projeto antes de escrever os artigos aqui.

Top comments (0)