packages feed

slackblocks-3.1.0: integrations/src/Send.hs

-- | Example application transport. The core slackblocks package has no HTTP
-- dependency; applications own credentials, endpoints, retries and routing.
module Send (ResponseKind (..), postPayload) where

import Control.Monad (unless)
import Data.Aeson (ToJSON, Value (..), eitherDecode, encode)
import Data.Aeson.KeyMap qualified as KM
import Data.ByteString qualified as B
import Network.HTTP.Client
import Network.HTTP.Types.Status (statusCode)

data ResponseKind = SlackAPI | Webhook

-- | Send an intact JSON object. API calls use a bearer token; webhook/response
-- URLs use Nothing. Do not log either credentials or credential-bearing URLs.
postPayload :: (ToJSON a) => Manager -> ResponseKind -> String -> Maybe B.ByteString -> a -> IO ()
postPayload manager kind endpoint token payload = do
  baseRequest <- parseRequest endpoint
  let request =
        baseRequest
          { method = "POST",
            requestHeaders =
              [("Content-Type", "application/json; charset=utf-8")]
                <> maybe [] (\value -> [("Authorization", "Bearer " <> value)]) token,
            requestBody = RequestBodyLBS (encode payload),
            redirectCount = 0,
            checkResponse = \_ _ -> pure ()
          }
  response <- httpLbs request manager
  let code = statusCode (responseStatus response)
  unless (code >= 200 && code < 300) (fail ("Slack HTTP status " <> show code))
  case kind of
    Webhook -> unless (responseBody response == "ok") (fail "Unexpected webhook response")
    SlackAPI -> case eitherDecode (responseBody response) of
      Right (Object result) | KM.lookup "ok" result == Just (Bool True) -> pure ()
      _ -> fail "Slack API did not confirm success"