From 0b1981ef40404802a828f2a91ecadba3c2453034 Mon Sep 17 00:00:00 2001 From: Igor Pashev Date: Sun, 19 Apr 2020 12:26:49 +0200 Subject: Add forecast weather API --- lib/Web/OpenWeatherMap/API.hs | 26 +++++++++++++++++++++++-- lib/Web/OpenWeatherMap/Client.hs | 22 ++++++++++++++------- lib/Web/OpenWeatherMap/Types/City.hs | 21 ++++++++++++++++++++ lib/Web/OpenWeatherMap/Types/Coord.hs | 4 ++-- lib/Web/OpenWeatherMap/Types/Forecast.hs | 23 ++++++++++++++++++++++ lib/Web/OpenWeatherMap/Types/ForecastWeather.hs | 20 +++++++++++++++++++ 6 files changed, 105 insertions(+), 11 deletions(-) create mode 100644 lib/Web/OpenWeatherMap/Types/City.hs create mode 100644 lib/Web/OpenWeatherMap/Types/Forecast.hs create mode 100644 lib/Web/OpenWeatherMap/Types/ForecastWeather.hs (limited to 'lib/Web/OpenWeatherMap') diff --git a/lib/Web/OpenWeatherMap/API.hs b/lib/Web/OpenWeatherMap/API.hs index 8a1690e..6d06421 100644 --- a/lib/Web/OpenWeatherMap/API.hs +++ b/lib/Web/OpenWeatherMap/API.hs @@ -8,6 +8,8 @@ For API key (a.k.a appid) refer to . module Web.OpenWeatherMap.API ( weatherByName , weatherByCoord + , forecastByName + , forecastByCoord ) where import Data.Proxy (Proxy(..)) @@ -16,14 +18,22 @@ import Servant.API ((:<|>)(..), (:>), Get, JSON, QueryParam) import Servant.Client (ClientM, client) import Web.OpenWeatherMap.Types.CurrentWeather (CurrentWeather) +import Web.OpenWeatherMap.Types.ForecastWeather (ForecastWeather) type GetCurrentWeather = AppId :> Get '[ JSON] CurrentWeather +type GetForecastWeather = AppId :> Get '[ JSON] ForecastWeather + type AppId = QueryParam "appid" String -type API +type Current = "weather" :> QueryParam "q" String :> GetCurrentWeather :<|> "weather" :> QueryParam "lat" Double :> QueryParam "lon" Double :> GetCurrentWeather +type Forecast + = "forecast" :> QueryParam "q" String :> GetForecastWeather :<|> "forecast" :> QueryParam "lat" Double :> QueryParam "lon" Double :> GetForecastWeather + +type API = Current :<|> Forecast + -- | Request current weather in the city. weatherByName :: Maybe String -- ^ City name, e. g. \"Moscow\" or \"Moscow,ru\". @@ -35,4 +45,16 @@ weatherByCoord :: -> Maybe Double -- ^ Longitude, e. g. 37.6155600 for Moscow. -> Maybe String -- ^ API key. -> ClientM CurrentWeather -weatherByName :<|> weatherByCoord = client (Proxy :: Proxy API) +-- | Request forecast weather in the city. +forecastByName :: + Maybe String -- ^ City name, e. g. \"Moscow\" or \"Moscow,ru\". + -> Maybe String -- ^ API key. + -> ClientM ForecastWeather +-- | Request current weather at the geographic coordinates (in decimal degrees). +forecastByCoord :: + Maybe Double -- ^ Latitude, e. g. 55.7522200 for Moscow. + -> Maybe Double -- ^ Longitude, e. g. 37.6155600 for Moscow. + -> Maybe String -- ^ API key. + -> ClientM ForecastWeather +(weatherByName :<|> weatherByCoord) :<|> (forecastByName :<|> forecastByCoord) = + client (Proxy :: Proxy API) diff --git a/lib/Web/OpenWeatherMap/Client.hs b/lib/Web/OpenWeatherMap/Client.hs index c7ad7b6..445e2a4 100644 --- a/lib/Web/OpenWeatherMap/Client.hs +++ b/lib/Web/OpenWeatherMap/Client.hs @@ -4,6 +4,7 @@ High-level client functions perfoming requests to OpenWeatherMap API. module Web.OpenWeatherMap.Client ( Location(..) , getWeather + , getForecast ) where import Network.HTTP.Client (defaultManagerSettings, newManager) @@ -11,7 +12,6 @@ import Servant.Client ( BaseUrl(BaseUrl) , ClientEnv , ClientError - , ClientM , Scheme(Http) , mkClientEnv , runClientM @@ -19,6 +19,7 @@ import Servant.Client import qualified Web.OpenWeatherMap.API as API import Web.OpenWeatherMap.Types.CurrentWeather (CurrentWeather) +import Web.OpenWeatherMap.Types.ForecastWeather (ForecastWeather) -- | Various way to specify location. data Location @@ -33,13 +34,20 @@ getWeather :: -> Location -> IO (Either ClientError CurrentWeather) getWeather appid loc = defaultEnv >>= runClientM (api loc appid) + where + api (Name city) = API.weatherByName (Just city) . Just + api (Coord lat lon) = API.weatherByCoord (Just lat) (Just lon) . Just -api :: - Location - -> String -- ^ API key. - -> ClientM CurrentWeather -api (Name city) = API.weatherByName (Just city) . Just -api (Coord lat lon) = API.weatherByCoord (Just lat) (Just lon) . Just +-- | Make a request to OpenWeatherMap API +-- and return forecast weather in given location. +getForecast :: + String -- ^ API key. + -> Location + -> IO (Either ClientError ForecastWeather) +getForecast appid loc = defaultEnv >>= runClientM (api loc appid) + where + api (Name city) = API.forecastByName (Just city) . Just + api (Coord lat lon) = API.forecastByCoord (Just lat) (Just lon) . Just defaultEnv :: IO ClientEnv defaultEnv = do diff --git a/lib/Web/OpenWeatherMap/Types/City.hs b/lib/Web/OpenWeatherMap/Types/City.hs new file mode 100644 index 0000000..bb6cd6d --- /dev/null +++ b/lib/Web/OpenWeatherMap/Types/City.hs @@ -0,0 +1,21 @@ +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} + +module Web.OpenWeatherMap.Types.City + ( City(..) + ) where + +import GHC.Generics (Generic) + +import Data.Aeson (FromJSON) + +import Web.OpenWeatherMap.Types.Coord (Coord) + +data City = City + { name :: String + , country :: Maybe String + , coord :: Coord + , timezone :: Int + , sunset :: Int + , sunrise :: Int + } deriving (Show, Generic, FromJSON) diff --git a/lib/Web/OpenWeatherMap/Types/Coord.hs b/lib/Web/OpenWeatherMap/Types/Coord.hs index 517c532..0751964 100644 --- a/lib/Web/OpenWeatherMap/Types/Coord.hs +++ b/lib/Web/OpenWeatherMap/Types/Coord.hs @@ -10,6 +10,6 @@ import GHC.Generics (Generic) import Data.Aeson (FromJSON) data Coord = Coord - { lon :: Double - , lat :: Double + { lon :: Maybe Double + , lat :: Maybe Double } deriving (Show, Generic, FromJSON) diff --git a/lib/Web/OpenWeatherMap/Types/Forecast.hs b/lib/Web/OpenWeatherMap/Types/Forecast.hs new file mode 100644 index 0000000..3434930 --- /dev/null +++ b/lib/Web/OpenWeatherMap/Types/Forecast.hs @@ -0,0 +1,23 @@ +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} + +module Web.OpenWeatherMap.Types.Forecast + ( Forecast(..) + ) where + +import GHC.Generics (Generic) + +import Data.Aeson (FromJSON) + +import Web.OpenWeatherMap.Types.Clouds (Clouds) +import Web.OpenWeatherMap.Types.Main (Main) +import Web.OpenWeatherMap.Types.Weather (Weather) +import Web.OpenWeatherMap.Types.Wind (Wind) + +data Forecast = Forecast + { dt :: Int + , clouds :: Clouds + , main :: Main + , weather :: [Weather] + , wind :: Wind + } deriving (Show, Generic, FromJSON) diff --git a/lib/Web/OpenWeatherMap/Types/ForecastWeather.hs b/lib/Web/OpenWeatherMap/Types/ForecastWeather.hs new file mode 100644 index 0000000..fa8e50a --- /dev/null +++ b/lib/Web/OpenWeatherMap/Types/ForecastWeather.hs @@ -0,0 +1,20 @@ +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} + +module Web.OpenWeatherMap.Types.ForecastWeather + ( ForecastWeather(..) + ) where + +import GHC.Generics (Generic) + +import Data.Aeson (FromJSON) + +import Web.OpenWeatherMap.Types.City (City) +import Web.OpenWeatherMap.Types.Forecast (Forecast) + +-- | Response to requests for forecast weather. +-- Refer to . +data ForecastWeather = ForecastWeather + { list :: [Forecast] + , city :: City + } deriving (Show, Generic, FromJSON) -- cgit v1.2.3