From 0653c3181444c2c52ece5470b136be52cd5655b2 Mon Sep 17 00:00:00 2001 From: Mathilde Hertaas <maimh@stud.ntnu.no> Date: Wed, 5 Mar 2025 18:49:56 +0100 Subject: [PATCH] pupolation info is implemented with correct year limit --- README.md | 33 +++++-- handelers/populasjonhandler.go | 168 ++++++++++++++++++++++++++++++++- main.go | 1 + main/main.go | 26 ----- 4 files changed, 191 insertions(+), 37 deletions(-) delete mode 100644 main/main.go diff --git a/README.md b/README.md index 62922b5..2a66c7b 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,13 @@ -# Cloud Project +### Assignment 1 +## Kjøre koden +koden kjøres ved å skrive go run main.go i temrinalen + - Da blir du eventuelt automatisk sendt til + http://localhost:8080/ + Dette er Hjemmeside + - Eventuelt kan du bruke fremgangsmåtene under Endepunkter for å navigere applikajsonen -# Endepunkter - 1. Hente informasjon om et land basert på en 2-letter country codes (ISO 3166-2). - * Endpoint: /countryinfo/v1/info/{country_code}{?limit=10} - * Metode: GET - * Eksempel: http://localhost:8080/countryinfo/v1/info/NO - - -# Hjemmeside (/) +## Hjemmeside (/) Når du åpner API-et uten spesifikke forespørsler (http://localhost:8080/), vil du bli sendt til en JSON-side med informasjon om hvordan du bruker API-et. @@ -17,4 +16,18 @@ Her får du informasjon om de tre endepunktene som er tilgjengelige: 2. populasjon 3. status Du får også se hvordan riktig format av url forespørsel til en av disse endepunktene -vil se ut og eksempler på riktig bruk. \ No newline at end of file +vil se ut og eksempler på riktig bruk. + + +## Endepunkter +#info + 1. Hente informasjon om et land basert på en 2-letter country codes (ISO 3166-2). + * Endpoint: /countryinfo/v1/info/{country_code}{?limit=10} + * Metode: GET + * Eksempel: http://localhost:8080/countryinfo/v1/info/NO?limit=4 +#populasjon + 2. Hente populasjonsdata + GET http://localhost:8080/population/NO + GET http://localhost:8080/population/NO?limit=2010-2015 + + diff --git a/handelers/populasjonhandler.go b/handelers/populasjonhandler.go index bb27ce5..b81780c 100644 --- a/handelers/populasjonhandler.go +++ b/handelers/populasjonhandler.go @@ -1 +1,167 @@ -package handelers \ No newline at end of file +package handelers + +import ( + "encoding/json" + "fmt" + "math" + "net/http" + "strconv" + "strings" +) + +// responsstruktur for befolkningsdata +type PopulationResponse struct { + Error bool `json:"error"` + Msg string `json:"msg"` + Data []Country `json:"data"` +} + +// land og dens befolkningsdata +type Country struct { + Name string `json:"country"` + Code string `json:"iso3"` // Trebokstavskode (ISO 3166-1 alpha-3) + PopulationCounts []PopulationCount `json:"populationCounts"` +} + + + + +// befolkningsdate for et bestemt år (brukes i den endelige repsonsen under values) +type PopulationCount struct { + Year int `json:"year"` + Value int `json:"value"` +} + +// Responsstruktur for vårt API(det som vises på skjerm) +type PopulationAPIResponse struct { + Name string `json:"land"` + Gjennomsnitt int `json:"gjennomsnittlig populasjon"` + Values []PopulationCount `json:"årlige populasjoner"` +} + + + + + + + +// ISO 3166-1 alpha-2 til alpha-3 landkoder +var isoAlpha2ToAlpha3 = make(map[string]string) + +// Henter befolkningsdata fra eksternt API +func fetchPopulationData() (*PopulationResponse, error) { + url := "https://countriesnow.space/api/v0.1/countries/population" + resp, err := http.Get(url) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var data PopulationResponse + err = json.NewDecoder(resp.Body).Decode(&data) + if err != nil { + return nil, err + } + + // Bygg dynamisk oppslagskart for landkoder + for _, country := range data.Data { + if len(country.Code) >= 2 { + isoAlpha2ToAlpha3[strings.ToUpper(country.Code[:2])] = country.Code // F.eks. NO → NOR + } + } + + return &data, nil +} + +// Henter befolkningsdata for et spesifikt land og filtrerer etter år +func getPopulationForCountry(alpha2Code string, startYear, endYear int) (*PopulationAPIResponse, error) { + data, err := fetchPopulationData() + if err != nil { + return nil, err + } + + // Konverter ISO 3166-1 alpha-2 til alpha-3 + alpha3Code, exists := isoAlpha2ToAlpha3[strings.ToUpper(alpha2Code)] + if !exists { + return nil, fmt.Errorf("invalid country code: %s", alpha2Code) + } + + // Finn landet basert på ISO 3166-1 alpha-3 kode + var countryData *Country + for _, c := range data.Data { + if c.Code == alpha3Code { + countryData = &c + break + } + } + + if countryData == nil { + return nil, fmt.Errorf("country not found") + } + + // Filtrer basert på år + + // en tom liste fyllt med PopulationCount, altså fylles med spesifikke år og antall + var filteredValues []PopulationCount + var total int + count := 0 + + // itererer over alle verdiene som følger med et land sin populasjonsdata + // over alle årstall-verdi strukturene + for _, stk := range countryData.PopulationCounts { + if (startYear == 0 || stk.Year >= startYear) && (endYear == 0 || stk.Year <= endYear) { + filteredValues = append(filteredValues, stk) + total += stk.Value + count++ + } + } + + // Beregn gjennomsnitt + mean := 0 + if count > 0 { + mean = int(math.Round(float64(total) / float64(count))) + } + + return &PopulationAPIResponse{ + Name: countryData.Name, + Gjennomsnitt: mean, + Values: filteredValues, + }, nil +} + + + + +func PopulationHandler(w http.ResponseWriter, r *http.Request) { + // r.URL.Path er den fulle URL som ble sendt til serveren altså /population/NO + // deretter fjerner den /population/ så vi sitter igjen med NO + path := strings.TrimPrefix(r.URL.Path, "/population/") + // NO + countryCode := strings.ToUpper(path) // ISO 3166-2-kode + + + query := r.URL.RawQuery + limit := strings.Replace(query, "limit=","",1) + + + startYear, endYear := 0, 0 + + if len(limit)>0 { + yearRange := strings.Split(limit, "-") + if len(yearRange) == 2 { + startYear, _ = strconv.Atoi(yearRange[0]) + endYear, _ = strconv.Atoi(yearRange[1]) + } else { + fmt.Println("Year range format is incorrect") + } + } + + result, err := getPopulationForCountry(countryCode, startYear, endYear) + if err != nil { + http.Error(w, err.Error(), http.StatusNotFound) + return + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(result) +} \ No newline at end of file diff --git a/main.go b/main.go index 90fff95..ee53077 100644 --- a/main.go +++ b/main.go @@ -18,6 +18,7 @@ func main() { }) http.HandleFunc("/", handelers.HomeHandler) http.HandleFunc("/countryinfo/v1/info/", handelers.CountryInfoHandler) + http.HandleFunc("/population/", handelers.PopulationHandler) fmt.Println("Server running on port 8080...") diff --git a/main/main.go b/main/main.go deleted file mode 100644 index 9501725..0000000 --- a/main/main.go +++ /dev/null @@ -1,26 +0,0 @@ -package main - -import ( - "fmt" - "net/http" - "time" - "git.gvk.idi.ntnu.no/Mathilde/cloud/handelers" -) - -var serviceStartTime time.Time - -func main() { - serviceStartTime = time.Now() - - // Send serviceStartTime til DiagnosticsHandler - http.HandleFunc("/status/", func(w http.ResponseWriter, r *http.Request) { - handelers.DiagnosticsHandler(w, r, serviceStartTime) - }) - http.HandleFunc("/", handelers.HomeHandler) - http.HandleFunc("/countryinfo/v1/info/", handelers.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) - } -} \ No newline at end of file -- GitLab