Introdução

Neste tutorial, vamos explorar como construir uma aplicação web escalável utilizando TypeScript, React e NestJS. O objetivo é criar uma arquitetura robusta que facilite tanto a manutenção quanto a escalabilidade do projeto. Abordaremos as melhores práticas para a tipagem do TypeScript e a integração de APIs utilizando o NestJS. Vamos desenvolver uma aplicação que permite realizar operações CRUD (Criar, Ler, Atualizar e Deletar) em um recurso fictício, ensinando desde a configuração inicial até a implementação de testes. Este guia é ideal para desenvolvedores que desejam aplicar conceitos modernos no desenvolvimento de aplicações web.

Etapas

  1. Configuração do Ambiente de Desenvolvimento

    Comece configurando seu ambiente de desenvolvimento com Node.js e npm (Node Package Manager). Você pode verificar as versões instaladas com `node -v` e `npm -v`. Instale o NestJS CLI globalmente com o comando `npm i -g @nestjs/cli`.

    commands
    # Verificar versões instaladas
    node -v
    npm -v
    # Instalar NestJS CLI
    npm i -g @nestjs/cli

  2. Criação do Projeto NestJS

    Utilize o NestJS CLI para criar um novo projeto. Execute o comando `nest new nome-do-projeto` e escolha as opções desejadas. Isso irá criar a estrutura básica do seu projeto NestJS.

    commands
    # Criar um novo projeto
    nest new nome-do-projeto

  3. Configuração do TypeScript no NestJS

    O NestJS já vem configurado para utilizar TypeScript por padrão. Você encontrará um arquivo `tsconfig.json` na raiz do projeto. Você pode personalizar este arquivo para atender às suas necessidades específicas, como habilitar a verificação rigorosa de tipos.

    tsconfig.json
    {
      "compilerOptions": {
        "target": "es2017",
        "module": "commonjs",
        "strict": true,
        "esModuleInterop": true,
        "skipLibCheck": true,
        "forceConsistentCasingInFileNames": true
      },
      "include": ["src/**/*.ts"],
      "exclude": ["node_modules"]
    }

  4. Criação de um Módulo de Produtos

    Crie um módulo chamado `products` com o comando `nest g module products`. Isso irá gerar a estrutura para gerenciar produtos em sua aplicação.

    commands
    # Criar módulo products
    nest g module products

  5. Criação da Entidade Produto

    Dentro do módulo `products`, crie uma entidade `Product` utilizando TypeScript. Crie um arquivo `product.entity.ts` que define a estrutura do produto, inclusive suas propriedades e tipos.

    product.entity.ts
    import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
    
    @Entity()
    export class Product {
      @PrimaryGeneratedColumn()
      id: number;
    
      @Column()
      name: string;
    
      @Column()
      price: number;
    }

  6. Criação do Repositório de Produtos

    Crie um repositório para a entidade `Product`, que permitirá interagir com a base de dados. Para isso, crie um arquivo `products.repository.ts`.

    products.repository.ts
    import { EntityRepository, Repository } from 'typeorm';
    import { Product } from './product.entity';
    
    @EntityRepository(Product)
    export class ProductsRepository extends Repository<Product> {}

  7. Implementação do Serviço de Produtos

    Implemente uma classe de serviço `ProductsService` para encapsular a lógica de negócio. Crie um arquivo `products.service.ts` que irá conter métodos para operações CRUD.

    products.service.ts
    import { Injectable } from '@nestjs/common';
    import { InjectRepository } from '@nestjs/typeorm';
    import { ProductsRepository } from './products.repository';
    import { Product } from './product.entity';
    import { CreateProductDTO } from './create-product.dto';
    
    @Injectable()
    export class ProductsService {
      constructor(
        @InjectRepository(ProductsRepository)
        private readonly productsRepository: ProductsRepository,
      ) {}
    
      async create(productData: CreateProductDTO): Promise<Product> {
        const product = this.productsRepository.create(productData);
        return await this.productsRepository.save(product);
      }
    
      async findAll(): Promise<Product[]> {
        return await this.productsRepository.find();
      }
    
      async findOne(id: number): Promise<Product> {
        return await this.productsRepository.findOne(id);
      }
    
      async update(id: number, productData: CreateProductDTO): Promise<Product> {
        await this.productsRepository.update(id, productData);
        return this.findOne(id);
      }
    
      async delete(id: number): Promise<void> {
        await this.productsRepository.delete(id);
      }
    }

  8. Criação do Controlador de Produtos

    Crie um controlador `ProductsController` que expõe os endpoints da API. Este controlador irá mapear requisições HTTP para métodos do serviço criado anteriormente. Crie o arquivo `products.controller.ts`.

    products.controller.ts
    import { Controller, Get, Post, Body, Param, Put, Delete } from '@nestjs/common';
    import { ProductsService } from './products.service';
    import { Product } from './product.entity';
    
    @Controller('products')
    export class ProductsController {
      constructor(private readonly productsService: ProductsService) {}
    
      @Post()
      async create(@Body() productData: CreateProductDTO): Promise<Product> {
        return this.productsService.create(productData);
      }
    
      @Get()
      async findAll(): Promise<Product[]> {
        return this.productsService.findAll();
      }
    
      @Get(':id')
      async findOne(@Param('id') id: number): Promise<Product> {
        return this.productsService.findOne(id);
      }
    
      @Put(':id')
      async update(@Param('id') id: number, @Body() productData: CreateProductDTO): Promise<Product> {
        return this.productsService.update(id, productData);
      }
    
      @Delete(':id')
      async delete(@Param('id') id: number): Promise<void> {
        return this.productsService.delete(id);
      }
    }

  9. Implementação de Testes Unitários

    Adicione testes unitários para o serviço de produtos. Crie um arquivo `products.service.spec.ts` que utilize o framework de testes do NestJS e o Jest.

    products.service.spec.ts
    import { Test, TestingModule } from '@nestjs/testing';
    import { ProductsService } from './products.service';
    import { ProductsRepository } from './products.repository';
    import { Product } from './product.entity';
    import { getRepositoryToken } from '@nestjs/typeorm';
    
    describe('ProductsService', () => {
      let service: ProductsService;
      let repository: ProductsRepository;
    
      beforeEach(async () => {
        const module: TestingModule = await Test.createTestingModule({
          providers: [
            ProductsService,
            {
              provide: getRepositoryToken(ProductsRepository),
              useValue: {
                create: jest.fn(),
                save: jest.fn(),
                find: jest.fn(),
                findOne: jest.fn(),
                update: jest.fn(),
                delete: jest.fn(),
              },
            },
          ],
        }).compile();
    
        service = module.get<ProductsService>(ProductsService);
        repository = module.get<ProductsRepository>(getRepositoryToken(ProductsRepository));
      });
    
      it('should be defined', () => {
        expect(service).toBeDefined();
      });
    
      // Adicione testes para os métodos do serviço
    });

  10. Executando a Aplicação e Testes

    Compile e execute a aplicação utilizando o comando `npm run start`. Em seguida, utilize o Postman ou cURL para testar os endpoints da API. Para rodar os testes unitários, execute `npm run test`.

    commands
    # Executar a aplicação
    npm run start
    # Executar os testes
    npm run test

    curl_examples
    # Listar todos os produtos
    curl -X GET http://localhost:3000/products
    # Criar um novo produto
    curl -X POST -H 'Content-Type: application/json' -d '{"name":"Novo Produto", "price":99.99}' http://localhost:3000/products

Conclusão

Neste tutorial, você aprendeu a construir uma aplicação web escalável utilizando TypeScript, React e NestJS. Passamos por todo o processo desde a configuração do ambiente até a implementação das camadas de controle, serviços e repositórios. Além disso, abordamos a criação de testes unitários para garantir a qualidade do código. Com estas habilidades, você estará preparado para desenvolver aplicações robustas e manuteníveis, aproveitando as melhores práticas de tipagem e integração de APIs.

Hashtags

#TypeScript #React #NestJS #DesenvolvimentoWeb #APIs #TesteUnitário