This is a simple Ruby on Rails application that exposes an API for retrieving weather data for a given city.
The API endpoint allows users to retrieve weather data such as temperature, humidity, and wind speed for a specific city.
Make sure you have Docker installed on your machine.
Docker will take care of eveyrthing else.
For correct work of the application, you need to set OpenWeatherMap API key under OPEN_WEATHER_MAP_APP_ID
environment variable.
Copy example .env
file and set your API key.
$ cp .env.example .env
# in .env file
OPEN_WEATHER_MAP_APP_ID=your_open_weather_map_api_key
NOTE:
If you don't have a key, you can get it by registering on OpenWeatherMap website.
API key could be obtained from API keys section.
Free key limitations is 60 calls per minute and 1,000,000 calls per month.
$ docker-compose build
$ docker-compose up
NOTE:
This mode show logs from all docker-compose services what might be not very useful.
Applications stops automatically by pressingCtrl+C
$ docker-compose up -d --build
$ docker-compose up -d
$ docker-compose down
$ docker-compose logs -f web
NOTE:
This mode attaches to logs of service and will show logs in real-time.
To check logs of other services replaceweb
with service name.
Availablle services:web
,postgres
,redis
,otel-collector
,jaeger
,prometheus
,grafana
$ docker-compose exec web bin/rails c
Note: You might need to run migrations before running tests. To run migrations, open Rails console in running container and run:
$ RAILS_ENV=test bin/rails db:migrate
$ rspec
$ rubocop
$ rubocop -a
or for specific cop
$ rubocop -a --only <cop_name>
Offences to be ignored could be set in .rubocop_todo.yml
file.
$ rubocop --regenerate-todo
API flow is displayed in the diagram
OpenWeatherMap deprecates automatic geolocation for Weather API. This splits flow into two parts:
- Get city coordinates by city name from OpenWeatherMap Geolocating API
OpenWeatherMap::Clients::Geocoding.new.direct(...)
- Get weather data by coordinates from OpenWeatherMap Weather API
OpenWeatherMap::Clients::Weather.current_wather(...)
In order to reduce external API usage and avoid rate limit hits, both clients user cache.
Geolocation cache does not expiry date because unlikely city coordinates will change.
Weather cache is set to 10 minutes by default. This is a reasonable time for weather data.
Both clients are wrapped in OpenWeatherMap::Weather
service that provides a single entry point for weather data retrieval.T
The service also uses caching.
OpenWeatherMap API has default modes and units for weather data.
This was used in cache key generation, because:
GET /weather?q=London
is effectively the same as
GET /weather?q=London&units=standard&mode=json&lang=en
Client uses default units and mode for weather data, so it is safe to use them in cache key generation and avoids unnecessary cache hits for equivalent requests.
It was decided not to add cache APP Id, because in future we could implement token load balancing.
Having APP Id will make unnecessary cache overhead for equivalent requests.
Example:
module OpenWeatherMap
module Clients
class Weather < BaseClient
...
def current_weather(lat:, lon:, units: nil, mode: nil, lang: nil)
units = DEFAULT_UNITS unless units.in? ALLOWED_UNITS
mode = DEFAULT_MODE unless mode.in? ALLOWED_MODES
lang = DEFAULT_LANG unless lang.in? ALLOWED_LANGS
query = { lat: lat, lon: lon, units: units, mode: mode, lang: lang, appid: @app_id }
cache_key = query.except(:appid)
Caching.fetch(cache_key, namespace: CACHE_NAMESPACE) do
...
end
end
...
end
end
end
Open browser and navigate to http://localhost:3001
NOTE: Credentials requeried
username:admin
password:admin
NOTE: Dashboards
Three dashboards are available:
- Averagge Rate Dashboard
- Average Response Time Dashboard
- Home Dashboard (both Average Rate and Average Response Time in one) For more details go to
Explore
NOTE: Data Sources
Jaeger
andPrometheus
are used as data sources at the moment.
For more details go toExplore
and select required data source.
Open browser and navigate to http://localhost:9090
Open browser and navigate to http://localhost:16686
NOTE: Traces
Make few api calls to see traces in Jaeger UI.
To see traces, click onSearch
and then selectweather_api
underServce
dropdown.
Traces are bieing generated for each API call with Opentelemetry.
Postman collection is available in doc/postman/Simple Weather API.postman_collection.json
file.
Collection contains API documentations and examples of requests.
Import it to Postman and use for testing API.
-[ ] Add support for geolocation by ZIP and country codes
-[ ] Add support for multiple languages
-[ ] Expand language support
-[ ] Add token based authentication
-[ ] Reduce weather cachce life to a possible minimum
-[ ] Store freueqent citi names or coordinates in database. Such information could be regulary refreshed with background job to response time.
-[ ] Reduce Rack::Attack throttling time to a possible minimum
-[ ] Add visualisation for CPU usage in Grafana
-[ ] Add visualisation for RAM usage in Grafana
-[ ] Add metrics for failed requests
-[ ] Add metrics for OpenWeatherMap API rate exceedings