Externe Rest API konsumieren

Diskutiere Externe Rest API konsumieren im Java Basics - Anfänger-Themen Bereich.
tom.j85

tom.j85

Hallo liebe Community,

ich versuche gerade eine Rest API zu Reisewarnungen im Backend einzubinden (FYI die hier). Das json Format sollte eigentlich so aussehen:

JSON:
{
          "api_status": {
            "request": {
              "item": "de"
            },
            "reply": {
              "cache": "renewed",
              "code": 200,
              "status": "ok",
              "note": "The api works, we could match requested country code.",
              "count": 1
            }
          },
          "data": {
            "DE": {
              "iso_alpha2": "DE",
              "name": "Germany",
              "continent": "EU",
              "advisory": {
                "score": 1.5,
                "sources_active": 4,
                "message": "Germany has a current risk level of 1.5 (out of 5). We Advise: Travelling Germany is (relatively) safe.",
                "updated": "2019-02-12 19:53:38",
                "source": "https:\/\/www.travel-advisory.info\/germany"
              }
            }
          }
        }
Jetzt habe ich die Struktur nachgebaut, um mit einem GetMapping auf Spring die Daten abzuholen. Meine Objekte sind einfach gehalten:


Java:
package com.savetravel.SaveTravel.TravelWarning;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@NoArgsConstructor
@Getter
@Setter
public class TravelWarningObject {

    
    private Api_status api_status;
    private Data data;
    
}
Java:
package com.savetravel.SaveTravel.TravelWarning;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@NoArgsConstructor
@Getter
@Setter
public class Api_status {

    private Request request;
    private Reply reply;
    
    }
Java:
package com.savetravel.SaveTravel.TravelWarning;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@NoArgsConstructor
@Getter
@Setter
public class Reply {

    private String cache;
    private int code;
    private String status;
    private String note;
    private int count;
    
    }
Java:
package com.savetravel.SaveTravel.TravelWarning;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@NoArgsConstructor
@Getter
@Setter
public class Request {
    
    private String item;
    
    }
Java:
package com.savetravel.SaveTravel.TravelWarning;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@NoArgsConstructor
@Getter
@Setter
public class Data {

    private CountryCode DE;
}
Java:
package com.savetravel.SaveTravel.TravelWarning;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@NoArgsConstructor
@Getter
@Setter
public class CountryCode {

    private String iso_alpha_2;
    private String name;
    private String continent;
    private Advisory advisory;
    
    }
Und der Controller:

Java:
package com.savetravel.SaveTravel;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.savetravel.SaveTravel.TravelWarning.TravelWarningObject;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;

import org.springframework.web.client.RestTemplate;

@RestController
@RequestMapping("/gettravelwarnings")
public class TravelWarningController {

    @GetMapping
    public TravelWarningObject getTravelWarnings()
            throws JsonMappingException, JsonProcessingException {
        
        RestTemplate restTemplate= new RestTemplate();
        TravelWarningObject newTravelWarning = new TravelWarningObject();
        ResponseEntity<TravelWarningObject> responseEntity = restTemplate.getForEntity(
                "https://www.travel-Advisory.info/api?countrycode=DE",
                TravelWarningObject.class);
        newTravelWarning = responseEntity.getBody();
        return newTravelWarning;
    }
        
}
Grundsätzlich scheint das zu funktionieren, allerdings kommt nur die Hälfte an. Wenn ich die get Methode mit Postman abrufe, erhalte ich:

JSON:
{
    "api_status": {
        "request": {
            "item": "de"
        },
        "reply": {
            "cache": "cached",
            "code": 200,
            "status": "ok",
            "note": "The api works, we could match requested country code.",
            "count": 1
        }
    },
    "data": {
        "de": null
    }
}
Aufällig ist, dass das Objekt Country Code (DE) in Kleinbuchstaben dasteht. Ich vermute den Fehler hier, da json case sensitive ist, es ist mir aber ein Rätsel, wie ich das Ändern könnte.

Zweitens, stehe ich auch auf dem Schlauch, wie man die Daten aller Länder vernünftig abrufen kann (FYI, die API gibts hier). Das scheint mir nämlich ein Monsterobjekt^TM zu sein, in dem ein Objekt api_status und ungefähr 180 Objekte mit Ländercodes stehen. Irgendwie scheint das alles nicht so zu funktionieren, wie ich es aus kleineren APIs gewohnt bin...hat jemand einen Tipp / Link / Hinweis, wie ich das Lösen kann?

Vielen Dank
Tom
 
mrBrown

mrBrown

Statt Data wäre vermutlich eine Map<String /*Oder enum CountryCode [1], CountryCode> passender :)

[1] das wäre dann der ISO-3166 Country-Code, Benennen kollidiert dann natürlich mit deiner eigenen Klasse, aber das kann man ja lösen :)
 
mihe7

mihe7

Aufällig ist, dass das Objekt Country Code (DE) in Kleinbuchstaben dasteht. Ich vermute den Fehler hier, da json case sensitive ist, es ist mir aber ein Rätsel, wie ich das Ändern könnte.
Wenn ich einen GET-Request per curl absetze:
Code:
curl https://www.travel-advisory.info/api?countrycode=DE
kommt
JSON:
{"api_status":{"request":{"item":"de"},"reply":{"cache":"cached","code":200,"status":"ok","note":"The api works, we could match requested country code.","count":1}},"data":{"DE":{"iso_alpha2":"DE","name":"Germany","continent":"EU","advisory":{"score":3.100000000000000088817841970012523233890533447265625,"sources_active":8,"message":"","updated":"2020-07-10 07:22:48","source":"https:\/\/www.travel-advisory.info\/germany"}}}}
zurück.

EDIT: LOL, das scheint mir eine lustige API zu sein. Zuvor kam im Browser
JSON:
{"api_status":{"request":{"item":"tr"},"reply":{"cache":"renewed","code":200,"status":"ok","note":"The api works, we could match requested country code.","count":1}},"data":{"TR":{"iso_alpha2":"TR","name":"Turkey","continent":"AS","advisory":{"score":3.600000000000000088817841970012523233890533447265625,"sources_active":9,"message":"Turkey has a current risk level of 3.6 (out of 5). We advise: Please reconsider your need to travel to Turkey.","updated":"2020-07-10 07:22:48","source":"https:\/\/www.travel-advisory.info\/turkey"}}}}
auch eine Message mit - jetzt nicht mehr.
 
H

handshake45

:rolleyes:
Hier mal die ersten 10 Länder alphabetisch:
Java:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import org.json.JSONObject;

public class TravelAdvisory {
	public static List<String> getCountrycodes() throws IOException {
		LinkedList<String> codes = new LinkedList<String>();
		StringBuilder b = new StringBuilder();
		try (BufferedReader r = new BufferedReader(
				new InputStreamReader(new URL("https://www.travel-advisory.info/api").openStream()))) {
			int c;
			while ((c = r.read()) != -1) {
				b.append((char) c);
			}
		}
		JSONObject api_status = new JSONObject(b.toString());
		JSONObject data = api_status.getJSONObject("data");
		for (Object o : data.names()) {
			String iso_alpha2 = data.getJSONObject((String) o).getString("iso_alpha2");
			codes.add(iso_alpha2);
		}
		return codes;
	}

	public static JSONObject getCountryInfos(String iso_alpha2) throws IOException {
		StringBuilder b = new StringBuilder();
		try (BufferedReader r = new BufferedReader(new InputStreamReader(
				new URL("https://www.travel-advisory.info/api?countrycode=" + iso_alpha2).openStream()))) {
			int c;
			while ((c = r.read()) != -1) {
				b.append((char) c);
			}
		}
		return new JSONObject(b.toString());
	}

	public static void main(String[] args) throws IOException {
		List<String> countrycodes = getCountrycodes();
		Collections.sort(countrycodes);
		System.out.println(countrycodes);
		for (int i = 0; i < 10; i++) {
			System.out.println(getCountryInfos(countrycodes.get(i)).toString(4));
		}
	}
}
JSON:
[AD, AE, AF, AG, AI, AL, AM, AO, AR, AS, AT, AU, AW, AZ, BA, BB, BD, BE, BF, BG, BH, BI, BJ, BL, BM, BN, BO, BR, BS, BT, BW, BY, BZ, CA, CC, CD, CF, CG, CH, CI, CK, CL, CM, CN, CO, CR, CU, CV, CX, CY, CZ, DE, DJ, DK, DM, DO, DZ, EC, EE, EG, EH, ER, ES, ET, FI, FJ, FK, FM, FO, FR, GA, GB, GD, GE, GF, GG, GH, GI, GL, GM, GN, GP, GQ, GR, GS, GT, GU, GW, GY, HK, HN, HR, HT, HU, ID, IE, IL, IM, IN, IQ, IR, IS, IT, JE, JM, JO, JP, KE, KG, KH, KI, KM, KN, KP, KR, KW, KY, KZ, LA, LB, LC, LI, LK, LR, LS, LT, LU, LV, LY, MA, MC, MD, ME, MF, MG, MH, MK, ML, MM, MN, MO, MP, MQ, MR, MS, MT, MU, MV, MW, MX, MY, MZ, NA, NC, NE, NF, NG, NI, NL, NO, NP, NU, NZ, OM, PA, PE, PF, PG, PH, PK, PL, PM, PN, PR, PS, PT, PW, PY, QA, RE, RO, RS, RU, RW, SA, SB, SC, SD, SE, SG, SH, SI, SJ, SK, SL, SM, SN, SO, SR, SS, ST, SV, SY, SZ, TC, TD, TG, TH, TJ, TL, TM, TN, TO, TR, TT, TV, TW, TZ, UA, UG, US, UY, UZ, VA, VC, VE, VG, VI, VN, VU, WF, WS, XK, YE, YT, ZA, ZM, ZW]
{
    "data": {"AD": {
        "continent": "EU",
        "iso_alpha2": "AD",
        "advisory": {
            "score": 2.8,
            "sources_active": 4,
            "source": "https://www.travel-advisory.info/andorra",
            "message": "Andorra has a current risk level of 2.8 (out of 5). We advise: Use some caution when travelling Andorra.",
            "updated": "2020-07-10 07:22:48"
        },
        "name": "Andorra"
    }},
    "api_status": {
        "request": {"item": "ad"},
        "reply": {
            "note": "The api works, we could match requested country code.",
            "cache": "renewed",
            "code": 200,
            "count": 1,
            "status": "ok"
        }
    }
}
{
    "data": {"AE": {
        "continent": "AS",
        "iso_alpha2": "AE",
        "advisory": {
            "score": 3.1,
            "sources_active": 7,
            "source": "https://www.travel-advisory.info/united-arab-emirates",
            "message": "United Arab Emirates has a current risk level of 3.1 (out of 5). We advise: Use some caution when travelling United Arab Emirates.",
            "updated": "2020-07-10 07:22:48"
        },
        "name": "United Arab Emirates"
    }},
    "api_status": {
        "request": {"item": "ae"},
        "reply": {
            "note": "The api works, we could match requested country code.",
            "cache": "renewed",
            "code": 200,
            "count": 1,
            "status": "ok"
        }
    }
}
{
    "data": {"AF": {
        "continent": "AS",
        "iso_alpha2": "AF",
        "advisory": {
            "score": 5,
            "sources_active": 10,
            "source": "https://www.travel-advisory.info/afghanistan",
            "message": "Afghanistan has a current risk level of 5 (out of 5). We advise: It is not safe to travel Afghanistan.",
            "updated": "2020-07-10 07:22:48"
        },
        "name": "Afghanistan"
    }},
    "api_status": {
        "request": {"item": "af"},
        "reply": {
            "note": "The api works, we could match requested country code.",
            "cache": "renewed",
            "code": 200,
            "count": 1,
            "status": "ok"
        }
    }
}
{
    "data": {"AG": {
        "continent": "NA",
        "iso_alpha2": "AG",
        "advisory": {
            "score": 3,
            "sources_active": 3,
            "source": "https://www.travel-advisory.info/antigua-and-barbuda",
            "message": "Antigua and Barbuda has a current risk level of 3 (out of 5). We advise: Use some caution when travelling Antigua and Barbuda.",
            "updated": "2020-07-10 07:22:48"
        },
        "name": "Antigua and Barbuda"
    }},
    "api_status": {
        "request": {"item": "ag"},
        "reply": {
            "note": "The api works, we could match requested country code.",
            "cache": "renewed",
            "code": 200,
            "count": 1,
            "status": "ok"
        }
    }
}
{
    "data": {"AI": {
        "continent": "NA",
        "iso_alpha2": "AI",
        "advisory": {
            "score": 3,
            "sources_active": 3,
            "source": "https://www.travel-advisory.info/anguilla",
            "message": "Anguilla has a current risk level of 3 (out of 5). We advise: Use some caution when travelling Anguilla.",
            "updated": "2020-07-10 07:22:48"
        },
        "name": "Anguilla"
    }},
    "api_status": {
        "request": {"item": "ai"},
        "reply": {
            "note": "The api works, we could match requested country code.",
            "cache": "renewed",
            "code": 200,
            "count": 1,
            "status": "ok"
        }
    }
}
{
    "data": {"AL": {
        "continent": "EU",
        "iso_alpha2": "AL",
        "advisory": {
            "score": 3.3,
            "sources_active": 7,
            "source": "https://www.travel-advisory.info/albania",
            "message": "Albania has a current risk level of 3.3 (out of 5). We advise: Use some caution when travelling Albania.",
            "updated": "2020-07-10 07:22:48"
        },
        "name": "Albania"
    }},
    "api_status": {
        "request": {"item": "al"},
        "reply": {
            "note": "The api works, we could match requested country code.",
            "cache": "renewed",
            "code": 200,
            "count": 1,
            "status": "ok"
        }
    }
}
{
    "data": {"AM": {
        "continent": "AS",
        "iso_alpha2": "AM",
        "advisory": {
            "score": 3.2,
            "sources_active": 5,
            "source": "https://www.travel-advisory.info/armenia",
            "message": "Armenia has a current risk level of 3.2 (out of 5). We advise: Use some caution when travelling Armenia.",
            "updated": "2020-07-10 07:22:48"
        },
        "name": "Armenia"
    }},
    "api_status": {
        "request": {"item": "am"},
        "reply": {
            "note": "The api works, we could match requested country code.",
            "cache": "renewed",
            "code": 200,
            "count": 1,
            "status": "ok"
        }
    }
}
{
    "data": {"AO": {
        "continent": "AF",
        "iso_alpha2": "AO",
        "advisory": {
            "score": 3,
            "sources_active": 6,
            "source": "https://www.travel-advisory.info/angola",
            "message": "Angola has a current risk level of 3 (out of 5). We advise: Use some caution when travelling Angola.",
            "updated": "2020-07-10 07:22:48"
        },
        "name": "Angola"
    }},
    "api_status": {
        "request": {"item": "ao"},
        "reply": {
            "note": "The api works, we could match requested country code.",
            "cache": "renewed",
            "code": 200,
            "count": 1,
            "status": "ok"
        }
    }
}
{
    "data": {"AR": {
        "continent": "SA",
        "iso_alpha2": "AR",
        "advisory": {
            "score": 3.1,
            "sources_active": 7,
            "source": "https://www.travel-advisory.info/argentina",
            "message": "Argentina has a current risk level of 3.1 (out of 5). We advise: Use some caution when travelling Argentina.",
            "updated": "2020-07-10 07:22:48"
        },
        "name": "Argentina"
    }},
    "api_status": {
        "request": {"item": "ar"},
        "reply": {
            "note": "The api works, we could match requested country code.",
            "cache": "renewed",
            "code": 200,
            "count": 1,
            "status": "ok"
        }
    }
}
{
    "data": {"AS": {
        "continent": "OC",
        "iso_alpha2": "AS",
        "advisory": {
            "score": 4,
            "sources_active": 1,
            "source": "https://www.travel-advisory.info/american-samoa",
            "message": "American Samoa has a current risk level of 4 (out of 5). We advise: Please reconsider your need to travel to American Samoa.",
            "updated": "2020-07-10 07:22:48"
        },
        "name": "American Samoa"
    }},
    "api_status": {
        "request": {"item": "as"},
        "reply": {
            "note": "The api works, we could match requested country code.",
            "cache": "renewed",
            "code": 200,
            "count": 1,
            "status": "ok"
        }
    }
}
Das Ganze könntest du jetzt in einer Liste die man sortieren kann darstellen... (Dazu war ich gerad zu faul).
 
tom.j85

tom.j85

Vielen lieben Dank erst einmal für den Input!

Der Tipp von Mr.Brown mit der Map hat die Sache für mich am einfachsten gelöst. Das TravelWarningObject sieht jetzt so aus:

Java:
package com.savetravel.SaveTravel.TravelWarning;

import java.util.HashMap;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@NoArgsConstructor
@Getter
@Setter
public class TravelWarningObject {

    private Api_status api_status;
    private HashMap<String, CountryCode> data;
}
Und der Controller, mit einer Methode für einzelne und eine für alle Länder:

Java:
package com.savetravel.SaveTravel;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.savetravel.SaveTravel.TravelWarning.TravelWarningObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import org.springframework.web.client.RestTemplate;

@RestController
@RequestMapping("/gettravelwarnings")
public class TravelWarningController {

    @GetMapping
    public TravelWarningObject getTravelWarnings(String coCo)
            throws JsonMappingException, JsonProcessingException {
       
        //Dummy for test
        coCo = "DE";
       
        RestTemplate restTemplate= new RestTemplate();
        TravelWarningObject newTravelWarning = new TravelWarningObject();
        ResponseEntity<TravelWarningObject> responseEntity = restTemplate.getForEntity(
                "https://www.travel-Advisory.info/api?countrycode="+coCo.toUpperCase(),
                TravelWarningObject.class);
        newTravelWarning = responseEntity.getBody();
        return newTravelWarning;
    }
   
   
    @GetMapping("/alltw")
    public TravelWarningObject getAllTravelWarnings()
            throws JsonMappingException, JsonProcessingException {
       
        RestTemplate restTemplate = new RestTemplate();
        TravelWarningObject allTravelWarnings = new TravelWarningObject();
       
        ResponseEntity<TravelWarningObject> responseEntity = restTemplate.getForEntity(
                "https://www.travel-advisory.info/api", TravelWarningObject.class);
        allTravelWarnings = responseEntity.getBody();
   
        return allTravelWarnings;
               
    }
}
Warum beim alten Code die Daten ab dem Ländercode nicht mehr ausgegeben wurden ist mir nach wie vor ein Rätsel. Ich habe bei coCo ein .toUpperCase reingesetzt...aus Sicherheitsgründen.

@handshake45
Der Code sieht sexy aus, danke, schaue ich mir nochmal an. Das scheint mir die Lösung ohne Spring Boot zu sein, hätte vielleicht noch dazu schrieben sollen, dass ich Spring verwende

@mrBrown
Ich habe mir auch Enum und EnumMap angesehen. Bin aber grandios gescheitert. Ich hatte mir die Ländercodes gezogen:
Java:
String[] locales = Locale.getISOCountries()
hatte aber keine Ahnung wie man das jetzt als Enum verpackt...vielleicht hast Du da noch einen Tipp oder Link oder ähnliches weiterführendes?

Besten Dank & schönen Sonntag
Tom
 
mrBrown

mrBrown

@@handshake45
Der Code sieht sexy aus,
Also wenn du solchen Code sexy findest scheinst du seeeehr merkwürdige Fetische zu haben...


@@mrBrown
Ich habe mir auch Enum und EnumMap angesehen. Bin aber grandios gescheitert. Ich hatte mir die Ländercodes gezogen:
Java:
String[] locales = Locale.getISOCountries()
hatte aber keine Ahnung wie man das jetzt als Enum verpackt...vielleicht hast Du da noch einen Tipp oder Link oder ähnliches weiterführendes?
Den enum müsstest du dir selber schreiben, wenn du die fertigen Länder-Codes nutzen willst, ist String die bessere Wahl.
Ansonsten halt einfach enum CountryCode { DE, GB, FR }
 
O

Oneixee5

Was ich mich frage: Wozu das alles? Der orginale Post macht eine API Abfrage und das JSON-Resultat wird zurückgeben. Dazu ist doch gar kein Mapping in irgendwelche Objekte notwendig, reiche das JSON einfach so weiter wie es ist. Im einfachsten Fall würde schon eine Weiterleitung ausreichen: HTTP/1.1 301 Moved Permanently
 
Thema: 

Externe Rest API konsumieren

Passende Stellenanzeigen aus deiner Region:
Anzeige

Neue Themen

Anzeige

Anzeige
Oben