From 9003029c3449b33abd85ef243021666ceb55d0e7 Mon Sep 17 00:00:00 2001 From: Hasan Mohammad Fawzi Date: Tue, 15 Sep 2026 08:55:45 +0200 Subject: [PATCH 1/3] feat: implement Open-Meteo weather service --- README.md | 62 ++++++++++++++++++++++++++++++ web/src/services/weatherService.ts | 60 +++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 web/src/services/weatherService.ts diff --git a/README.md b/README.md index ebeaa0a..a174746 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,68 @@ Applikasjonen skal: Værdata hentes direkte når applikasjonen brukes og mellomlagres ikke. +## Weather service + +`weatherService` har ansvar for å hente værdata fra Open-Meteo og konvertere API-responsen til prosjektets egen `WeatherData`-type. + +Dette gjør at React-komponentene ikke trenger å kjenne til: + +* URL-en til Open-Meteo +* feltnavnene i API-responsen +* hvordan API-kallet bygges +* hvordan HTTP-feil håndteres + +Komponentene arbeider bare med prosjektets egne TypeScript-typer. + +### Hente værdata + +```ts +const weather = await getWeather(city); +``` + +Her skjer følgende: + +1. `city` inneholder navn, breddegrad og lengdegrad. +2. `getWeather(city)` sender et `fetch`-kall til Open-Meteo. +3. `await` venter til API-kallet er ferdig. +4. API-responsen konverteres til `WeatherData`. +5. Resultatet lagres i variabelen `weather`. + +Variabelen kan deretter brukes slik: + +```ts +console.log(weather.temperature); +console.log(weather.windSpeed); +console.log(weather.precipitation); +``` + +### Eksempel med feilhåndtering + +```ts +try { + const weather = await getWeather(city); + console.log(weather); +} catch (error) { + console.error('Kunne ikke hente værdata:', error); +} +``` + +Hvis API-kallet mislykkes, kaster `getWeather` en feil som React-komponenten kan fange og vise som en forståelig feilmelding til brukeren. + +### Dataflyt + +```mermaid +flowchart LR + City["City"] --> Service["getWeather(city)"] + Service --> API["Open-Meteo"] + API --> Service + Service --> Data["WeatherData"] + Data --> Component["React-komponent"] +``` + +Denne oppdelingen gjør API-håndteringen samlet på ett sted og lar React-komponentene bruke en enkel og stabil `WeatherData`-modell. + + ## Teknologi React, TypeScript, Vite, TanStack Query, `fetch`, plain CSS, ESLint, Prettier og Vitest. Eksemplet bruker [Open-Meteo](https://open-meteo.com/en/docs). diff --git a/web/src/services/weatherService.ts b/web/src/services/weatherService.ts new file mode 100644 index 0000000..aa87188 --- /dev/null +++ b/web/src/services/weatherService.ts @@ -0,0 +1,60 @@ +import type { City } from '../types/city'; +import type { WeatherData } from '../types/weather'; + +interface OpenMeteoCurrent { + time: string; + temperature_2m: number; + apparent_temperature: number; + relative_humidity_2m: number; + precipitation: number; + weather_code: number; + wind_speed_10m: number; + is_day: number; +} + +interface OpenMeteoResponse { + current: OpenMeteoCurrent; +} + +const API_URL = 'https://api.open-meteo.com/v1/forecast'; + +export async function getWeather(city: City): Promise { + const parameters = new URLSearchParams({ + latitude: city.latitude.toString(), + longitude: city.longitude.toString(), + current: [ + 'temperature_2m', + 'apparent_temperature', + 'relative_humidity_2m', + 'precipitation', + 'weather_code', + 'wind_speed_10m', + 'is_day', + ].join(','), + wind_speed_unit: 'ms', + timezone: 'auto', + }); + + const response = await fetch(`${API_URL}?${parameters.toString()}`); + + if (!response.ok) { + throw new Error( + `Kunne ikke hente værdata for ${city.name}. HTTP ${response.status}`, + ); + } + + const apiData = (await response.json()) as OpenMeteoResponse; + const current = apiData.current; + + return { + cityId: city.id, + time: current.time, + temperature: current.temperature_2m, + apparentTemperature: current.apparent_temperature, + humidity: current.relative_humidity_2m, + precipitation: current.precipitation, + weatherCode: current.weather_code, + windSpeed: current.wind_speed_10m, + isDay: current.is_day === 1, + }; +} \ No newline at end of file From b4106a13343eb06de4b5091ddd17e1d5771f4995 Mon Sep 17 00:00:00 2001 From: Hasan Mohammad Fawzi Date: Tue, 15 Sep 2026 11:09:15 +0200 Subject: [PATCH 2/3] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Oliver Ørjavik --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a174746..ef5470b 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,7 @@ Her skjer følgende: 1. `city` inneholder navn, breddegrad og lengdegrad. 2. `getWeather(city)` sender et `fetch`-kall til Open-Meteo. 3. `await` venter til API-kallet er ferdig. -4. API-responsen konverteres til `WeatherData`. +4. Relevante felter fra API-responsen mappes til prosjektets egen WeatherData-type. 5. Resultatet lagres i variabelen `weather`. Variabelen kan deretter brukes slik: From c75ca843f82fd171ec76a4d0f9e92268265a786c Mon Sep 17 00:00:00 2001 From: Hasan Mohammad Fawzi Date: Tue, 15 Sep 2026 11:09:24 +0200 Subject: [PATCH 3/3] Update web/src/services/weatherService.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Oliver Ørjavik --- web/src/services/weatherService.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/web/src/services/weatherService.ts b/web/src/services/weatherService.ts index aa87188..63fbf94 100644 --- a/web/src/services/weatherService.ts +++ b/web/src/services/weatherService.ts @@ -2,14 +2,14 @@ import type { City } from '../types/city'; import type { WeatherData } from '../types/weather'; interface OpenMeteoCurrent { - time: string; - temperature_2m: number; - apparent_temperature: number; - relative_humidity_2m: number; - precipitation: number; - weather_code: number; - wind_speed_10m: number; - is_day: number; + time: string; // Local time (ISO 8601) + temperature_2m: number; // °C + apparent_temperature: number; // °C + relative_humidity_2m: number; // % + precipitation: number; // mm + weather_code: number; // WMO weather code + wind_speed_10m: number; // m/s + is_day: number; // 0 = night, 1 = day } interface OpenMeteoResponse {