Skip to content
Snippets Groups Projects
Commit d62941f3 authored by Mathilde Hertaas's avatar Mathilde Hertaas
Browse files

cities is now included in info endpoint, user can spesify but not over 10

parent 06a502b9
No related branches found
No related tags found
No related merge requests found
......@@ -4,132 +4,258 @@ import (
"encoding/json"
"fmt"
"net/http"
"time"
"strings"
"strconv"
)
//countryinfo/v1/info/{country_code}{?limit=10}
//given country, 2-letter country codes (ISO 3166-2).
//limit is the number of cities that are listed in the response.
var serviceStartTime time.Time
// Struktur for å lagre data om landene i info endepunktet
// Funksjon for å hente statuskode fra et API
func getAPIStatus(url string) (int, error) {
resp, err := http.Get(url)
if err != nil {
return 0, err
}
defer resp.Body.Close()
// Returner HTTP-statuskoden
return resp.StatusCode, nil
}
// Funksjon for å beregne oppetid
func getUptime() int64 {
return int64(time.Since(serviceStartTime).Seconds())
}
// Handler for Diagnostics endpoint
func diagnosticsHandler(w http.ResponseWriter, r *http.Request) {
// Hent statuskoder fra eksterne API-er
countriesNowStatus, err := getAPIStatus("http://129.241.150.113:3500/api/v0.1/countries")
if err != nil {
http.Error(w, "Error fetching CountriesNow status", http.StatusInternalServerError)
return
}
restCountriesStatus, err := getAPIStatus("http://129.241.150.113:8080/v3.1/all") //funker med all
if err != nil {
http.Error(w, "Error fetching RestCountries status", http.StatusInternalServerError)
return
}
// Bygg responsen med statusinformasjon
response := map[string]interface{}{
"countriesnowapi": fmt.Sprintf("%d", countriesNowStatus),
"restcountriesapi": fmt.Sprintf("%d", restCountriesStatus),
"version": "v1", // Versjon av API
"uptime": getUptime(), // Oppetid i sekunder
}
// Sett Content-Type til application/json
w.Header().Set("Content-Type", "application/json")
// Returner JSON-responsen
json.NewEncoder(w).Encode(response)
}
type Flags struct{
PNG string `json:"png"`
}
// Struktur for data fra REST Countries API
type CountryInfo struct {
Name struct {
Common string `json:"common"`
Official string `json:"official"`
} `json:"name"`
Capital []string `json:"capital"`
Region string `json:"region"`
Common string `json:"common"`
Official string `json:"official"`
} `json:"name"`
Capital []string `json:"capital"`
Languages map[string]string `json:"languages"`
Continents []string `json:"continents"`
Borders []string `json:"borders"`
Population int `json:"population"`
Flags Flags `json:"flags"`
}
type CityInfo struct {
Cities []string `json:"cities"`
}
//Når du kjører koden blir du sendt til en hjemmeside siden forespørsel spesifikasjoner ikke er gitt enda
//info om hvordan bruke API
func homeHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
// Strukturert respons for bedre lesbarhet
response := map[string]interface{}{
"WELCOME": "Welcome to the Country Info API",
"endpoints": map[string]interface{}{
"Endpoint 1": map[string]string{
"Description": "Get information about a country using its ISO 3166-1 alpha-2 code.",
"URL": "http://localhost:8080/countryinfo/v1/info/{country_code}{?limit=10}",
"Example": "http://localhost:8080/countryinfo/v1/info/NO",
},
"Endpoint 2": map[string]interface{}{
"Description": "TO BE IMPLEMENTED",
},
},
}
json.NewEncoder(w).Encode(response)
}
// Struktur for kombinert respons
type CombinedInfo struct {
Name string `json:"name"`
Continents []string `json:"continenents"`
Population int `json:"population"`
Languages map[string]string `json:"languages"`
Borders []string `json:"borders"`
Flags string `json:"flags"`
Capital string `json:"capital"`
Cities string `json:"cities"`
}
// En funksjon som henter data fra det eksterne API-et ved landkode
// Henter landdata fra REST Countries API
func getCountryDataByCode(countryCode string) (*CountryInfo, error) {
//bygge en URL for API kallet
url := fmt.Sprintf("http://129.241.150.113:8080/v3.1/alpha/%s", countryCode)
//sender en http forespørsel
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
// Sjekk om API-kallet var vellykket (statuskode 200)
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("error retrieving country data, status code: %d", resp.StatusCode)
}
// Håndterer en http feil, som om landet ikke finnes
var countries []CountryInfo
if err := json.NewDecoder(resp.Body).Decode(&countries); err != nil {
return nil, err
}
// Hvis vi ikke får noen treff
if len(countries) == 0 {
return nil, fmt.Errorf("country not found for code: %s", countryCode)
}
// Returner det første elementet i listen siden forventer bare ett treff)
return &countries[0], nil
}
func getCitiesByCountry(countryName string) ([]string, error) {
url := fmt.Sprintf("https://countriesnow.space/api/v0.1/countries/cities/q?country=%s", countryName)
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
//oprett en handler for /countryinfo/v1/info/{country_code}
// leser landkoden fra URL
// slår opp dataene
// REturnerer dem som JSON
func handler(w http.ResponseWriter, r *http.Request) {
// Hent landkode fra path
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("error retrieving cities, status code: %d", resp.StatusCode)
}
var responseBody map[string]interface{}
if err := json.NewDecoder(resp.Body).Decode(&responseBody); err != nil {
return nil, err
}
if cities, ok := responseBody["data"].([]interface{}); ok {
var cityList []string
for _, city := range cities {
if cityStr, ok := city.(string); ok {
cityList = append(cityList, cityStr)
}
}
// Hvis ingen byer er funnet, returner en feilmelding
if len(cityList) == 0 {
fmt.Println("No cities found in the response.")
}
return cityList, nil
}
return nil, fmt.Errorf("no cities found for country %s", countryName)
}
func countryInfoHandler(w http.ResponseWriter, r *http.Request) {
parts := strings.Split(r.URL.Path, "/")
if len(parts) < 5 {
http.Error(w, "Invalid format. Please use the format /countryinfo/v1/info/{countryCode}{?limit=10}. Example: /countryinfo/v1/info/NO", http.StatusBadRequest)
http.Error(w, "Invalid format. Use: /countryinfo/v1/info/{countryCode}", http.StatusBadRequest)
return
}
countryCode := parts[4] // Landkoden er den 5. delen av pathen (fra 0)
countryCode := parts[4]
// Hent data fra API ved landkode
//country inneholder data om alt går bra
// Hent landdata fra REST Countries API
country, err := getCountryDataByCode(countryCode)
//err inneholder feil hvis noe går galt, ikke finner landkode
if err != nil {
http.Error(w, fmt.Sprintf(
"Error retrieving data for country code: %s. Check if the country code is correct.\nExample: /countryinfo/v1/info/NO\nError: %s",
countryCode, err.Error(),
), http.StatusInternalServerError)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Hent antall byer som skal vises fra URL-parameteren (default til 10)
// F.eks. /countryinfo/v1/info/NO?cities=5
cityCount := 10 // Standardverdi
cityCountStr := r.URL.Query().Get("cities") // Hent "cities" parameteren
if cityCountStr != "" {
// Prøv å konvertere parameteren til et heltall
if count, err := strconv.Atoi(cityCountStr); err == nil && count > 0 {
cityCount = count
}
}
// Hent byene fra countriesnow API
cities, err := getCitiesByCountry(country.Name.Common)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Hvis det er flere enn det brukeren ønsker, begrens listen
if len(cities) > cityCount {
cities = cities[:cityCount]
}
// Feilsøking: Hvis ingen byer ble funnet
if len(cities) == 0 {
fmt.Printf("No cities found for %s\n", country.Name.Common)
}
// Returner JSON-respons
// Begrens byene til maks 10
if len(cities) > 10 {
cities = cities[:10]
}
// Bygg kombinert respons
response := CombinedInfo{
Name: country.Name.Common,
Continents: country.Continents,
Population: country.Population,
Languages: country.Languages,
Borders: country.Borders,
Flags: country.Flags.PNG,
Capital: "",
Cities: strings.Join(cities, ", "), // Legg til de 10 første byene som en kommaseparert liste
}
if len(country.Capital) > 0 {
response.Capital = country.Capital[0]
}
// Sett Content-Type til application/json
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(country)
json.NewEncoder(w).Encode(response)
}
// kaller de ulike funkjsonene basert på hvilken URL som sender forespørsel
func main() {
http.HandleFunc("/",homeHandler)
//Rute for info om land
http.HandleFunc("/countryinfo/v1/info/", handler)
//starttidspunkt for tjenesten
serviceStartTime = time.Now()
http.HandleFunc("/status/", diagnosticsHandler)
http.HandleFunc("/", homeHandler)
http.HandleFunc("/countryinfo/v1/info/", countryInfoHandler)
//info i terminal
fmt.Println("Server running on port 8080...")
if err := http.ListenAndServe(":8080", nil); err != nil {
// Logg feilen og avslutt programmet dersom serveren ikke kan starte
fmt.Printf("Server failed to start: %s\n", err)
}
}
//URL for å teste info for norge
//http://localhost:8080/countryinfo/v1/info/No
\ No newline at end of file
func homeHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
response := map[string]interface{}{
"WELCOME": "Welcome to the Country Info API",
"endpoints": map[string]interface{}{
"Get Country Info": map[string]string{
"Description": "Get country details including cities, population, and more.",
"URL Format": "http://localhost:8080/countryinfo/v1/info/{country_code}{?limit=10}",
"Example": "http://localhost:8080/countryinfo/v1/info/NO?cities=5",
},
"Get status info" : map[string]string{
"Description" : "Get information about the API statuses",
"URL" : "http://localhost:8080/status/",
},
},
}
json.NewEncoder(w).Encode(response)
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment