Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 62 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,68 @@ Applikasjonen skal:
- vise tydelig lasting og feilmelding ved API-feil
- fungere på både mobil og desktop

Værdata hentes direkte når applikasjonen brukes og mellomlagres ikke.
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. Relevante felter fra API-responsen mappes til prosjektets egen WeatherData-type.
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.


## Værdata

Expand Down
60 changes: 60 additions & 0 deletions web/src/services/weatherService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import type { City } from '../types/city';
import type { WeatherData } from '../types/weather';

interface OpenMeteoCurrent {
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 {
current: OpenMeteoCurrent;
}

const API_URL = 'https://api.open-meteo.com/v1/forecast';

export async function getWeather(city: City): Promise<WeatherData> {
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,
};
}