API погоды назначения для REST API не возвращает данные JSON в почтальоне

Я создаю REST API в java и тестирую его в почтальоне, а в базе данных есть широта и долгота, я пытаюсь использовать API OpenWeather для возврата данных о погоде на основе широты и долготы. однако при тестировании в почтальоне он возвращает HTML, а не данные JSON, которые я запросил.

путь, который я пытаюсь проверить,

http://localhost:8080/Assignment2C/map/weather/4

код в моем контроллере

  @GetMapping(value = "weather/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
    public String getWeather(@PathVariable("id") int id) {
        BreweriesGeocode geocode = geocode_service.getGeocode(id);
        Breweries brewerie = breweries_service.getBrewerieById(id);

        double latitude = geocode.getLatitude();
        double longitude = geocode.getLongitude();
       String output = "https://api.openweathermap.org/data/2.5/weather?lat=" + latitude + "&lon=" + longitude + "&appid=4a1f5501b2798f409961c62d384a1c74";
       return output;

при использовании Postman он возвращает это

https: //api.openweathermap.org/data/2.5/weather?lat=59.74509811401367&lon=10.213500022888184&appid=4a1f5501b2798f409961c62d384a1c74

но когда я проверяю путь, который почтальон создает в браузере

https://api.openweathermap.org/data/2.5/weather?lat=59.74509811401367&lon=10.213500022888184&appid=4a1f5501b2798f409961c62d384a1c74

он возвращает правильные данные JSON

который

{"coord":{"lon":10.21,"lat":59.75},"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01d"}],"base":"stations","main":{"temp":291.36,"feels_like":289.49,"temp_min":288.71,"temp_max":294.26,"pressure":1028,"humidity":40},"wind":{"speed":0.89,"deg":190},"clouds":{"all":1},"dt":1587551663,"sys":{"type":3,"id":2006615,"country":"NO","sunrise":1587526916,"sunset":1587581574},"timezone":7200,"id":6453372,"name":"Drammen","cod":200}

как мне заставить данные JSON отображаться в почтальоне, когда я его тестирую?


person GreyWolf18    schedule 22.04.2020    source источник


Ответы (2)


Почтальон анализирует/показывает правильное значение, поскольку вы отправляете URL-адрес в ответе.

Чтобы вызвать API в вашем коде, вам нужно использовать HTTP-клиент/обработчик. Если вы просто назначите URL-адрес переменной, он просто сохранит его как строку и никогда не будет вызывать данный URL-адрес.

Класс RestTemplate (доступен по умолчанию в Spring, никаких других зависимостей не требуется) — это простой HTTP-клиент, который позволяет выполнять вызовы API из вашего кода.
Вы можете использовать RestTemplate для вызова OpenWeather API и получить ответ JSON, тот же ответ можно вернуть и просмотреть в Postman.


Если вы уверены, что собираетесь совершать только HTTP-вызовы, а не HTTPS, то следуйте подходу 1, в противном случае следуйте подходу 2 —

Подход 1:

@RestController
public class WeatherController{

    @Autowired
    RestTemplate restTemplate;

    @GetMapping(value = "weather/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
    public String getWeather(@PathVariable("id") int id) {
        BreweriesGeocode geocode = geocode_service.getGeocode(id);
        Breweries brewerie = breweries_service.getBrewerieById(id);

        double latitude = geocode.getLatitude();
        double longitude = geocode.getLongitude();
        String url = "http://api.openweathermap.org/data/2.5/weather?lat="+latitude+"&lon="+longitude+"&appid=4a1f5501b2798f409961c62d384a1c74";

        //Calling OpenWeather API
        ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
        String output = response.getBody();
        return output;
    }
}

Подход 2:

import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;

import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

@Component
public class CustomRestTemplate {

    /**
     * @param isHttpsRequired - pass true if you need to call a https url, otherwise pass false
     */
    public RestTemplate getRestTemplate(boolean isHttpsRequired)
            throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {

        // if https is not required,
        if (!isHttpsRequired) {
            return new RestTemplate();
        }

        // else below code adds key ignoring logic for https calls
        TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
        SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy)
                .build();

        SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);

        CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(csf).build();

        HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
        requestFactory.setHttpClient(httpClient);

        RestTemplate restTemplate = new RestTemplate(requestFactory);       
        return restTemplate;
    }
}

Затем в классе контроллера вы можете сделать следующее:

@RestController
public class WeatherController{


    @Autowired
    CustomRestTemplate customRestTemplate;

    @GetMapping(value = "weather/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
    public String getWeather(@PathVariable("id") int id) {
        BreweriesGeocode geocode = geocode_service.getGeocode(id);
        Breweries brewerie = breweries_service.getBrewerieById(id);

        double latitude = geocode.getLatitude();
        double longitude = geocode.getLongitude();
        String url = "https://api.openweathermap.org/data/2.5/weather?lat="+latitude+"&lon="+longitude+"&appid=4a1f5501b2798f409961c62d384a1c74";

        // Getting instance of Rest Template
        // Passing true becuase the url is a HTTPS url
        RestTemplate restTemplate = customRestTemplate.getRestTemplate(true);

        //Calling OpenWeather API
        ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);

        String output = response.getBody();

        return output;
    }
}

Вы можете написать обработчик ошибок Http для ответов RestTemplate, если код ответа не является кодом успеха.

person Dusayanta Prasad    schedule 22.04.2020
comment
Спасибо за ответ, HTTP не обязательно должен быть HTTPS, поэтому, чтобы избежать добавления ненужных зависимостей, как мне изменить контроллер, чтобы ему не нужно было использовать customRestTemplate? - person GreyWolf18; 22.04.2020
comment
@ GreyWolf18 GreyWolf18 Нам не нужна никакая зависимость для RestTemplate, она доступна по умолчанию в Spring. - person Dusayanta Prasad; 22.04.2020
comment
Кроме того, вы не можете вызвать API, просто назначив URL-адрес строковой переменной. Вам нужен HTTP-клиент/обработчик в вашем коде, который будет вызывать API, используя URL-адрес. Точно так же класс RestTemplate предоставляет готовый http-клиент, где вам просто нужно вызвать URL-адрес, используя его. - person Dusayanta Prasad; 22.04.2020
comment
Я понимаю, что мне не нужна зависимость для RestTemplate, однако в customRestTemplate я не могу добавить TrustStrategy, SSLContext, HttpComponentsClientHttpRequestFactory и некоторые другие, я предположил, что нужна зависимость, как это обойти? - person GreyWolf18; 22.04.2020
comment
@ GreyWolf18 GreyWolf18 Я обновил ответ. Если вы уверены, что собираетесь использовать только Http, следуйте подходу 1, он небольшой, чистый и понятный. Достаточно будет сделать вызов API. - person Dusayanta Prasad; 22.04.2020
comment
спасибо, я думаю об автоподключении RestTemplate, извините за вопросы - person GreyWolf18; 22.04.2020
comment
Да, RestTemplate является Autowired. Есть трудности в понимании? - person Dusayanta Prasad; 22.04.2020

Я проверил URL-адрес в почтальоне, он возвращает правильный ответ. Проверьте приведенный ниже экран, возможно, вы делаете что-то другое. Ответ почтальона

Убедитесь, что в URL-адресе нет пробелов, я вижу, что URL-адрес, который вы использовали в Postman, имел пробел после ":"

person JimmyFlash    schedule 22.04.2020
comment
Да, я понял пробел после http, извините, я забыл упомянуть, что я тестирую путь localhost :8080/Assignment2C/map/weather/4 и как искать в браузере с помощью почтальона, вызывая мой API - person GreyWolf18; 22.04.2020
comment
Это ваша локальная среда, я не могу получить к ней доступ, но я надеюсь, что мой ответ вам помог - person JimmyFlash; 22.04.2020