Alura > Cursos de Front-end > Cursos de Next.JS > Conteúdos de Next.JS > Primeiras aulas do curso Next.js: construa suas aplicações com Postgres e Prisma

Next.js: construa suas aplicações com Postgres e Prisma

Next fullstack - Apresentação

Olá! Aqui é o Vinicios Neves, a pessoa desenvolvedora careca e barbuda que você mais gosta aqui na Alura, e estamos super animados para evoluir em mais este curso.

Audiodescrição: Vinicios Neves é um homem de pele clara com rosto oval. Tem olhos castanhos-escuros, sobrancelhas grossas, nariz comprido e boca larga. Usa barba e um bigode, óculos de grau com armação quadrada preta. Veste um moletom amarelo e sentado em uma cadeira cinza.

Continuaremos com aquela história de termos um Figma e um sonho, e vamos evoluir tudo isso.

O que vamos aprender?

Desta vez, não vamos mais começar tudo do zero, já trabalhamos no Figma no curso anterior. Portanto, a camada visual já existe, mas como foi feito? Está conectado a uma API REST. Vamos pegar o Next, que é um framework full stack, remover a camada daquela API externa, e fazer com que o próprio Next gerencie os dados.

Como vamos fazer isso? Vamos evoluir, criando um ambiente local, usando o Docker, com o Docker Compose, para levantar um Postgres, que será nosso banco de dados.

Logo após disso, usaremos o Prisma como ORM para controlar tanto a versão da forma das nossas tabelas, as nossas entidades, quanto para montar as consultas para obter esses dados. No final, teremos um deploy na Vercel, com Postgres, com tudo completo e funcional.

O instrutor acessa o seguinte endereço:

code-connect-one.vercel.app/?page=2&q=s

Essa é a minha versão que está disponível do CodeConnect, posso fazer uma busca no campo de busca na parte superior, por exemplo, o "React". Isso para buscar os dados que estão relacionados aos postos cadastrados que têm o título do React. Tudo isso paginado e controlando, inclusive, as variáveis de ambiente.

Vamos lá?

Estou super animado para começar, com o nosso VS Code aberto, e estarei te esperando no primeiro vídeo da próxima aula. Só lembrando, usaremos Docker, com Docker Compose, Postgres, se essas são palavras novas para você, deixamos na página inicial do curso os pré-requisitos e as coisas que você deveria conhecer antes de iniciarmos com o CodeConnect.

Te espero no próximo vídeo!

Next fullstack - Postgres via docker-compose

Estou muito animado que você esteja aqui para iniciar nosso novo curso de Next. Agora, vamos trabalhar com um Next Full Stack. O que isso significa?

No nosso curso anterior, que recomendamos fortemente que você faça, se ainda não o fez, desenvolvemos uma aplicação chamada CodeConnect. Nessa aplicação, que é um blog sobre tecnologias, integramos com uma API REST já existente.

Durante este curso, vamos remover completamente a API antiga e passaremos a nos comunicar diretamente com o banco de dados. A própria aplicação Next saberá como recuperar esses dados para exibir para a pessoa usuária.

Como vamos fazer isso?

Preparação do Ambiente de Desenvolvimento

O primeiro passo é preparar nosso ambiente de desenvolvimento. Pensando nisso, disponibilizamos no https://gist.github.com/viniciosneves/b4628877edbc78e890ab61eb23eaad49 um docker-compose.yaml que representa nossos serviços locais. Isso significa que ele vai configurar todas as dependências do nosso projeto para que possamos executá-lo sem problemas localmente.

Um dos principais pontos é garantir que, não importa se estamos no Mac, no Windows ou no Linux, haja um mínimo de compatibilidade entre nós, pessoas desenvolvedoras.

O que vamos fazer?

Copiamos todo o conteúdo que está no gist.github.com, teclamos "Ctrl + C" de todas as instruções do docker-compose.

docker-compose.yaml

services:
  # 'services' define um ou mais serviços, cada um representando um contêiner.
  
  postgres:
    # 'postgres' é o nome dado a este serviço. Você pode nomear o serviço como desejar.

    image: postgres:15-alpine
    # 'image' especifica a imagem Docker a ser usada para criar o contêiner.
    # 'postgres:15-alpine' indica que estamos usando a versão 15 da imagem do PostgreSQL, baseada na distribuição Alpine Linux, que é uma versão mais leve.

    ports:
      - 5432:5432
    # 'ports' permite mapear portas entre o contêiner e o host (sua máquina).
    # '5432:5432' significa que a porta 5432 do contêiner será mapeada para a porta 5432 do seu host. Isso permite que você acesse o serviço PostgreSQL pela porta 5432 na sua máquina.

    environment:
      POSTGRES_DB: codeconnect_dev
      # 'environment' define variáveis de ambiente dentro do contêiner.
      # 'POSTGRES_DB' define o nome do banco de dados a ser criado automaticamente quando o contêiner for iniciado pela primeira vez. Aqui, o banco de dados será chamado de 'codeconnect_dev'.

      POSTGRES_HOST_AUTH_METHOD: trust
      # 'POSTGRES_HOST_AUTH_METHOD' define o método de autenticação.
      # 'trust' significa que não é necessária senha para conectar ao banco de dados. Isso não é recomendado para ambientes de produção por razões de segurança.

Agora, no VS Code, criamos um novo arquivo chamado docker-compose.yaml e colar o que copiamos do nosso gist.

Deixamos como pré-requisito para este curso um curso específico de docker. Se isso é novidade para você, vale a pena dar uma estudada lá primeiro. Mas para resumir este arquivo, além de termos deixado comentado o que cada uma dessas instruções faz, este docker-compose vai levantar um banco de dados postgres. Uma alternativa a isso é instalá-lo manualmente.

É uma alternativa, mas para garantir e maximizar nossa compatibilidade, recomendamos fortemente que você use o docker-compose.yaml, pois isso vai garantir que tenhamos o mesmo ambiente. Assim, tudo que fizermos aqui e você repetir do seu lado, estará conectado e homogêneo.

Execução do Docker Compose

Agora que já trouxemos o docker-compose.yaml, é hora de usar o terminal. Abrimos o terminal dentro do VS Code e, na raiz do projeto, rodamos o comando docker compose up. Isso vai levantar nosso ambiente de desenvolvimento. No entanto, vamos passar uma flag no final "-d".

docker compose up -d

Isso fará com que o terminal não fique preso nesse comando. O próprio docker vai cuidar de manter esse Postgres rodando.

Quando pressionarmos a tecla "Enter", ele começará a fazer o download, preparar e baixar tudo que precisa para executar nosso Postgres. Quando terminar, ele exibirá uma mensagem informando que tudo está correto.

Conclusão e Próximos Passos

Se abrirmos nosso docker-desktop, veremos que, no containers/app, dentro do docker-desktop, ele exibirá e informará que nosso Postgres está rodando. Com tudo isso feito, nosso ambiente está preparado para darmos o próximo passo e começarmos a entender como o Next vai se conectar com esse Postgres.

Nos vemos no próximo vídeo!

Next fullstack - Instalando o Prisma

Agora que temos nossa infraestrutura para o ambiente de desenvolvimento funcionando, com o Docker e o container sendo executados, podemos evoluir nosso projeto. A primeira coisa que faremos é configurar o Prisma.

Configurando o Prisma

O Prisma é um ORM, ou seja, vamos escrever um pouco de código JavaScript e um pouco de código na própria linguagem do Prisma. O Prisma vai entender a sintaxe dele e esse ORM vai fazer a comunicação com o banco de dados. Isso vai evitar que precisemos escrever SQL manualmente.

Se o universo de um ORM ainda é novo para você, deixamos uma atividade nesta aula, um "Para Saber Mais", que explica de onde nasceu esse conceito de ORM e como podemos explorar e entender um pouco mais esse universo, onde abstraímos a escrita do nosso SQL para escrever algo mais específico da linguagem que estamos executando, no nosso caso, JavaScript. Escreveremos consultas que pegam dados do banco, mas usando JavaScript.

Para começar, temos três pequenos passos.

O primeiro: no VS Code, limpamos o terminal, porque ele ainda estava exibindo o resultado do docker compose up -d. Agora, o que faremos? Pedimos para o npx executar um script do Prisma e o script vai receber esse parâmetro init, que vai iniciar a nossa preparação do nosso ambiente Prisma.

npx prisma init

O comando foi executado, ele retornou um resultado informando que está tudo certo, que já tem um arquivo .gitignore, e que o esquema da nossa aplicação foi criado dentro da pasta prisma em um arquivo chamado schema.prisma.

Your Prisma schema was created at prisma/schema.prisma

You can now open it in your favorite editor.

Analisaremos esse arquivo agora. Podemos clicar no ícone de lixeira no canto superior direito do terminal. Do lado esquerdo, clicamos na pasta prisma e depois em schema.prisma.

schema.prisma

// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

generator client {
    provider = "prisma-client-js"
}

datasource db {
    provider = "postgresql"
    url = env("DATABASE_URL")
}

Repare, foi criado um generator, que é uma forma do Prisma criar o nosso client, e mais para frente vamos começar a fazer isso, e ele inseriu também um datasource, que é o nosso banco de dados.

Repare, já foi indicado na linha 9 que o provider é um Postgres, ou seja, por padrão, o Prisma já vem preparado para o Postgres. E a URL desse banco de dados, ele está vindo de uma variável de ambiente chamada DATABASE_URL.

Então, você provavelmente está se questionando sobre essa variável de ambiente, já que ainda não fizemos nada. Bem, quando executamos o comando prisma init, ele automaticamente criou um arquivo .env para nós.

Esse arquivo será responsável por armazenar todas as variáveis de ambiente personalizadas, além dos padrões do Node. E o Prisma já incluiu uma URL de banco de dados (DATABASE_URL) para nós.

Aqui, muito cuidado e atenção. No nosso cenário, nesse momento, essa variável de ambiente tem uma URL para uma conexão com o banco de dados local. Então, como aqui tem coisa local, o exemplo que ele gerou aqui até um exemplo que não funciona, que é um johndoe com random password.

Trecho de código indicado pelo instrutor:

DATABASE_URL="postgresql://johndoe: randompassword@localhost:5432/mydb?schema=public"

Não tem problema comitarmos, porque é um ambiente seguro. É o nosso ambiente de desenvolvimento e não tem problema nenhum de isso estar público lá no GitHub.

Porém, quando mandarmos isso para a produção, esse .env não pode, de maneira nenhuma, conter os dados de acesso ao nosso banco. Senão, qualquer pessoa vai entrar no GitHub, pegar essa conexão e poderá manipular e fazer o que quiser com o banco de dados.

Normalmente, os arquivos .env, eles não são comitados. No nosso cenário, não tem problema, porque é só o ambiente de dev.

Desenvolvendo o schema.prisma

Agora que organizamos isso, avançamos para criar e desenvolver nosso schema.prisma. Vamos fechar tudo que está aberto e criar nossos modelos. Considerando nosso contexto, onde temos posts e os autores desses posts, o autor será um model. E já que estamos codificando em inglês, vamos chamar esse modelo de User.

schema.prisma

// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

generator client {
    provider = "prisma-client-js"
}

datasource db {
    provider = "postgresql"
    url = env("DATABASE_URL")
}

model User {

}

Aqui se inicia o encanto de como conseguimos detalhar uma tabela para o Prisma.

Por exemplo, podemos iniciar solicitando um id, e afirmaremos que este id é um número inteiro (Int). Adicionalmente, faremos uma observação indicando que ele é a chave primária desta tabela usando @id. Também podemos atribuir um valor @default() (padrão) para este campo, especificando que o valor padrão é o autoincrement.

schema.prisma

// código omitido

model User {
 id Int @id @default(autoincrement())
}

Criamos uma model User, ou seja, o Prisma vai criar no banco de dados uma tabela user, e adicionamos o primeiro campo id, que é um inteiro, de autoincrement.

Observação importante: No meu VS Code, o destaque de sintaxe (highlight) já está funcionando perfeitamente. As cores estão sendo modificadas conforme necessário. Isso ocorre porque tenho uma extensão instalada, especificamente a extensão do Prisma. Do lado esquerdo, clicamos no ícone de extensões e no campo de busca na parte superior digitamos "prisma".

Essa extensão do Prisma, presente no meu VS Code, realiza exatamente essa função: realçar o código escrito e também fornecer sugestões de preenchimento automático (autocomplete). Portanto, ela me sugeriu o @id, o autoincrement, e outras funcionalidades semelhantes.

Vamos seguindo. Além disso, pegamos um name, que vai ser uma string. Teremos o username da nossa pessoa usuária, que também vai ser um string.

schema.prisma

// código omitido

model User {
  id Int @id @default(autoincrement())
  name String
  username String
}

Neste ponto, temos um detalhe.

Se estamos falando de um username, não podemos ter mais de um usuário com o mesmo nome. E conseguimos proteger isso quando estamos falando de banco de dados. Para indicar para o Prisma que esse campo é o único e não pode ter valores repetidos. Então, vamos colocar a anotação @unique.

schema.prisma

// código omitido

model User {
  id Int @id @default(autoincrement())
  name String
  username String @unique
}

Temos o id, o name, o username, e também temos o avatar, que vai ser também uma string.

schema.prisma

// código omitido

model User {
  id Int @id @default(autoincrement())
  name String
  username String @unique
  avatar String
}

Você pode estar se perguntando de onde vêm esses id, name, username e avatar. No curso anterior, nós utilizamos uma API que fornecia esses dados. Agora, estou com o repositório aberto, então se quiser mais detalhes, fique à vontade para explorá-lo. Mas se preferir não se aprofundar, confie em mim, vou revisitar o projeto antigo e garantir que tudo funcione corretamente.

Criamos a nossa model de user. Vamos seguir para a nossa model, que representa agora um post.

Criando a model Post

Digitamos na sequência "model Post".

schema.prisma

// código omitido

model User {
  id Int @id @default(autoincrement())
  name String
  username String @unique
  avatar String
}

model Post {

}

Temos o posts.json, onde você pode visualizar de onde vêm esses dados iniciais, mas isso é para podermos pegar esses campos que vamos precisar. Deixei aberto no fundo o posts.json, vou trazer o VSCode para frente, porque vamos precisar analisar os dois. E vamos começar a escrever o nosso código.

O model Post vai ter também um id inteiro, que é um @id, e por padrão tem um autoincrement. Além disso, ele vai ter uma coluna chamada cover, que é onde está a capa, o endereço para a nossa imagem, que vai ser string. Vai ter um title, que também é string. Também vai ter um slug, que é um string. A ideia do slug é a mesma do username.

Queremos que o slug seja o único, que é um texto que conseguimos ler, mas que identifica de forma única o post dentro da nossa tabela. Então, id, cover, que é a capa, o title, que é o título, o slug.

schema.prisma

// código omitido

model User {
  id Int @id @default(autoincrement())
  name String
  username String @unique
  avatar String
}

model Post {
  id Int @id @default(autoincrement())
  cover String
  title String
  slug String @unique
}

O que mais? Temos o body, que é o conteúdo em si do nosso post, que também será uma string. Temos o id, cover, title, slug, body, o markdown, que também será uma string.

schema.prisma

// código omitido

model User {
  id Int @id @default(autoincrement())
  name String
  username String @unique
  avatar String
}

model Post {
  id Int @id @default(autoincrement())
  cover String
  title String
  slug String @unique
  body String
  markdown String
}

Agora, o que desejamos fazer? Desejamos mapear.

Desejamos informar para o Prisma que esse usuário vai possuir um ou mais posts. É um relacionamento que vamos criar. Então, como vamos fazer isso? Vamos indicar no model User que temos Post, o nosso P, com P maiúsculo mesmo, porque queremos relacionar as tabelas. Vamos dizer que ele é do tipo Post[], só que ele é um array. Um usuário pode ter múltiplos posts.

schema.prisma

// código omitido

model User {
  id Int @id @default(autoincrement())
  name String
  username String @unique
  avatar String
  Post Post[]
}

model Post {
  id Int @id @default(autoincrement())
  cover String
  title String
  slug String @unique
  body String
  markdown String
}

Observe que temos um sublinhado na cor vermelha abaixo. Ao passarmos o mouse por cima, temos indicado pela próprio VSCode que o campo Post dentro de user está sendo relacionado com posts, mas o relacionamento inverso ainda não existe.

Mensagem em inglês exibida no VSCode:

Error validating field 'Post' in model 'User': The relation field Post on model 'User' is missing an opposite relation field on the model 'Post'. Either run 'prisma format' or add it manually.

Então, ou você pede para o Prisma formatar isso para você, ou adicionar manualmente. Adicionaremos manualmente para entendermos como o Prisma lida com isso.

Na nossa model Post, informamos que temos um autor, author. Esse author, ele é do tipo User. E informamos agora como que mapeamos a nossa relation, que é a nossa relação. Para isso, usamos @relation(). Como que post se relaciona com user.

Chamamos o @relation() para iniciar a montagem, começando com os fields. Nosso primeiro campo dentro da tabela post, representando um usuário, será o authorId. Este campo vai referenciar o id do usuário. Em outras palavras, na tabela Post, teremos a coluna authorId, que apontará para o id da pessoa usuária.

schema.prisma

// código omitido

model Post {
  id Int @id @default(autoincrement())
  cover String
  title String
  slug String @unique
  body String
  markdown String
  author User @relation(fields: [authorId], references: [id])
}

Há um sublinhado na cor vermelha abaixo de authorId porque ainda não criamos esse campo. Então criamos ele acima do nosso relacionamento. Então, authorId vai ser um inteiro.

schema.prisma

// código omitido

model Post {
  id Int @id @default(autoincrement())
  cover String
  title String
  slug String @unique
  body String
  markdown String
  authorId Int
  author User @relation(fields: [authorId], references: [id])
}

Agora, sim. O nosso authorId, ele aponta para o nosso usuário.

Conclusão e Próximos Passos

Já mapeamos a estrutura da nossa tabela, o nosso author, que é um usuário, e o nosso post.

Agora estamos prontos para dar o próximo passo: vamos conectar isso. Esse prisma tem que criar essa tabela, essa estrutura lá no Postgres. Vamos fazer isso no próximo vídeo.

Sobre o curso Next.js: construa suas aplicações com Postgres e Prisma

O curso Next.js: construa suas aplicações com Postgres e Prisma possui 108 minutos de vídeos, em um total de 43 atividades. Gostou? Conheça nossos outros cursos de Next.JS em Front-end, ou leia nossos artigos de Front-end.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda Next.JS acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas