javajsonspringjacksonobjectmapper

Getting JSON from URL (from API that need an authentication token) SPRING


I am trying to build database - and i want to get data that i need from API which have an authentication token - im using Java, Spring, MySql DB

I've created simple example of what i want to achieve - in this example i DONT need additional header with authentication token - and my question is can i get data this way when i need to add one:

@Component
public class DataLoader implements CommandLineRunner {
    private final ObjectMapper mapper;
    private final CountryRepository repository;

    public DataLoader(ObjectMapper mapper, CountryRepository repository) {
        this.mapper = mapper;
        this.repository = repository;
    }

    @Override
    public void run(String... args) throws Exception {
        List<Country> countries = new ArrayList<>();
        JsonNode json;

        try {
            json = mapper.readValue(new URL("https://api.football-data.org/v4/areas"), JsonNode.class);
        } catch (IOException e) {
            throw new RuntimeException("Failed to read JSON data", e);
        }

        JsonNode areas = getAreas(json);

        for (JsonNode area : areas) {
            countries.add(createCountryFromNode(area));
        }

        repository.saveAll(countries);
    }

    private Country createCountryFromNode(JsonNode area) {
        String code = area.get("countryCode").asText();
        String name = area.get("name").asText();

        return new Country(code, name);
    }

    private JsonNode getAreas(JsonNode json) {
        return Optional.ofNullable(json)
                .map(j -> j.get("areas"))
                .orElseThrow(() -> new IllegalArgumentException("Invalid JSON Object"));
    }
}

So, in example above, when i use readValue() method, everything works fine, i get JSON, and i can work with it - BUT, when i want to use for example:

"https://api.football-data.org/v4/competitions/PL"

instead of:

"https://api.football-data.org/v4/areas"

my response will look like this:

"message": "The resource you are looking for is restricted and apparently not within your permissions. Please check your subscription.",
"errorCode": 403

Ive created account, i got my personal token, i got all permissions now, but i have to add this token as HTTP header.

FINALLY:

Can I add header with key token to an URL in mapper.readValue() method?

Is there any way to parse JSON by Jackson with api that have a key token? Spring annotations, anything? Or maybe i have to use "raw" Java classes (HttpRequest, HttpResponse etc.)?


Solution

  • We can't add headers using ObjectMapper. Use RestTemplate instead:

            HttpHeaders headers = new HttpHeaders();
            headers.set("X-Auth-Token", "my-new-auth-token");
            HttpEntity<String> requestEntity = new HttpEntity<>(headers);
    
            RestTemplate restTemplate = new RestTemplate();
            ResponseEntity<String> response = restTemplate.exchange("https://api.football-data.org/v4/competitions/PL", HttpMethod.GET, requestEntity, String.class);
    
            JsonNode json = mapper.readTree(response.getBody());
    

    Always use restTemplate.exchange method for API calls in spring/springboot. It's simple, easy to use, supports headers, works with any http method, helps in conversion to any Java object. It has been there since ages.

    Also, I would suggest you use Java class, instead of JsonNode.

    public class AreaResponse {
        private List<Area> areas;
        //... getter/setters/etc
    }
    

    Create Area class & put countryCode/name parameters & instead of String.class as response type, you can provide your class AreaResponse while calling the api:

        restTemplate.exchange("https://api.football-data.org/v4/competitions/PL", HttpMethod.GET, requestEntity, AreaResponse.class)
    

    This will even save you more boiler plate code to extract data from JsonNode object.