mapquest-api (empty) → 0.1.0.0
raw patch · 6 files changed
+209/−0 lines, 6 filesdep +aesondep +basedep +bytestringsetup-changed
Dependencies added: aeson, base, bytestring, exceptions, req, text
Files
- LICENSE +30/−0
- README.md +5/−0
- Setup.hs +2/−0
- mapquest-api.cabal +51/−0
- src/Web/API/Mapquest.hs +15/−0
- src/Web/API/Mapquest/Geocoding.hs +106/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Marco Zocca (c) 2018++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Marco Zocca nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,5 @@+# mapquest-api++[](https://travis-ci.org/ocramz/mapquest-api)++TODO Description.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ mapquest-api.cabal view
@@ -0,0 +1,51 @@+name: mapquest-api+version: 0.1.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+license: BSD3+license-file: LICENSE+author: Marco Zocca+maintainer: zocca.marco gmail+copyright: 2018 Marco Zocca+category: Web+build-type: Simple+extra-source-files: README.md+cabal-version: >=1.10+tested-with: GHC == 8.0.1++library+ default-language: Haskell2010+ ghc-options: -Wall+ hs-source-dirs: src+ exposed-modules: Web.API.Mapquest+ Web.API.Mapquest.Geocoding+ build-depends: base >= 4.7 && < 5+ , req+ , bytestring+ , text+ , aeson+ , exceptions++-- executable mapquest-api+-- default-language: Haskell2010+-- ghc-options: -threaded -rtsopts -with-rtsopts=-N+-- hs-source-dirs: app+-- main-is: Main.hs+-- build-depends: base+-- , mapquest-api++-- test-suite spec+-- default-language: Haskell2010+-- ghc-options: -Wall+-- type: exitcode-stdio-1.0+-- hs-source-dirs: test+-- main-is: Spec.hs+-- build-depends: base+-- , mapquest-api+-- , hspec+-- , QuickCheck++source-repository head+ type: git+ location: https://github.com/ocramz/mapquest-api
+ src/Web/API/Mapquest.hs view
@@ -0,0 +1,15 @@+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,106 @@+{-# 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+++