Construindo APIs REST com API Platform e MongoDB
Aasawari Sahasrabuddhe9 min read • Published Jan 09, 2025 • Updated Jan 14, 2025
APLICATIVO COMPLETO
Classifique este artigo
Os aplicativos web de hoje dependem de grandes conjuntos de dados e exigem interação com o banco de dados em tempo real. Os desenvolvedores geralmente enfrentam o desafio de gerenciar e dimensionar com eficiência as operações CRUD (Create, Read, Update, Delete) e, ao mesmo tempo, manter a flexibilidade, o desempenho e a segurança. No entanto, a criação de uma API padrão geralmente vem com desafios significativos: documentar endpoints, mapeá-los para o banco de dados, lidar com a transformação de dados e garantir a validação - tudo enquanto mantém o desempenho, a escalabilidade e a segurança.
Criar um aplicação com a API Platform fornece uma solução robusta, flexível e fácil de usar para criar APIs modernas. Quando perfeitamente integrado ao MongoDB, ele habilita os desenvolvedores a lidar com eficiência com operações CRUD, mantendo a escalabilidade e a facilidade de uso.
Neste tutorial, usaremos a API Platform com Symfony para construir APIs REST que executam operações CRUD no banco de dados MongoDB . Para conectar o aplicação ao MongoDB, usaremos o MongoDB Atlas.
- Docker instalado
Para começar com o projeto Symfony usando a API Platform, siga as etapas descritas abaixo:
- Crie o projeto modelo , que gera todos os arquivos necessários para você. Para fazer isso, gere um repositório do Github com sua escolha de nome usando o modelo de
api-platform
repositório. Você pode consultar a captura de tela abaixo para preencher as entradas.

1 git clone <URL to your repository>
Depois de ter o código em sua máquina local, editaremos o aplicação para se conectar ao MongoDB.
Para saber mais, você pode seguir as etapas mencionadas na documentação de Introdução à API Platform para o Symfony.
Na próxima seção, entenderemos como conectar seu aplicação ao cluster MongoDB Atlas e executar as operações CRUD nas coleções dentro do cluster.
Depois que seu aplicação de amostra estiver sendo executado corretamente, a próxima etapa é se conectar ao MongoDB Atlas. Para fazer isso, primeiro precisaremos criar um Atlas cluster gratuito e obter a string de conexão.
Para obter a string de conexão, clique em Conectar e selecione o driver apropriado com a versão correta. Você verá uma tela como a abaixo; copie a string de conexão e mantenha-a segura com você.

Depois de ter a string de conexão, a próxima etapa é atualizar o Dockerfile e instalar as extensões PHP. O Dockerfile para instalar as extensões está disponível dentro da pasta API/.
Atualize o arquivo com o código abaixo para instalar extensões PHP.
- Adicione as alterações de código abaixo ao Dockerfile que você precisará atualizar:
1 RUN apt-get update && apt-get install --no-install-recommends -y \ 2 libcurl4-openssl-dev \ 3 libssl-dev \ 4 && pecl install mongodb \ 5 && docker-php-ext-enable mongodb
Após a atualização, execute o comando a partir da pasta raiz do projeto para instalar as extensões. Nesse caso, vá para <location where="" git="" clone="" was="" done="" repository="" name="">.</location>
1 docker compose build --no-cache
- Atualize o .env com a string de conexão e o nome do banco de dados .
1 MONGODB_URL=<Atlas URI> 2 MONGODB_DB=Test
1 services: 2 php: 3 image: ${IMAGES_PREFIX:-}app-php 4 depends_on: 5 - pwa 6 environment: 7 MONGODB_URL: <Atlas URI>
- Depois que as extensões forem instaladas, precisamos iniciar os contêineres e instalar o pacote ODM.
1 docker compose up --wait
Quando os contêineres estiverem ativos e prontos, execute os comandos abaixo para instalar o pacote ODM.
1 docker compose exec php \ 2 composer require doctrine/mongodb-odm-bundle api-platform/doctrine-odm
O mongodb-odm-bundle é um pacote (um pacote modular de código) que integra o MongoDB ODM ao Symfony. Esta biblioteca fornece uma funcionalidade de mapeamento de objeto PHP para MongoDB.
Quando estiver pronto para fazer as conexões do MongoDB Atlas , a próxima etapa é criar APIs REST para executar operações CRUD.
Neste tutorial, estamos usando uma coleção simples chamada Restaurantes, que terá os seguintes valores de campo :
1 { 2 "name": "The Gourmet Spot", 3 "address": { 4 "building": "123", 5 "street": "Elm Street", 6 "zipcode": "12345" 7 }, 8 "borough": "Manhattan", 9 "cuisine": "Italian" 10 }
Depois que a estrutura do documento for definida, a próxima etapa será criar o Documento e a classe Controlador.
A classe Documento é criada em API/src/Document/Restaurant.php.
A classe Documento é criada em API/src/Document/Restaurant.php.
1 2 3 namespace App\Document; 4 5 use ApiPlatform\Metadata\ApiResource; 6 use App\Repository\RestaurantRepository; 7 use Doctrine\ODM\MongoDB\Mapping\Annotations\Document; 8 use Doctrine\ODM\MongoDB\Mapping\Annotations\Field; 9 use Doctrine\ODM\MongoDB\Mapping\Annotations\Id; 10 11 12 collection: 'restaurants') (13 class Restaurant 14 { 15 16 public string $id; 17 18 19 public string $name; 20 21 22 public array $address; 23 24 25 public string $borough; 26 27 28 public string $cuisine; 29 }
O endereço.php será parecido com:
1 2 3 namespace App\Document; 4 5 use Doctrine\ODM\MongoDB\Mapping\Annotations\EmbeddedDocument; 6 use Doctrine\ODM\MongoDB\Mapping\Annotations\Field; 7 8 9 class Address 10 { 11 12 public string $building; 13 14 15 public string $street; 16 17 18 public string $zipcode; 19 }
Depois que o código estiver definido, execute o comando abaixo para executar o aplicação completo.
1 HTTP_PORT=8080 HTTPS_PORT=8443 docker-compose up
A próxima etapa é acessar as APIs de acesso que foram criadas. O URI abaixo leva você até a plataforma da API para testar as chamadas da API REST.
1 https://localhost:8443/docs
A API Platform oferece suporte nativo ao formato de documentação da API Open API (anteriormente Atlas). Ele também integra uma versão personalizada da UI do MongoDB, uma boa ferramenta para exibir a documentação da API de forma amigável.
Esta página no URI abaixo terá a seguinte aparência:
figura:3 imagem mostrando captura de tela para a plataforma de API sando

Vamos testar essas APIs REST.
Para testar a API CREATE, vá para o método POST e coloque o JSON como:
1 { 2 "name": "The Gourmet Spot", 3 "address": { 4 "building": "123", 5 "street": "Elm Street", 6 "zipcode": "12345" 7 }, 8 "borough": "Manhattan", 9 "cuisine": "Italian" 10 }
Clique em "Try it out" e você verá que o documento abaixo foi inserido na coleção:

Para verificar, navegue até o cluster do Atlas e verifique se os dados foram inseridos na coleção test.Restaurants. A captura de tela abaixo mostra que os dados foram inseridos no banco de dados.

Para obter todos os documentos da coleção, você pode simplesmente usar a API GET para obter todos os documentos. Para obter um documento específico da coleta, execute a API GET conforme especificado.
Imagem 6: captura de tela do swigger representando a solicitação GET

Há duas operações para atualizar um documento existente. O PUT substitui o documento completo e o PATCH atualizará apenas as propriedades enviadas. Normalmente, apenas o PATCH é usado, e é por isso que a operação PUT está desabilitada por padrão. Para obter mais informações, você pode consultar a documentação de Operações de plataforma API.
Para testar essa API, atualizamos o documento JSON acima como:
1 { 2 "name": "The Gourmet Spot", 3 "address": { 4 "building": "123", 5 "street": "Elm Street", 6 "zipcode": "12345" 7 }, 8 "borough": "New York", 9 "cuisine": "Spanish" 10 }
A API resulta em:

O documento também é atualizado no Atlas cluster.
Imagem 8: captura de tela da UI do Atlas representando a atualização do documento

Por fim, para excluir informações específicas de um restaurante com um _id, executamos a chamada API como:

Os testes acima abrangem as operações CRUD básicas: Criar, Ler, Atualizar, Excluir. Mas a plataforma de API vai muito além disso. Ele possui muitos recursos que permitem criar APIs mais poderosas e dinâmicas com o mínimo de trabalho.
Vamos ver cada um deles em detalhes na próxima seção.
A plataforma de API simplifica a criação e a aplicação de validações para que suas regras de integridade de dados sejam aplicadas de forma consistente sem a necessidade de escrever muito código personalizado. E também é ótimo na pesquisa avançada, para que você possa executar queries complexas com facilidade. Ele também permite que você aplique filtros, execute validações de regex e muito mais.
Se você deseja colocar validações no campo como valores obrigatórios, definimos os valores de campo como #[Assert\NotBlank] antes dos valores de campo . Por exemplo, no código abaixo, marcamos o nome, bairro e localidade como os valores obrigatórios.
1 class Restaurant 2 { 3 #[Id] 4 public string $id; 5 6 #[Field] 7 #[Assert\NotBlank] 8 #[Assert\Length(max: 255)] 9 public string $name; 10 11 #[EmbedOne(targetDocument: Address::class)] 12 #[Assert\Valid] 13 public ?Address $address; 14 15 #[Field] 16 #[Assert\NotBlank] 17 public string $borough; 18 19 #[Field] 20 #[Assert\NotBlank] 21 public string $cuisine; 22 }
Como resultado, se uma solicitação for enviada com qualquer um dos valores ausentes, um erro de HTTP será retornado. A captura de tela abaixo mostra um exemplo de um nome ausente na solicitação POST.

Precisamos adicionar o código aos Validadores para adicionar essa validação. Esse código deve estar disponível na pasta API/src/Validator/Constraints/ .
1 <?php 2 3 namespace App\Validator\Constraints; 4 5 use Symfony\Component\Validator\Constraint; 6 use Symfony\Component\Validator\ConstraintValidator; 7 8 final class MinimalPropertiesValidator extends ConstraintValidator 9 { 10 public function validate($value, Constraint $constraint): void 11 { 12 if (array_diff(['name', 'cuisine', 'bourough'], $value)) { 13 $this->context->buildViolation($constraint->message)->addViolation(); 14 } 15 } 16 }
E:
1 <?php 2 3 namespace App\Validator\Constraints; 4 5 use Symfony\Component\Validator\Constraint; 6 7 #[Attribute] 8 class MinimalProperties extends Constraint 9 { 10 public $message = 'The product must have the minimal properties required ("name", "cuisine", "bourough")'; 11 }
Este código define uma lógica de validação personalizada no Symfony. A classeMinimalPropertiesValidator é responsável por validar se uma array contém as chaves necessárias: nome, cozinha e bairro.
O métodovalidate verifica se alguma dessas chaves está ausente usando array_diff e, se a validação falhar, dispara uma violação com uma mensagem de erro.
A classeMinimalProperties atua como a restrição personalizada, com sua propriedade de mensagem mantendo o texto de erro exibido em caso de falha.
Da mesma forma, se você deseja adicionar o validador para o CEP fornecido nos valores do campo Endereço, adicione o código abaixo na pasta API/src/Validator/Constraints/ como:
1 <?php 2 3 namespace App\Validator\Constraints; 4 5 use Symfony\Component\Validator\Constraint; 6 use Symfony\Component\Validator\ConstraintValidator; 7 8 final class ValidZipcodeValidator extends ConstraintValidator 9 { 10 public function validate($value, Constraint $constraint): void 11 { 12 if (!$constraint instanceof ValidZipCode) { 13 throw new InvalidArgumentException(sprintf('Expected instance of %s, got %s.', ValidZipCode::class, get_class($constraint)));} 14 15 if (!preg_match('/^[0-9]{5}$/', $value)) { 16 $this->context->buildViolation($constraint->message) 17 ->setParameter('{{ value }}', $value) 18 ->addViolation();} 19 } 20 }
E:
1 <?php 2 3 namespace App\Validator\Constraints; 4 5 use Symfony\Component\Validator\Constraint; 6 7 #[Attribute] 8 class ValidZipCode extends Constraint 9 { 10 public $message = 'The zipcode "{{ value }}" is not valid. It must be exactly 5 digits.'; 11 }
No código acima, oValidZipcodeValidator cria a validação de que o CEP só pode ser numérico e apenas cinco caracteres serão permitidos. Para qualquer outro CEP, ele deve lançar o erro conforme mencionado na classeValidZipCode.
Você também precisa declarar a função no Endereço.php como:
1 #[Field] 2 #[ValidZipCode] 3 public string $zipcode;
Para testar isso, podemos enviar a solicitação POST como:
1 { 2 "name": "Dim Sum Express", 3 "address": { 4 "building": "404", 5 "street": "Chinatown Blvd", 6 "zipcode": "abcnn" 7 }, 8 "borough": "Manhattan", 9 "cuisine": "Chinese" 10 }
A solicitação acima deve resultar em um erro de HTTP com código 422 e uma mensagem informando:
1 The zipcode \"abcnn\" is not valid. It must be exactly 5 digits
A captura de tela abaixo exibe a mensagem de erro com a solicitação POST.

A plataforma API permite aplicar filtros e critérios de classificação nas coleções. O filtro de pesquisa suporta estratégias de correspondência exatas, parciais, iniciais, finais e word_start. Você pode ler mais sobre filtros na documentação da plataforma API em filtros de pesquisa.
Em nosso caso, aplicaremos filtros de pesquisa aos campos nome e cozinha usando o código abaixo dentro da classe Documento.
1 #[ApiFilter( 2 SearchFilter::class, 3 properties: [ 4 'name' => 'ipartial', The "ipartial" strategy will use a case-insensitive partial match 5 'cuisine' => 'exact', The "exact" strategy will use an exact match 6 ]) 7 ]
Como o comentário sugere, temos um filtro parcial que diferencia maiúsculas de minúsculas para o nome e um filtro de correspondência exata nos campos de gastronomia.
Para testar isso, temos dados de amostra já sendo armazenados dentro da coleção como:
1 db.restaurants.find() 2 [ 3 { 4 _id: ObjectId('6750aa7acda8e992af0c97b4'), 5 name: 'The Gourmet Spot', 6 address: { building: '123', street: 'Elm Street', zipcode: '12345' }, 7 borough: 'Manhattan', 8 cuisine: 'Italian' 9 }, 10 { 11 _id: ObjectId('6750b8406868c9f4fb012be5'), 12 name: 'Burger Bliss', 13 address: { building: '789', street: 'Main Street', zipcode: '54321' }, 14 borough: 'Queens', 15 cuisine: 'American' 16 }, 17 { 18 _id: ObjectId('6750b8516868c9f4fb012be8'), 19 name: 'Curry Delight', 20 address: { building: '202', street: 'Spice Lane', zipcode: '45678' }, 21 borough: 'Staten Island', 22 cuisine: 'Indian' 23 }, 24 { 25 _id: ObjectId('6750b85e6868c9f4fb012beb'), 26 name: 'Pasta Paradise', 27 address: { building: '303', street: 'Olive Way', zipcode: '11223' }, 28 borough: 'Manhattan', 29 cuisine: 'Italian' 30 }, 31 { 32 _id: ObjectId('6750b86e6868c9f4fb012bee'), 33 name: 'Pizza Kingdom', 34 address: { building: '606', street: 'Pizza Lane', zipcode: '77889' }, 35 borough: 'Queens', 36 cuisine: 'Italian' 37 } 38 ]
Agora, para aplicar o filtro de pesquisa, enviamos a solicitação GET com o nome da cozinha Italiana e devemos ver todos os restaurantes com
cuisine: 'Italian'.

Da mesma forma, enviamos uma solicitação GET com um nome parcial como "nome": "Macarrão ...", e devemos ter um restaurante com o nome “Pasta Paradise.”

Você pode criar mais chamadas de API com base no requisito, estendendo o código disponível no repositório do Github e seguindo a documentação da API Platform.
Concluindo, vimos como a API Platform permite criar rapidamente uma API REST para executar operações CRUD em um banco de dados MongoDB . Essa estrutura também permite adicionar recursos à API, como validação de dados e filtros de query, mantendo o código altamente abrangente e escalável. Os programadores podem trabalhar em um ambiente local usando Docker e Atlas.
O tutorial também demonstra como estabelecer a conexão, configurar o ambiente e executar operações CRUD básicas usando um exemplo simples, destacando a flexibilidade e a facilidade de trabalhar com a plataforma API do Symfony.
Para explorar mais, considere mergulhar nos recursos avançados da API Platform, otimizar queries do MongoDB ou experimentar operações CRUD adicionais para atender às necessidades específicas do seu aplicação . Se quiser saber mais, visite a documentação da API Platform e do MongoDB.
Em caso de dúvidas, entre em contato com o Fórum da MongoDB Community e, para saber mais, consulte o Centro de desenvolvedores do MongoDB para obter mais artigos interessantes.
Principais comentários nos fóruns
Ainda não há comentários sobre este artigo.