packages feed

mapquest-api 0.1.0.0 → 0.2.0.0

raw patch · 5 files changed

+139/−124 lines, 5 files

Files

mapquest-api.cabal view
@@ -1,5 +1,5 @@ name:                mapquest-api-version:             0.1.0.0+version:             0.2.0.0 synopsis:            Bindings to the MapQuest API description:         This library provides a high-level interface to the MapQuest API. Currently only the "geocoding" API (street address to coordinates) is provided, but the functionality is straightforward to extend. homepage:            https://github.com/ocramz/mapquest-api@@ -18,8 +18,8 @@   default-language:    Haskell2010   ghc-options:         -Wall   hs-source-dirs:      src-  exposed-modules:     Web.API.Mapquest-                       Web.API.Mapquest.Geocoding+  exposed-modules:     Web.API.MapQuest+  other-modules:       Web.API.MapQuest.Geocoding   build-depends:       base >= 4.7 && < 5                      , req                      , bytestring
+ src/Web/API/MapQuest.hs view
@@ -0,0 +1,24 @@+{-|+Module      : Web.API.MapQuest+Description : MapQuest+Copyright   : (c) Marco Zocca, 2018+License     : GPL-3+Maintainer  : zocca.marco gmail+Stability   : experimental+Portability : POSIX+-}+module Web.API.MapQuest (+  -- * Geocoding+  G.request,+  -- ** Parameters+  G.GeoQuery(..),+  -- ** Output+  G.Coords(..)+  ) where++import qualified Web.API.MapQuest.Geocoding as G+++++
+ src/Web/API/MapQuest/Geocoding.hs view
@@ -0,0 +1,112 @@+{-# language OverloadedStrings, DataKinds, DeriveGeneric #-}+{-|+Module      : Web.API.MapQuest.Geocoding+Description : Geocoding interface+Copyright   : (c) Marco Zocca, 2018+License     : GPL-3+Maintainer  : zocca.marco gmail+Stability   : experimental+Portability : POSIX+-}+module Web.API.MapQuest.Geocoding (request, GeoQuery(..), Coords(..))where++import Data.List (intersperse)+import Data.Monoid ((<>))++import Network.HTTP.Req+import qualified Data.Text as T+import qualified Data.ByteString.Lazy as LBS++import GHC.Generics++import Control.Monad.Catch++import Data.Aeson+import Data.Aeson.Types (Parser, parseMaybe)++-- https://developer.mapquest.com/documentation/geocoding-api/address/get/++apiRootPath :: Url 'Http+apiRootPath = http "www.mapquestapi.com" /: "geocoding" /: "v1" /: "address"+++-- example request :+-- GET http://www.mapquestapi.com/geocoding/v1/address?key=KEY&location=Washington,DC++instance MonadHttp IO where+  handleHttpException = throwM++-- | Call the MapQuest Geocoding API with a given address and extract the coordinates from the parsed result.+--+-- Example usage :+-- assuming the user has bound /key/ to hold the API key string, the following can be run in a GHCi shell :+--+-- >>> request key (GQ "Via Irnerio" "Bologna" "Italy")+-- Just (Coords {lat = 44.49897, long = 11.34503})+--+-- >>> request key (GQFree "Hong Kong")+-- Just (Coords {lat = 22.264412, long = 114.16706})++request ::+     T.Text  -- ^ API key (available for free on <https://developer.mapquest.com>)+  -> GeoQuery -- ^ Query address+  -> IO (Maybe (Coords Float))+request apikey q = do+  r <- req GET apiRootPath NoReqBody lbsResponse opts'+  return $ decoder1 $ responseBody r where+    opts' = +      ("key" =: apikey) <>+      ("outFormat" =: ("json" :: T.Text)) <>+      ("location" =: renderGeoQuery q)++++decoder1 :: LBS.ByteString -> Maybe (Coords Float)+decoder1 dat = do+  r <- decode dat+  flip parseMaybe r $ \obj -> do +    locp <- decodeLocation obj+    decodeLatLong locp++decodeLocation :: FromJSON a => Object -> Parser a+decodeLocation obj = do+    (res0 : _) <- obj .: "results"+    (loc0 : _) <- res0 .: "locations"+    return loc0++decodeLatLong :: Object -> Parser (Coords Float)+decodeLatLong loc = do+    ll <- loc .: "latLng"+    Coords <$> ll .: "lat" <*> ll .: "lng"+    +-- | Coordinates+data Coords a = Coords {+    lat :: a -- ^ Latitude+  , long :: a -- ^ Longitude+  } deriving (Eq, Show, Generic)++-- instance Functor Coords where+--   fmap f (Coords x y) = Coords (f x) (f y)++-- instance FromJSON a => FromJSON (Coords a)+++-- | Geocoding query parameters+data GeoQuery = GQ {+    gqStreet :: T.Text -- ^ Street address (e.g. \"Via Irnerio\")+  , gqCity :: T.Text   -- ^ City (e.g. \"Bologna\")+  , gqCountry :: T.Text -- ^ Country (e.g. \"Italy\")+  }+  | GQFree T.Text -- ^ Free-text query (must be a valid address or location)+  deriving (Eq, Show)++renderGeoQuery :: GeoQuery -> T.Text+renderGeoQuery q = case q of+  (GQ addr city country) -> T.concat $ intersperse ", " [addr, city, country]+  (GQFree t) -> t ++-- options :: Foldable t => t (T.Text, T.Text) -> Option 'Http+-- options = foldr (\(k, v) acc  -> (k =: v) <> acc ) mempty+++
− src/Web/API/Mapquest.hs
@@ -1,15 +0,0 @@-module Web.API.Mapquest (-  -- * Geocoding-  G.request,-  -- ** Parameters-  G.GeoQuery(..),-  -- ** Output-  G.Coords(..)-  ) where--import qualified Web.API.Mapquest.Geocoding as G-----
− src/Web/API/Mapquest/Geocoding.hs
@@ -1,106 +0,0 @@-{-# language OverloadedStrings, DataKinds, DeriveGeneric #-}-module Web.API.Mapquest.Geocoding (request, GeoQuery(..), Coords(..))where--import Data.List (intersperse)-import Data.Monoid (mempty, (<>))--import Network.HTTP.Req-import qualified Data.Text as T-import qualified Data.Text.Encoding as T (encodeUtf8, decodeUtf8)-import qualified Data.ByteString.Lazy as LBS--import GHC.Generics--import Control.Monad.Catch--import Data.Aeson-import Data.Aeson.Types (Parser(..), parseMaybe, parseEither)---- https://developer.mapquest.com/documentation/geocoding-api/address/get/--apiRootPath :: Url 'Http-apiRootPath = http "www.mapquestapi.com" /: "geocoding" /: "v1" /: "address"----- example request :--- GET http://www.mapquestapi.com/geocoding/v1/address?key=KEY&location=Washington,DC--instance MonadHttp IO where-  handleHttpException = throwM---- | Call the MapQuest Geocoding API with a given address and extract the coordinates from the parsed result.------ Example usage :--- assuming the user has bound /key/ to hold the API key string, the following can be run in a GHCi shell :------ >>> request key (GQ "Via Irnerio" "Bologna" "Italy")--- Just (Coords {lat = 44.49897, long = 11.34503})------ >>> request key (GQFree "Hong Kong")--- Just (Coords {lat = 22.264412, long = 114.16706})--request ::-     T.Text  -- ^ API key (available for free on mapquestapi.com)-  -> GeoQuery -- ^ Query address-  -> IO (Maybe (Coords Float))-request apikey q = do-  r <- req GET apiRootPath NoReqBody lbsResponse opts'-  return $ decoder1 $ responseBody r where-    opts' = -      ("key" =: apikey) <>-      ("outFormat" =: ("json" :: T.Text)) <>-      ("location" =: renderGeoQuery q)----decoder1 :: LBS.ByteString -> Maybe (Coords Float)-decoder1 dat = do-  r <- decode dat-  flip parseMaybe r $ \obj -> do -    locp <- decodeLocation obj-    decodeLatLong locp--decodeLocation :: FromJSON a => Object -> Parser a-decodeLocation obj = do-    (res0 : _) <- obj .: "results"-    (loc0 : _) <- res0 .: "locations"-    return loc0--decodeLatLong :: Object -> Parser (Coords Float)-decodeLatLong loc = do-    ll <- loc .: "latLng"-    Coords <$> ll .: "lat" <*> ll .: "lng"-    --- | Coordinates-data Coords a = Coords {-    lat :: a -- ^ Latitude-  , long :: a -- ^ Longitude-  } deriving (Eq, Show, Generic)---- instance Functor Coords where---   fmap f (Coords x y) = Coords (f x) (f y)---- instance FromJSON a => FromJSON (Coords a)--mkQuery :: T.Text -> T.Text -> T.Text -> GeoQuery-mkQuery = GQ---- | Geocoding query -data GeoQuery = GQ {-    gqStreet :: T.Text -- ^ Street address (e.g. \"Via Irnerio\")-  , gqCity :: T.Text   -- ^ City (e.g. \"Bologna\")-  , gqCountry :: T.Text -- ^ Country (e.g. \"Italy\")-  }-  | GQFree T.Text -- ^ Free-text query (must be a valid address or location)-  deriving (Eq, Show)--renderGeoQuery :: GeoQuery -> T.Text-renderGeoQuery q = case q of-  (GQ addr city country) -> T.concat $ intersperse ", " [addr, city, country]-  (GQFree t) -> t ---- options :: Foldable t => t (T.Text, T.Text) -> Option 'Http--- options = foldr (\(k, v) acc  -> (k =: v) <> acc ) mempty---