From 5b789475ef3b58c3155d8baf8ccf5842c3f9b049 Mon Sep 17 00:00:00 2001 From: Damien A Date: Sun, 3 Mar 2024 17:11:52 +0100 Subject: [PATCH] commit exercice --- .gitignore | 3 ++ README.md | 71 +++++++++++++++++++++++++++++++++++++++++++++++ api.py | 50 +++++++++++++++++++++++++++++++++ requierement.txt | 2 ++ utils/__init.py__ | 0 utils/weather.py | 55 ++++++++++++++++++++++++++++++++++++ 6 files changed, 181 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 api.py create mode 100644 requierement.txt create mode 100644 utils/__init.py__ create mode 100644 utils/weather.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..413a5ea --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +# Python venv folder +.venv/* +utils/__pycache__/weather.cpython-311.pyc diff --git a/README.md b/README.md new file mode 100644 index 0000000..88a61ae --- /dev/null +++ b/README.md @@ -0,0 +1,71 @@ +# Weather API + +## Context + +As part of an exercise, the idea is to be able to retrieve information via [open-meteo](https://open-meteo.com/en/docs). +The statement is as follows: + +### First part + +**Endpoint :** + +- **Objective:** Develop an endpoint that returns the average temperature over a specified period. +- **Request:** `GET /temperature?x=[X]&y=[Y]&prevision_jours=[prevision_jours]` +- **Parameters:** X and Y represent GPS coordinates. + +**Expected output:** + +```json +Temperature: { + "average_temperature": [Calculated average value] +} +``` + +### Second part + +**Endpoint:** + +- **Objective:** Create an endpoint that indicates, for the next 2 days, the time slots when it's advisable to go out with an umbrella, based on the probability of precipitation. +- **Request:** `GET /umbrella?x=[X]&y=[Y]` +- **Parameters:** X and Y represent GPS coordinates. +- **How it works:** If precipitation_probability is greater than 50%, these hours are marked as requiring an umbrella. + +**Expected output:** + +```json +{ + "sort_ton_parapluie": [List of time slots] +} +``` + +## Install and execution + +```bash +git clone https://github.com/MasqAs/weather-api.git +python -m venv .venv +source .venv/bin/activate +pip install -r requerements.txt +python3 api.py +``` + +To call API endpoint : + +```bash +❯ curl -X GET 'http://127.0.0.1:5000/temperature?x=52.12&y=13.4&prevision_jours=3' +{ + "Temperature": { + "temperature_moyenne": [ + 7.68 + ] + } + +curl -X GET 'http://127.0.0.1:5000/parapluie?x=52.12&y=13.4&prevision_jours=3' +{ + "sort_ton_parapluie": [] +} +``` + +## Technical Debt + +- Handle "," as the decimal separator +- Add logs diff --git a/api.py b/api.py new file mode 100644 index 0000000..c9c50a8 --- /dev/null +++ b/api.py @@ -0,0 +1,50 @@ +import utils.weather as weather +from flask import Flask, jsonify, request + +app = Flask(__name__) + + +@app.route("/temperature", methods=["GET"]) +def temperature(): + # Extract query parameters + latitude = request.args.get("x", type=float) + longitude = request.args.get("y", type=float) + forecast_days = request.args.get("prevision_jours", type=int) + + # Ensure all parameters are provided + if latitude is None or longitude is None or forecast_days is None: + return jsonify({"error": "Missing parameters"}), 400 + + # Call the weather_average function with the parameters + try: + average_temperature = weather.weather_average(latitude, longitude, forecast_days) + # Updated response format as per the requirement + return jsonify({"Temperature": {"temperature_moyenne": [average_temperature]}}) + except Exception as e: + return jsonify({"error": str(e)}), 500 + + +@app.route("/parapluie", methods=["GET"]) +def parapluie(): + # Extract query parameters for latitude and longitude + latitude = request.args.get("x", type=float) + longitude = request.args.get("y", type=float) + + # Ensure both parameters are provided + if latitude is None or longitude is None: + return jsonify({"error": "Missing parameters"}), 400 + + # The forecast is fixed to 2 + forecast_days = 2 + + # Call the need_umbrella function with the parameters + try: + times_list = weather.need_umbrella(latitude, longitude, forecast_days) + # Format the response as specified + return jsonify({"sort_ton_parapluie": times_list}) + except Exception as e: + return jsonify({"error": str(e)}), 500 + + +if __name__ == "__main__": + app.run(debug=True) diff --git a/requierement.txt b/requierement.txt new file mode 100644 index 0000000..44aee5e --- /dev/null +++ b/requierement.txt @@ -0,0 +1,2 @@ +Flask==3.0.2 +httpx==0.27.0 \ No newline at end of file diff --git a/utils/__init.py__ b/utils/__init.py__ new file mode 100644 index 0000000..e69de29 diff --git a/utils/weather.py b/utils/weather.py new file mode 100644 index 0000000..9683154 --- /dev/null +++ b/utils/weather.py @@ -0,0 +1,55 @@ +import httpx + +OPEN_METEO_URL = "https://api.open-meteo.com/v1/forecast" +HOURLY = "temperature_2m" + + +def weather_average(latitude: float, longitude: float, forecast: int) -> float: + + params = {"latitude": latitude, "longitude": longitude, "hourly": "temperature_2m", "forecast_days": forecast} + + # Using httpx to make the GET request + with httpx.Client() as client: + response = client.get(OPEN_METEO_URL, params=params) + + # Check if the response status code is 200 + if response.status_code == 200: + data = response.json() + else: + # Handle non-200 responses appropriately + response.raise_for_status() + + # Extracting the temperature data + weather_data = data["hourly"]["temperature_2m"] + + # Calculating the average temperature + average_data = round((sum(weather_data) / len(weather_data)), 2) + + return average_data + + +def need_umbrella(latitude: float, longitude: float, forecast: int) -> list: + + params = {"latitude": latitude, "longitude": longitude, "hourly": "precipitation_probability", "forecast_days": forecast} + + # Using httpx to make the GET request + with httpx.Client() as client: + response = client.get(OPEN_METEO_URL, params=params) + + # Check if the response status code is 200 + if response.status_code == 200: + data = response.json() + else: + # Handle non-200 responses appropriately + response.raise_for_status() + + # Extracting time and precipitation probability data + times = data["hourly"]["time"] + precipitation_probabilities = data["hourly"]["precipitation_probability"] + + # Filtering times where precipitation probability is >= 50 + times_with_high_precipitation = [ + times[i] for i, probability in enumerate(precipitation_probabilities) if probability >= 50 + ] + + return times_with_high_precipitation