diff options
Diffstat (limited to 'lib/Web')
-rw-r--r-- | lib/Web/OpenWeatherMap/API.hs | 45 | ||||
-rw-r--r-- | lib/Web/OpenWeatherMap/Client.hs | 49 | ||||
-rw-r--r-- | lib/Web/OpenWeatherMap/Types/Clouds.hs | 16 | ||||
-rw-r--r-- | lib/Web/OpenWeatherMap/Types/Coord.hs | 17 | ||||
-rw-r--r-- | lib/Web/OpenWeatherMap/Types/CurrentWeather.hs | 35 | ||||
-rw-r--r-- | lib/Web/OpenWeatherMap/Types/Main.hs | 23 | ||||
-rw-r--r-- | lib/Web/OpenWeatherMap/Types/Sys.hs | 19 | ||||
-rw-r--r-- | lib/Web/OpenWeatherMap/Types/Weather.hs | 19 | ||||
-rw-r--r-- | lib/Web/OpenWeatherMap/Types/Wind.hs | 17 |
9 files changed, 240 insertions, 0 deletions
diff --git a/lib/Web/OpenWeatherMap/API.hs b/lib/Web/OpenWeatherMap/API.hs new file mode 100644 index 0000000..0c1e282 --- /dev/null +++ b/lib/Web/OpenWeatherMap/API.hs @@ -0,0 +1,45 @@ +{-| +Direct API functions. +For API key (a.k.a appid) refer to <http://openweathermap.org/appid>. +-} + +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE TypeOperators #-} + +module Web.OpenWeatherMap.API ( + weatherByName, + weatherByCoord +) where + +import Data.Proxy (Proxy(..)) + +import Servant.API ((:>), (:<|>)(..), JSON, Get, QueryParam) +import Servant.Client (client) +import Servant.Common.Req (ClientM) + +import Web.OpenWeatherMap.Types.CurrentWeather (CurrentWeather) + + +type GetCurrentWeather = AppId :> Get '[JSON] CurrentWeather +type AppId = QueryParam "appid" String + +type API + = "weather" :> QueryParam "q" String :> GetCurrentWeather + :<|> "weather" :> QueryParam "lat" Double :> QueryParam "lon" Double + :> GetCurrentWeather + +-- | Request current weather in the city. +weatherByName + :: Maybe String -- ^ City name, e. g. \"Moscow\" or \"Moscow,ru\". + -> Maybe String -- ^ API key. + -> ClientM CurrentWeather + +-- | Request current weather at the geographic coordinates (in decimal degrees). +weatherByCoord + :: Maybe Double -- ^ Latitude, e. g. 55.7522200 for Moscow. + -> Maybe Double -- ^ Longitude, e. g. 37.6155600 for Moscow. + -> Maybe String -- ^ API key. + -> ClientM CurrentWeather + +weatherByName :<|> weatherByCoord = client (Proxy :: Proxy API) + diff --git a/lib/Web/OpenWeatherMap/Client.hs b/lib/Web/OpenWeatherMap/Client.hs new file mode 100644 index 0000000..7804ef2 --- /dev/null +++ b/lib/Web/OpenWeatherMap/Client.hs @@ -0,0 +1,49 @@ +{-| +High-level client functions perfoming requests to OpenWeatherMap API. +-} +module Web.OpenWeatherMap.Client ( + Location(..), + getWeather +) where + +import Network.HTTP.Client (newManager, defaultManagerSettings) +import Servant.Client (ClientEnv(..), runClientM, ServantError) +import Servant.Common.BaseUrl (BaseUrl(..), Scheme(..)) +import Servant.Common.Req (ClientM) + +import Web.OpenWeatherMap.Types.CurrentWeather (CurrentWeather) +import qualified Web.OpenWeatherMap.API as API + + +-- | Various way to specify location. +data Location + = Name String -- ^ City name. + | Coord Double Double -- ^ Geographic coordinates: latitude and longitude. + + +-- | Make a request to OpenWeatherMap API +-- and return current weather in given location. +getWeather + :: String -- ^ API key. + -> Location + -> IO (Either ServantError CurrentWeather) +getWeather appid loc = + defaultEnv >>= runClientM (api loc appid) + +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 + +defaultEnv :: IO ClientEnv +defaultEnv = do + manager <- newManager defaultManagerSettings + return $ ClientEnv manager baseUrl + +-- XXX openweathermap.org does not support HTTPS, +-- XXX appid is passed in clear text. Oops. +baseUrl :: BaseUrl +baseUrl = BaseUrl Http "api.openweathermap.org" 80 "/data/2.5" + diff --git a/lib/Web/OpenWeatherMap/Types/Clouds.hs b/lib/Web/OpenWeatherMap/Types/Clouds.hs new file mode 100644 index 0000000..78a6e97 --- /dev/null +++ b/lib/Web/OpenWeatherMap/Types/Clouds.hs @@ -0,0 +1,16 @@ +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} + +module Web.OpenWeatherMap.Types.Clouds ( + Clouds(..) +) where + +import GHC.Generics (Generic) + +import Data.Aeson (FromJSON) + + +data Clouds = Clouds + { all :: Double + } deriving (Show, Generic, FromJSON) + diff --git a/lib/Web/OpenWeatherMap/Types/Coord.hs b/lib/Web/OpenWeatherMap/Types/Coord.hs new file mode 100644 index 0000000..d9a9f21 --- /dev/null +++ b/lib/Web/OpenWeatherMap/Types/Coord.hs @@ -0,0 +1,17 @@ +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} + +module Web.OpenWeatherMap.Types.Coord ( + Coord(..) +) where + +import GHC.Generics (Generic) + +import Data.Aeson (FromJSON) + + +data Coord = Coord + { lon :: Double + , lat :: Double + } deriving (Show, Generic, FromJSON) + diff --git a/lib/Web/OpenWeatherMap/Types/CurrentWeather.hs b/lib/Web/OpenWeatherMap/Types/CurrentWeather.hs new file mode 100644 index 0000000..26572a7 --- /dev/null +++ b/lib/Web/OpenWeatherMap/Types/CurrentWeather.hs @@ -0,0 +1,35 @@ +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} + +module Web.OpenWeatherMap.Types.CurrentWeather ( + CurrentWeather(..) +) where + +import Prelude hiding (id) +import GHC.Generics (Generic) + +import Data.Aeson (FromJSON) + +import Web.OpenWeatherMap.Types.Clouds (Clouds) +import Web.OpenWeatherMap.Types.Coord (Coord) +import Web.OpenWeatherMap.Types.Main (Main) +import Web.OpenWeatherMap.Types.Sys (Sys) +import Web.OpenWeatherMap.Types.Weather (Weather) +import Web.OpenWeatherMap.Types.Wind (Wind) + +-- | Response to requests for current weather. +-- Refer to <https://openweathermap.org/current>. +data CurrentWeather = CurrentWeather + { coord :: Coord + , weather :: [Weather] + , base :: String + , main :: Main + , wind :: Wind + , clouds :: Clouds + , dt :: Int + , sys :: Sys + , id :: Int + , name :: String + , cod :: Int + } deriving (Show, Generic, FromJSON) + diff --git a/lib/Web/OpenWeatherMap/Types/Main.hs b/lib/Web/OpenWeatherMap/Types/Main.hs new file mode 100644 index 0000000..21b1951 --- /dev/null +++ b/lib/Web/OpenWeatherMap/Types/Main.hs @@ -0,0 +1,23 @@ +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} + +module Web.OpenWeatherMap.Types.Main ( + Main(..) +) where + +import GHC.Generics (Generic) + +import Data.Aeson (FromJSON) + + +{-# ANN module "HLint: ignore Use camelCase" #-} +data Main = Main + { temp :: Double + , pressure :: Double + , humidity :: Double + , temp_min :: Double + , temp_max :: Double + , sea_level :: Maybe Double + , grnd_level :: Maybe Double + } deriving (Show, Generic, FromJSON) + diff --git a/lib/Web/OpenWeatherMap/Types/Sys.hs b/lib/Web/OpenWeatherMap/Types/Sys.hs new file mode 100644 index 0000000..03b223c --- /dev/null +++ b/lib/Web/OpenWeatherMap/Types/Sys.hs @@ -0,0 +1,19 @@ +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} + +module Web.OpenWeatherMap.Types.Sys ( + Sys(..) +) where + +import GHC.Generics (Generic) + +import Data.Aeson (FromJSON) + + +data Sys = Sys + { message :: Double + , country :: Maybe String + , sunrise :: Int + , sunset :: Int + } deriving (Show, Generic, FromJSON) + diff --git a/lib/Web/OpenWeatherMap/Types/Weather.hs b/lib/Web/OpenWeatherMap/Types/Weather.hs new file mode 100644 index 0000000..090fe0f --- /dev/null +++ b/lib/Web/OpenWeatherMap/Types/Weather.hs @@ -0,0 +1,19 @@ +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} + +module Web.OpenWeatherMap.Types.Weather ( + Weather(..) +) where + +import GHC.Generics (Generic) + +import Data.Aeson (FromJSON) + + +data Weather = Weather + { id :: Int + , main :: String + , description :: String + , icon :: String + } deriving (Show, Generic, FromJSON) + diff --git a/lib/Web/OpenWeatherMap/Types/Wind.hs b/lib/Web/OpenWeatherMap/Types/Wind.hs new file mode 100644 index 0000000..8481e62 --- /dev/null +++ b/lib/Web/OpenWeatherMap/Types/Wind.hs @@ -0,0 +1,17 @@ +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} + +module Web.OpenWeatherMap.Types.Wind ( + Wind(..) +) where + +import GHC.Generics (Generic) + +import Data.Aeson (FromJSON) + + +data Wind = Wind + { speed :: Double + , deg :: Double + } deriving (Show, Generic, FromJSON) + |