packages feed

polysemy-http-0.1.0.0: lib/Polysemy/Http/Request.hs

module Polysemy.Http.Request where

import qualified Data.Text as Text
import Prelude hiding (get)

import Polysemy.Http.Data.Request (Body, Host(Host), Method(..), Path(Path), Port(Port), Request(Request), Tls(Tls))

invalidScheme ::
  Text ->
  Text ->
  Either Text a
invalidScheme scheme url =
  Left [qt|invalid scheme `#{scheme}` in url: #{url}|]

split ::
  Text ->
  Text ->
  (Text, Maybe Text)
split target t =
  case Text.breakOn target t of
    (a, "") -> (a, Nothing)
    (a, b) -> (a, Just (Text.drop (Text.length target) b))

parseScheme ::
  Text ->
  (Text, Maybe Text) ->
  Either Text (Tls, Text)
parseScheme url = \case
  (full, Nothing) -> Right (Tls True, full)
  ("https", Just rest) -> Right (Tls True, rest)
  ("http", Just rest) -> Right (Tls False, rest)
  (scheme, _) -> invalidScheme scheme url

parseHostPort ::
  Text ->
  (Text, Maybe Text) ->
  Either Text (Host, Maybe Port)
parseHostPort url = \case
  (host, Nothing) -> Right (Host host, Nothing)
  (host, Just (readMaybe . toString -> Just port)) -> Right (Host host, Just (Port port))
  (_, Just port) -> Left [qt|invalid port `#{port}` in url: #{url}|]

parseUrl ::
  Text ->
  Either Text (Tls, Host, Maybe Port, Path)
parseUrl url = do
  (tls, split "/" -> (hostPort, path)) <- parseScheme url (split "://" url)
  (host, port) <- parseHostPort url (split ":" hostPort)
  pure (tls, host, port, Path (fromMaybe "" path))

withPort ::
  Maybe Port ->
  Tls ->
  Method ->
  Host ->
  Path ->
  Body ->
  Request
withPort port tls method host path =
  Request method host port tls path [] []

withTls ::
  Tls ->
  Method ->
  Host ->
  Path ->
  Body ->
  Request
withTls =
  withPort Nothing

simple ::
  Method ->
  Host ->
  Path ->
  Body ->
  Request
simple =
  withTls (Tls True)

get ::
  Host ->
  Path ->
  Request
get host path =
  simple Get host path ""

post ::
  Host ->
  Path ->
  Body ->
  Request
post host path =
  simple Post host path

put ::
  Host ->
  Path ->
  Body ->
  Request
put host path =
  simple Put host path

delete ::
  Host ->
  Path ->
  Request
delete host path =
  simple Delete host path ""

fromUrl ::
  Method ->
  Body ->
  Text ->
  Either Text Request
fromUrl method body url = do
  (tls, host, port, path) <- parseUrl url
  pure (withPort port tls method host path body)

getUrl ::
  Text ->
  Either Text Request
getUrl =
  fromUrl Get ""

postUrl ::
  Body ->
  Text ->
  Either Text Request
postUrl =
  fromUrl Post

putUrl ::
  Body ->
  Text ->
  Either Text Request
putUrl =
  fromUrl Put

deleteUrl ::
  Text ->
  Either Text Request
deleteUrl =
  fromUrl Delete ""