or1ko's diary

日々を書きます

Outlook の Web APIを呼び出す例

Outlook の Web APIを呼び出すサンプルコードを書いた。

起動して http://localhost:8080/ にアクセスすると、
OAuth2のためにOutlookに転送され、許可すると、
http://localhost:8080に戻ってきて、
メッセージのタイトル一覧を表示する。

Outlook の Web APIを呼び出す方法は下記に記載あり。OAuth2でアクセストークンを取得し、APIを呼び出す。
Get Started with the Outlook REST APIs - Outlook Dev Center


使用したパッケージ
- base >= 4.7 && < 5
- Spock >= 0.11
- mtl
- text
- hoauth2
- http-types
- http-client
- bytestring
- http-client-tls
- aeson

{-# LANGUAGE OverloadedStrings #-}
module Main where

import Web.Spock
import Web.Spock.Config
import Network.OAuth.OAuth2

import Control.Monad
import Control.Monad.Trans
import Data.IORef
import qualified Data.Text as T
import qualified Data.Text.Encoding as TE
import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString as B
import qualified Network.HTTP.Types.URI as URI
import qualified Network.HTTP.Types.Header as Header
import qualified Network.HTTP.Client as HTTPClient
import qualified Network.HTTP.Client.TLS as TLS
import qualified Data.Aeson as Aeson


data MySession = EmptySession
data MyAppState = DummyAppState (IORef Int)

main :: IO ()
main =
    do ref <- newIORef 0
       spockCfg <- defaultSpockCfg EmptySession PCNoDatabase (DummyAppState ref)
       runSpock 8080 (spock spockCfg app)

oauth2Param :: OAuth2
oauth2Param = OAuth2 {
  oauthClientId = "<client_id>",
  oauthClientSecret = "<client_secret>",
  oauthOAuthorizeEndpoint = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
  oauthAccessTokenEndpoint = "https://login.microsoftonline.com/common/oauth2/v2.0/token",
  oauthCallback = Just "http://localhost:8080/"
}

scope = "https://outlook.office.com/mail.read"

redirectHotmail = redirect $ TE.decodeUtf8 $ appendQueryParam (authorizationUrl oauth2Param) [("scope", scope)]

getAccessToken code =
    do man <- HTTPClient.newManager TLS.tlsManagerSettings
       at <- fetchAccessToken man oauth2Param $ TE.encodeUtf8 code
       return $ TE.decodeUtf8 $ either BL.toStrict accessToken at

mail = "https://outlook.office.com/api/v2.0/me/messages"

mailparam = [
  ("$select", Just "Subject,From,ReceivedDateTime"),
  ("$top", Just "25"),
  ("$orderby", Just "ReceivedDateTime DESC")]

getMailBox :: T.Text -> IO BL.ByteString
getMailBox accessToken =
    do
      man <- HTTPClient.newManager TLS.tlsManagerSettings
      requestUrl <- HTTPClient.setQueryString mailparam <$> HTTPClient.parseRequest mail
      let request = requestUrl { HTTPClient.method = "GET",
                                 HTTPClient.secure = True,
                                 HTTPClient.requestHeaders = [(Header.hAuthorization, B.append "Bearer " $ TE.encodeUtf8 accessToken)]}
      res <- HTTPClient.httpLbs request man
      return $ HTTPClient.responseBody res

data MailMessage = MailMessage {
  subject :: T.Text
} deriving Show

instance Aeson.FromJSON MailMessage where
    parseJSON (Aeson.Object v) = MailMessage <$> (v Aeson..: "Subject")
    parseJSON _          = mzero

data MailBox = MailBox {
  value :: [MailMessage]
} deriving Show

instance Aeson.FromJSON MailBox where
    parseJSON (Aeson.Object v) = MailBox <$> (v Aeson..: "value")
    parseJSON _          = mzero

getMailMessages code = liftIO (getAccessToken code >>= getMailBox) >>= toHtml
  where
     toHtml body = html (maybe "" (T.unwords . map (T.append "<BR>" . subject) . value) (Aeson.decode body))

app :: SpockM () MySession MyAppState ()
app =
    get root $
        param "code" >>= maybe redirectHotmail getMailMessages