Como rodar o WireMock em um container Docker (sem complicação)
Bom, eu estava fazendo o desafio backend do PicPay em Spring Boot e precisava simular serviços externos de autorização e notificação. O problema é que, observando o repositório do desafio, eu percebi que os links disponibilizados para simular esses serviços viviam quebrando, ficando offline ou simplesmente parando de funcionar do nada.
Então comecei a procurar uma forma de contornar isso e percebi que poderia mockar essas chamadas externas localmente. Basicamente, simular os endpoints como se a aplicação estivesse conversando com o serviço real.
Como eu já estava usando Docker para subir o banco de dados da aplicação, pensei:
“Por que não adicionar mais um container pra isso também?”
Além de resolver o problema, ainda seria uma boa oportunidade pra praticar mais Docker no processo.
Só que aí veio outro problema...
Praticamente todo tutorial que eu encontrava sobre WireMock com Docker:
- era antigo
- misturava várias formas diferentes de uso
- não explicava a estrutura dos arquivos
- assumia que você já entendia Docker
- ou simplesmente jogava um monte de configuração sem explicar muita coisa
Então resolvi documentar aqui a forma mais simples que encontrei pra subir tudo usando containers.
Por que usar o WireMock?
Então, essa é uma boa pergunta na verdade 😄.
Quando comecei a pesquisar formas de mockar chamadas HTTP externas, eu percebi que existiam várias ferramentas diferentes pra resolver esse problema.
As que eu mais encontrei foram:
- MockServer
- Rest Assured
- Restito
- e o próprio WireMock
No começo eu achei que todas faziam praticamente a mesma coisa. E, sendo bem sincero, até fazem em alguns cenários.
Mas conforme fui lendo a documentação e testando algumas abordagens, comecei a perceber que cada uma resolve problemas um pouco diferentes.
MockServer
O MockServer me pareceu uma solução bem poderosa e flexível, principalmente pra cenários mais complexos.
Ele permite:
- mockar HTTP e HTTPS
- validar requests
- criar expectativas mais avançadas
- rodar em container facilmente
Mas, pra minha necessidade naquele momento, achei a configuração um pouco mais verbosa do que eu precisava.
Rest Assured
O Rest Assured aparece MUITO quando o assunto é teste de APIs em Java.
Só que ele é mais focado em testes automatizados de APIs do que em simular um serviço HTTP rodando separadamente.
Então, apesar de ser excelente pra testes, ele não era exatamente o que eu queria naquele cenário.
Restito
O Restito foi uma ferramenta que achei interessante porque ela é bem simples e direta.
Mas eu senti falta de:
- mais exemplos modernos
- comunidade maior
- mais conteúdos usando Docker
Então por que escolhi o WireMock?
No final, acabei escolhendo o WireMock porque ele tinha exatamente o equilíbrio que eu estava procurando:
- simples de subir com Docker
- configuração relativamente fácil
- muito usado pela indústria
- bastante material da comunidade
- suporte muito bom pra mockar APIs REST
Além disso, gostei bastante da estrutura baseada em arquivos JSON, já que fica fácil visualizar os endpoints mockados e versionar tudo junto do projeto.
E como meu objetivo era simular serviços externos do desafio do PicPay da forma mais simples possível, ele acabou encaixando perfeitamente.
O que vamos fazer
Pra ficar mais fácil de acompanhar, vou dividir esse processo em 3 partes:
- Parte I → Subindo o WireMock com Docker
- Parte II → Criando os endpoints mockados
- Parte III → Integrando com a aplicação Spring
Parte I: Mão na massa
Primeiro você precisa criar um arquivo docker-compose.yaml.
É nele que vamos definir:
- qual imagem o Docker vai baixar
- nome do container
- portas
- volumes
- e outras configurações do serviço
Para subir o WireMock, o compose fica mais ou menos assim:
services:
wiremock:
image: wiremock/wiremock:3.13.2
container_name: my_wiremock
ports:
- "8089:8080"
volumes:
- ./wiremock:/home/wiremock
Se você já conhece um pouco de Docker, pode pular essa explicação sem problemas 😄.
Agora entendendo cada parte:
image
Aqui estamos dizendo qual imagem o Docker deve usar.
image: wiremock/wiremock:3.13.2
Se essa imagem não existir localmente, o Docker vai baixá-la automaticamente do Docker Hub.
container_name
container_name: my_wiremock
Define o nome do container.
Isso facilita bastante na hora de:
- visualizar containers
- acessar logs
- executar comandos
ports
ports:
- "8089:8080"
Aqui estamos fazendo um mapeamento de portas:
porta_da_maquina:porta_do_container
Ou seja:
- tudo que acessar a porta
8089da sua máquina - será redirecionado para a porta
8080dentro do container
Então o WireMock ficará acessível em:
http://localhost:8089
volumes
volumes:
- ./wiremock:/home/wiremock
Aqui estamos criando um volume entre:
- a pasta
wiremockda nossa máquina - e a pasta
/home/wiremockdentro do container
Isso é importante porque o WireMock lê os arquivos de configuração diretamente desse diretório.
Na prática, isso permite:
- editar mappings localmente
- versionar os mocks no Git
- não perder configurações ao reiniciar o container
Agora basta executar:
docker compose up -d
E pronto 🚀!!
Seu container do WireMock já estará rodando.
Para verificar se deu tudo certo, você pode executar:
docker ps
Esse comando mostra todos os containers que estão rodando atualmente.
Se você usa o Docker Desktop, também pode visualizar:
- containers na aba
Containers - imagens na aba
Images
Além disso, você pode acessar no navegador:
http://localhost:8089/__admin
Se a interface administrativa do WireMock aparecer:
✅ deu tudo certo.
Parte II: Criando os mocks
Depois de executar:
docker compose up -d
você terá uma estrutura parecida com essa:
aplicacao-java/
├── gradle/
├── docker-compose.yml
├── src/
│ ├── main/
│ └── test/
└── wiremock/
├── mappings/
└── __files/
O que significa cada pasta?
-
mappings/Aqui ficam os arquivos
.jsonresponsáveis por definir os endpoints mockados. -
__files/Pasta usada para armazenar arquivos auxiliares, como responses maiores, templates e payloads externos.
Em cenários simples, ela geralmente é opcional.
Agora vamos criar nosso primeiro endpoint mockado dentro da pasta mappings.
Exemplo:
{
"request": {
"method": "GET",
"urlPath": "/api/v1/authorize",
"queryParameters": {
"scenario": {
"equalTo": "success"
}
}
},
"response": {
"status": 200,
"jsonBody": {
"status": "success",
"data": {
"authorization": true
}
},
"headers": {
"Content-Type": "application/json"
}
}
}
O que está acontecendo aqui?
Por causa dessa configuração no docker-compose.yml:
volumes:
- ./wiremock:/home/wiremock
o container passa a enxergar a pasta local:
./wiremock
como:
/home/wiremock
dentro dele.
E o WireMock, por padrão, procura automaticamente os mappings em:
/home/wiremock/mappings
Ou seja, ele:
- encontra os arquivos
.json - carrega os endpoints automaticamente
- disponibiliza as rotas mockadas
Na maioria dos casos o WireMock detecta mudanças automaticamente nos mappings.
Mas, caso algum endpoint novo não apareça imediatamente, você pode reiniciar o container com:
docker compose restart
Testando pra ver se deu certo
Você pode ir no terminal e rodar o comando abaixo, ou simplesmente acessar esse link no navegador:
curl "http://localhost:8089/api/v1/authorize?scenario=success"
Nos dois casos será retornado algo assim:
{
"status": "success",
"data": {
"authorization": true
}
}
Se quiser visualizar melhor a resposta formatada no terminal:
curl "http://localhost:8089/api/v1/authorize?scenario=success" | jq
E aqui vem a parte interessante.
Talvez você esteja se perguntando:
“Como o WireMock sabe exatamente o que retornar?”
Porque foi exatamente isso que definimos no arquivo .json 😄
Perceba que nem existe backend Java rodando nesse momento. Quem está respondendo tudo isso é somente o WireMock.
E ele faz isso baseado em duas partes principais:
requestresponse
request section
"request": {
"method": "GET",
"urlPath": "/api/v1/authorize"
}
Isso significa:
quando alguém fizer um GET para essa rota
response section
"response": {
"status": 200
}
Isso significa:
responda com status HTTP 200
queryParameters
"queryParameters": {
"scenario": {
"equalTo": "success"
}
}
Isso significa:
a query parameter precisa conter ?scenario=success
Ou seja, o endpoint só será acionado corretamente se a URL for:
/api/v1/authorize?scenario=success
Parte III: Integrando com a aplicação Spring
Agora que já conseguimos acessar as URLs do nosso mini servidor mockado, podemos conectar ele ao código Java da aplicação.
Bom, você pode fazer isso de duas maneiras diferentes.
Opção 1: Configurando no application.yml
external:
authorization:
url: http://localhost:8089/api/v1/authorize
notification:
url: http://localhost:8089/api/v1/notify
E depois acessando no código:
@Value("${external.authorization.url}")
private String authorizationUrl;
Essa abordagem é legal porque deixa as URLs centralizadas e facilita trocar ambientes futuramente.
Opção 2: URL direto no código
Você também pode simplesmente salvar a URL em uma variável:
String url = "http://localhost:8089/api/v1/authorize";
Para cenários simples isso funciona tranquilamente também.
Como falei no começo do artigo, o desafio do PicPay possuía duas integrações externas:
- autorização
- notificação
Então precisei criar tanto cenários de sucesso quanto de falha para cada uma delas.
Minha estrutura final ficou assim:
wiremock/
├── mappings/
│ ├── authorize-success.json
│ ├── authorize-fail.json
│ ├── notify-success.json
│ └── notify-fail.json
└── __files/
Depois de estruturar tudo assim, eu consegui desenvolver e testar minha aplicação sem depender dos endpoints externos do desafio.
Além disso, ficou muito mais fácil:
- simular falhas
- testar cenários específicos
- desenvolver offline
- manter os mocks versionados junto do projeto
Conclusão
No final das contas, o WireMock resolveu exatamente o problema que eu tinha:
parar de depender de APIs externas instáveis durante o desenvolvimento. E, cara, sinceramente? Depois que você entende a estrutura básica dele, o WireMock deixa de parecer complicado e vira uma ferramenta extremamente útil no dia a dia de backend.
Principalmente quando você começa a trabalhar com:
- microsserviços
- integrações externas
- testes de integração
- ambientes isolados
Se você chegou até aqui, espero que esse artigo tenha conseguido te poupar as mesmas dores de cabeça que eu tive procurando documentação 😄. Vou deixar nas referências alguns dos artigos que usei durante o desenvolvimento do desafio e na escrita desse artigo.