Solucionado (ver solução)
Solucionado
(ver solução)
6
respostas

Duvida de como consumir uma API externa com spring

Estou com uma duvida para consumir end points publicos do IBGE, a aplicação retorna, porém os json não estão batendo quando chamo a URL pelo navegador, segue abaixo como são exibidos:

json pelo navegador url: https://servicodados.ibge.gov.br/api/v1/localidades/municipios/3509502/distritos 0 id 350950205 nome "Campinas" municipio id 3509502 nome "Campinas" microrregiao id 35032 nome "Campinas" mesorregiao id 3507 nome "Campinas" UF id 35 sigla "SP" nome "São Paulo" regiao id 3 sigla "SE" nome "Sudeste" regiao-imediata id 350038 nome "Campinas" regiao-intermediaria id 3510 nome "Campinas" UF id 35 sigla "SP" nome "São Paulo" regiao id 3 sigla "SE" nome "Sudeste" ......

json retornado pela aplicação:

{
    "headers": {
        "Date": [
            "Sat, 31 Jul 2021 00:15:18 GMT"
        ],
        "Server": [
            "Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips mod_qos/11.5"
        ],
        "Cache-Control": [
            "max-age=2592000"
        ],
        "Expires": [
            "Mon, 30 Aug 2021 00:08:15 GMT"
        ],
        "Access-Control-Allow-Headers": [
            "Content-Type"
        ],
        "Access-Control-Allow-Methods": [
            "GET"
        ],
        "Access-Control-Allow-Origin": [
            "*"
        ],
        "Age": [
            "424"
        ],
        "Content-Length": [
            "2343"
        ],
        "Connection": [
            "close"
        ],
        "Content-Type": [
            "application/json; charset=utf-8"
        ]
    },
    "body": [
        {
            "id": 350950205,
            "nome": "Campinas",
            "municipio": {
                "id": 3509502,
                "nome": "Campinas",
                "microRegiao": null,
                "regiaoImediata": null
            }
        },
        {
            "id": 350950210,
            "nome": "Barão Geraldo",
            "municipio": {
                "id": 3509502,
                "nome": "Campinas",
                "microRegiao": null,
                "regiaoImediata": null
            }
        },
        {
            "id": 350950215,
            "nome": "Joaquim Egídio",
            "municipio": {
                "id": 3509502,
                "nome": "Campinas",
                "microRegiao": null,
                "regiaoImediata": null
            }
        },
        {
            "id": 350950220,
            "nome": "Nova Aparecida",
            "municipio": {
                "id": 3509502,
                "nome": "Campinas",
                "microRegiao": null,
                "regiaoImediata": null
            }
        },
        {
            "id": 350950225,
            "nome": "Souzas",
            "municipio": {
                "id": 3509502,
                "nome": "Campinas",
                "microRegiao": null,
                "regiaoImediata": null
            }
        }
    ],
    "statusCode": "OK",
    "statusCodeValue": 200
}

gostaria de um auxilio para entender melhor como ajustar minha aplicaçaõ java para retornar esta lista corretamente, segue as classes que montei para retornar este serviço.

6 respostas

Classes DTO:

@Data
public class Regiao {

    private Long id;
    private String sigla;
    private String nome;

}

@Data
public class UF {

    private Long id;
    private String sigla;
    private String nome;
    private Regiao regiao;

}
@Data
public class MicroRegiao {


    private Long id;
    private String nome;
    private MesoRegiao mesoregiao;

}
@Data
public class MesoRegiao {


    private Long id;
    private String nome;
    private UF uf;

}
@Data
public class RegiaoIntermediaria {

    private Long id;
    private String nome;
    private UF uf;
}
@Data
public class RegiaoImediata {

    private Long id;
    private String nome;
    private RegiaoIntermediaria regiaoIntermediaria;

}

@Data
public class Municipio {


    private Long id;
    private String nome;
    private MicroRegiao microRegiao;
    private RegiaoImediata regiaoImediata;
}
@Data
public class Distritos {


    private Long id;
    private String nome;
    private Municipio municipio;
}

@Data
public class DistritosList {

    private List<Distritos> distritoList;


    public DistritosList() {

        distritoList = new ArrayList<>();
    }
}

Classe Service

@Service
public class IbgeService {


    public ResponseEntity<Distritos[]> retornarDistritos(String codIbge) {

        //https://servicodados.ibge.gov.br/api/v1/localidades/microrregioes/3509502/distritos
        String URI = "https://servicodados.ibge.gov.br/api/v1/localidades/microrregioes/"+codIbge+"/distritos";

          RestTemplate restTemplate = new RestTemplate();

          System.out.println("#### URL: "+ URI);
         // Distritos[] distritos = restTemplate.getForObject(URI, Distritos[].class);
          ResponseEntity<Distritos[]> distritos =  restTemplate.getForEntity(URI,Distritos[].class);


          return distritos;
    }

Controller

@RestController
@RequestMapping("/distrito")
public class DistritoController {

    @Autowired
    private IbgeService ibgeService;

    @GetMapping("/{numero}")
    public ResponseEntity<ResponseEntity<Distritos[]>> consultarDistrito(@PathVariable String numero) {

        ResponseEntity<Distritos[]> distritos = ibgeService.retornarDistritos(numero);
        return ResponseEntity.ok(distritos);
    }

Minha duvida é como retornar array de forma correta utilizando o RestTemplate e o que pode ser melhorado neste código, desde já muito obrigado.

Oi Marcos,

O codigo esta bacana e certinho :)

O RestTemplate deveria ter devolvido apenas o body com o json e nao os dados completos da resposta da requisicao.

De qualquer forma, o RestTemplate vai ser descontinuado em breve pelo Spring e agora voce deve realizar uma consulta Rest da seguinte maneira:

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
String url = "https://servicodados.ibge.gov.br";
String uri = "/api/v1/localidades/municipios/{codigoIbge}/distritos";

Distritos[] distritos = WebClient
            .create(url)
            .get()
            .uri(uri, codigoIbge)
            .retrieve()
            .bodyToMono(Distritos[].class).block();

Veja se assim funciona certinho.

Bons estudos!

Olá Rodrigo, obrigado pelo retorno, realizei a seguinte implementação porém o json ainda não vem populado corretamente, os arrays microregião e regiao imediata não são populados quando chamo pela minha aplicação:

classe service

public Distritos[] retornarDistritos2(String codIbge){
        String url = "https://servicodados.ibge.gov.br";
        String uri = "/api/v1/localidades/microrregioes/{codigoIbge}/distritos";

        Distritos[] distritos = WebClient
                    .create(url)
                    .get()
                    .uri(uri, codIbge)
                    .retrieve()
                    .bodyToMono(Distritos[].class).block();

        return distritos;
    }

Controller

    @GetMapping("/novo/{numero}")    
public ResponseEntity consultarDistritoWebFlux(@PathVariable String numero) {

        Distritos[] distritos = ibgeService.retornarDistritos2(numero);
        return ResponseEntity.ok(distritos);
    }

link de teste utlizado: https://servicodados.ibge.gov.br/api/v1/localidades/microrregioes/16003/distritos

link que utilizei no postman para testar a aplicação:http://localhost:8080/distrito/novo/16003

o código acima esta correto?

solução!

Oi Marcos,

O codigo esta correto sim.

O problema agora é que o nome de alguns dos seus atributos esta diferente do que vem no json.

Por exemplo, no json do ibge tem os atributos com esses nomes: microrregiao, mesorregiao e regiao-imediata, mas nas suas classes DTO os atributos estao com nomes que nao sao iguais: microRegiao, mesoregiao e regiaoImediata.

Por isso o Spring nao consegue fazer a conversao dessas informacoes para o DTO.

Voce pode utilizar a anotacao @JsonAlias nesses casos:

@JsonAlias("regiao-imediata")
private RegiaoImediata regiaoImediata

Realize esses ajustes que deve funcionar.

oi Rodrigo, usei a anotação indicada e funcionou corretamente muito obrigado!