diff --git a/handelers/homeHandler.go b/handelers/homeHandler.go new file mode 100644 index 0000000000000000000000000000000000000000..be20d268b1d8d3a2796ec450d3d8b69abe2262c7 --- /dev/null +++ b/handelers/homeHandler.go @@ -0,0 +1,28 @@ +package handelers +import ( + "encoding/json" + "net/http" +) + +// hjemmeside for kjøring av applikasjonen som sender deg direkte til en side uten spesifiksejoner gitt +// av brukeren. +//INFO +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) +} \ No newline at end of file diff --git a/handelers/infohandler.go b/handelers/infohandler.go new file mode 100644 index 0000000000000000000000000000000000000000..021905f67653c1b1f0a2c2712950fd2327c2b0f3 --- /dev/null +++ b/handelers/infohandler.go @@ -0,0 +1,134 @@ +package handelers + +import( + "strings" + "net/http" + "fmt" + "strconv" + "encoding/json" +) + +// Henter landdata fra REST Countries API +func getCountryDataByCode(countryCode string) (*CountryInfo, error) { + url := fmt.Sprintf("http://129.241.150.113:8080/v3.1/alpha/%s", countryCode) + resp, err := http.Get(url) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("error retrieving country data, status code: %d", resp.StatusCode) + } + + var countries []CountryInfo + if err := json.NewDecoder(resp.Body).Decode(&countries); err != nil { + return nil, err + } + + if len(countries) == 0 { + return nil, fmt.Errorf("country not found for code: %s", countryCode) + } + + return &countries[0], nil +} + +func CountryInfoHandler(w http.ResponseWriter, r *http.Request) { + parts := strings.Split(r.URL.Path, "/") + if len(parts) < 5 { + http.Error(w, "Invalid format. Use: /countryinfo/v1/info/{countryCode}", http.StatusBadRequest) + return + } + countryCode := parts[4] + + // Hent landdata fra REST Countries API + country, err := getCountryDataByCode(countryCode) + if err != nil { + 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) + } + // 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(response) +} + +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() + + 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) +} \ No newline at end of file diff --git a/handelers/populasjonhandler.go b/handelers/populasjonhandler.go new file mode 100644 index 0000000000000000000000000000000000000000..bb27ce5d36ad587a583b167d9fd0af5cd728d61f --- /dev/null +++ b/handelers/populasjonhandler.go @@ -0,0 +1 @@ +package handelers \ No newline at end of file diff --git a/handelers/statushandler.go b/handelers/statushandler.go new file mode 100644 index 0000000000000000000000000000000000000000..0b91a1195abde838e70259fcfa0b7dab926e1eae --- /dev/null +++ b/handelers/statushandler.go @@ -0,0 +1,59 @@ +package handelers + +import ( + "net/http" + "time" + "fmt" + "encoding/json" +) + + +var serviceStartTime time.Time + +// 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) { + serviceStartTime = time.Now() + // 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) +} \ No newline at end of file diff --git a/handelers/strukter.go b/handelers/strukter.go new file mode 100644 index 0000000000000000000000000000000000000000..69a56af612bb0402c9fd2ae2f58237a7acf22519 --- /dev/null +++ b/handelers/strukter.go @@ -0,0 +1,37 @@ +package handelers + + +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"` + 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"` +} + + +// 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"` +} \ No newline at end of file diff --git a/main.go b/main.go index afb7d6093c2103e7362b439eb61992add8df50c5..c437f0c08a191e10e8fc18ce12e4d2d445cd9716 100644 --- a/main.go +++ b/main.go @@ -1,255 +1,19 @@ package main import ( - "encoding/json" "fmt" "net/http" - "time" - "strings" - "strconv" + "git.gvk.idi.ntnu.no/Mathilde/cloud/handelers" ) -var serviceStartTime time.Time - -// 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"` - 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"` -} - - -// 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"` -} - -// Henter landdata fra REST Countries API -func getCountryDataByCode(countryCode string) (*CountryInfo, error) { - url := fmt.Sprintf("http://129.241.150.113:8080/v3.1/alpha/%s", countryCode) - resp, err := http.Get(url) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("error retrieving country data, status code: %d", resp.StatusCode) - } - - var countries []CountryInfo - if err := json.NewDecoder(resp.Body).Decode(&countries); err != nil { - return nil, err - } - - if len(countries) == 0 { - return nil, fmt.Errorf("country not found for code: %s", countryCode) - } - - 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() - - 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. Use: /countryinfo/v1/info/{countryCode}", http.StatusBadRequest) - return - } - countryCode := parts[4] - - // Hent landdata fra REST Countries API - country, err := getCountryDataByCode(countryCode) - if err != nil { - 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) - } - // 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(response) -} - func main() { + http.HandleFunc("/status/", handelers.DiagnosticsHandler) + http.HandleFunc("/", handelers.HomeHandler) + http.HandleFunc("/countryinfo/v1/info/", handelers.CountryInfoHandler) -//starttidspunkt for tjenesten - serviceStartTime = time.Now() - - http.HandleFunc("/status/", diagnosticsHandler) - - http.HandleFunc("/", homeHandler) - http.HandleFunc("/countryinfo/v1/info/", countryInfoHandler) fmt.Println("Server running on port 8080...") if err := http.ListenAndServe(":8080", nil); err != nil { fmt.Printf("Server failed to start: %s\n", err) } -} - -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) -} +} \ No newline at end of file