generated from tpl/purs
fix: request api sucks less now
This commit is contained in:
parent
fb5a3ac359
commit
762f35a207
16
src/HTTP.js
16
src/HTTP.js
@ -1,3 +1,13 @@
|
|||||||
/** @type {(_: string) => (_: string) => (_: Record<string, string>) => (_: null | string | FormData) => () => Promise<Response>} */
|
/**
|
||||||
export const fetchImpl = url => method => headers => body => () =>
|
* @typedef {{
|
||||||
fetch(url, { redirect: 'manual', body, method, headers })
|
* body: string | ArrayBuffer | Blob | FormData | null,
|
||||||
|
* headers: Record<string, string>,
|
||||||
|
* credentials: RequestCredentials,
|
||||||
|
* method: string,
|
||||||
|
* url: string,
|
||||||
|
* }} RequestInit
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @type {(o: RequestInit) => () => Promise<Response>} */
|
||||||
|
export const fetchImpl = o => () =>
|
||||||
|
fetch(o.url, {...o, redirect: 'manual'})
|
||||||
|
@ -4,30 +4,72 @@ import Prelude
|
|||||||
|
|
||||||
import Control.Promise (Promise)
|
import Control.Promise (Promise)
|
||||||
import Control.Promise as Promise
|
import Control.Promise as Promise
|
||||||
|
import Data.Newtype (unwrap)
|
||||||
import Data.Nullable (Nullable)
|
import Data.Nullable (Nullable)
|
||||||
import Data.Nullable as Nullable
|
import Data.Nullable as Nullable
|
||||||
import Data.URL (URL)
|
import Data.URL (URL)
|
||||||
|
import Data.URL as URL
|
||||||
import Effect (Effect)
|
import Effect (Effect)
|
||||||
import Effect.Aff.Class (class MonadAff, liftAff)
|
import Effect.Aff.Class (class MonadAff, liftAff)
|
||||||
import Foreign.Object (Object)
|
import Foreign.Object (Object)
|
||||||
import Foreign.Object as Object
|
import Foreign.Object as Object
|
||||||
import HTTP.Header (Headers(..))
|
import HTTP.Header (Headers)
|
||||||
import HTTP.Header (headers) as X
|
import HTTP.Header (headers) as X
|
||||||
import HTTP.Request (bodyToRaw)
|
import HTTP.Request (Body(..), Credentials(..), Method, RawBody, bodyHeaders, bodyToRaw)
|
||||||
import HTTP.Request (class Request, Method(..)) as X
|
import HTTP.Request (Method(..)) as X
|
||||||
import HTTP.Request as Req
|
import HTTP.Request as Req
|
||||||
import HTTP.Response (Response)
|
import HTTP.Response (Response)
|
||||||
|
import Prim.Row (class Nub, class Union)
|
||||||
|
import Record as Record
|
||||||
|
import Type.Prelude (Proxy(..))
|
||||||
|
|
||||||
foreign import fetchImpl :: URL -> String -> Object String -> Nullable Req.RawRequestBody -> Effect (Promise Response)
|
foreign import fetchImpl
|
||||||
|
:: forall r
|
||||||
|
. Record
|
||||||
|
( body :: Nullable RawBody
|
||||||
|
, headers :: Object String
|
||||||
|
, credentials :: String
|
||||||
|
, method :: String
|
||||||
|
, url :: String
|
||||||
|
| r
|
||||||
|
)
|
||||||
|
-> Effect (Promise Response)
|
||||||
|
|
||||||
fetch :: forall m a. MonadAff m => Req.Request a => a -> m Response
|
type OptionalFields =
|
||||||
fetch req = do
|
( body :: Body
|
||||||
url <- Req.requestUrl req
|
, headers :: Headers
|
||||||
method <- Req.requestMethod req
|
, credentials :: Credentials
|
||||||
body <- Req.requestBody req
|
)
|
||||||
bodyRaw <- bodyToRaw body
|
|
||||||
Headers headers <- Req.requestHeaders req
|
|
||||||
|
|
||||||
|
makeOptionalFields
|
||||||
|
:: forall @x xm o
|
||||||
|
. Nub o OptionalFields
|
||||||
|
=> Union x OptionalFields o
|
||||||
|
=> Union x xm OptionalFields
|
||||||
|
=> {|x}
|
||||||
|
-> Record OptionalFields
|
||||||
|
makeOptionalFields x =
|
||||||
|
let
|
||||||
|
default :: Record OptionalFields
|
||||||
|
default =
|
||||||
|
{ body: BodyEmpty
|
||||||
|
, headers: mempty
|
||||||
|
, credentials: SameSiteCredentials
|
||||||
|
}
|
||||||
|
in
|
||||||
|
Record.merge x default
|
||||||
|
|
||||||
|
fetch
|
||||||
|
:: forall x xm m o
|
||||||
|
. MonadAff m
|
||||||
|
=> Nub o OptionalFields
|
||||||
|
=> Union x OptionalFields o
|
||||||
|
=> Union x xm OptionalFields
|
||||||
|
=> URL
|
||||||
|
-> Method
|
||||||
|
-> {|x}
|
||||||
|
-> m Response
|
||||||
|
fetch url method x = do
|
||||||
let
|
let
|
||||||
methodStr = case method of
|
methodStr = case method of
|
||||||
Req.GET -> "GET"
|
Req.GET -> "GET"
|
||||||
@ -36,6 +78,25 @@ fetch req = do
|
|||||||
Req.PATCH -> "PATCH"
|
Req.PATCH -> "PATCH"
|
||||||
Req.DELETE -> "DELETE"
|
Req.DELETE -> "DELETE"
|
||||||
Req.HEAD -> "HEAD"
|
Req.HEAD -> "HEAD"
|
||||||
headers' = Object.fromFoldableWithIndex headers
|
|
||||||
|
|
||||||
liftAff $ Promise.toAffE $ fetchImpl url methodStr headers' $ Nullable.toNullable bodyRaw
|
credsStr = case _ of
|
||||||
|
SameSiteCredentials -> "same-origin"
|
||||||
|
OmitCredentials -> "omit"
|
||||||
|
IncludeCredentials -> "include"
|
||||||
|
|
||||||
|
fields =
|
||||||
|
Record.modify (Proxy @"credentials") credsStr
|
||||||
|
$ Record.modify (Proxy @"headers") (Object.fromFoldableWithIndex <<< unwrap)
|
||||||
|
$ Record.insert (Proxy @"method") methodStr
|
||||||
|
$ Record.insert (Proxy @"url") (URL.toString url)
|
||||||
|
$ makeOptionalFields @x x
|
||||||
|
|
||||||
|
bodyHeaders' <- (Object.fromFoldableWithIndex <<< unwrap) <$> bodyHeaders fields.body
|
||||||
|
bodyRaw <- Nullable.toNullable <$> bodyToRaw fields.body
|
||||||
|
let
|
||||||
|
fields' =
|
||||||
|
Record.modify (Proxy @"headers") (Object.union bodyHeaders')
|
||||||
|
$ Record.set (Proxy @"body") bodyRaw
|
||||||
|
$ fields
|
||||||
|
|
||||||
|
liftAff $ Promise.toAffE $ fetchImpl fields'
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
import { fetch, ProxyAgent } from 'undici'
|
|
||||||
import { socksDispatcher } from 'fetch-socks'
|
|
||||||
|
|
||||||
/** @type {(_: URL) => (_: URL) => (_: string) => (_: Record<string, string>) => (_: null | string | FormData) => () => Promise<import('undici').Response>} */
|
|
||||||
export const fetchImpl = proxyURL => url => method => headers => body => () => {
|
|
||||||
const dispatcher = proxyURL.protocol.startsWith('https')
|
|
||||||
? new ProxyAgent(proxyURL.host)
|
|
||||||
: proxyURL.protocol.startsWith('socks')
|
|
||||||
? socksDispatcher({
|
|
||||||
type: 5,
|
|
||||||
host: proxyURL.hostname,
|
|
||||||
port: parseInt(proxyURL.port, 10),
|
|
||||||
})
|
|
||||||
: (() => {
|
|
||||||
throw new Error(`unsupported proxy scheme ${proxyURL.protocol}`)
|
|
||||||
})()
|
|
||||||
|
|
||||||
return fetch(url, { dispatcher })
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
module HTTP.Node (fetchProxy, module X) where
|
|
||||||
|
|
||||||
import Prelude
|
|
||||||
|
|
||||||
import Control.Promise (Promise)
|
|
||||||
import Control.Promise as Promise
|
|
||||||
import Data.Nullable (Nullable)
|
|
||||||
import Data.Nullable as Nullable
|
|
||||||
import Data.URL (URL)
|
|
||||||
import Effect (Effect)
|
|
||||||
import Effect.Aff.Class (class MonadAff, liftAff)
|
|
||||||
import Foreign.Object (Object)
|
|
||||||
import Foreign.Object as Object
|
|
||||||
import HTTP.Header (Headers(..))
|
|
||||||
import HTTP.Header (headers) as X
|
|
||||||
import HTTP.Request (bodyToRaw)
|
|
||||||
import HTTP.Request (class Request, Method(..)) as X
|
|
||||||
import HTTP.Request as Req
|
|
||||||
import HTTP.Response (Response)
|
|
||||||
|
|
||||||
foreign import fetchImpl :: URL -> URL -> String -> Object String -> Nullable Req.RawRequestBody -> Effect (Promise Response)
|
|
||||||
|
|
||||||
fetchProxy :: forall m a. MonadAff m => Req.Request a => URL -> a -> m Response
|
|
||||||
fetchProxy pxy req = do
|
|
||||||
url <- Req.requestUrl req
|
|
||||||
method <- Req.requestMethod req
|
|
||||||
body <- Req.requestBody req
|
|
||||||
bodyRaw <- bodyToRaw body
|
|
||||||
Headers headers <- Req.requestHeaders req
|
|
||||||
|
|
||||||
let
|
|
||||||
methodStr = case method of
|
|
||||||
Req.GET -> "GET"
|
|
||||||
Req.PUT -> "PUT"
|
|
||||||
Req.POST -> "POST"
|
|
||||||
Req.PATCH -> "PATCH"
|
|
||||||
Req.DELETE -> "DELETE"
|
|
||||||
Req.HEAD -> "HEAD"
|
|
||||||
headers' = Object.fromFoldableWithIndex headers
|
|
||||||
|
|
||||||
liftAff $ Promise.toAffE $ fetchImpl pxy url methodStr headers' $ Nullable.toNullable bodyRaw
|
|
@ -1,18 +1,15 @@
|
|||||||
module HTTP.Request
|
module HTTP.Request
|
||||||
( class Request
|
( Credentials(..)
|
||||||
, Body(..)
|
, Body(..)
|
||||||
, RawRequestBody
|
, RawBody
|
||||||
, Method(..)
|
, Method(..)
|
||||||
|
, bodyHeaders
|
||||||
, bodyToRaw
|
, bodyToRaw
|
||||||
, json
|
, json
|
||||||
, form
|
, form
|
||||||
, blob
|
, blob
|
||||||
, arrayBuffer
|
, arrayBuffer
|
||||||
, requestBody
|
, rawBodySize
|
||||||
, requestHeaders
|
|
||||||
, requestUrl
|
|
||||||
, requestMethod
|
|
||||||
, rawRequestBodySize
|
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Prelude
|
import Prelude
|
||||||
@ -24,11 +21,7 @@ import Data.Eq.Generic (genericEq)
|
|||||||
import Data.Generic.Rep (class Generic)
|
import Data.Generic.Rep (class Generic)
|
||||||
import Data.Maybe (Maybe(..))
|
import Data.Maybe (Maybe(..))
|
||||||
import Data.Newtype (unwrap)
|
import Data.Newtype (unwrap)
|
||||||
import Data.Nullable as Nullable
|
|
||||||
import Data.Show.Generic (genericShow)
|
import Data.Show.Generic (genericShow)
|
||||||
import Data.Tuple.Containing (extract)
|
|
||||||
import Data.Tuple.Nested (type (/\))
|
|
||||||
import Data.URL (URL)
|
|
||||||
import Effect (Effect)
|
import Effect (Effect)
|
||||||
import Effect.Aff.Class (class MonadAff, liftAff)
|
import Effect.Aff.Class (class MonadAff, liftAff)
|
||||||
import Effect.Class (class MonadEffect, liftEffect)
|
import Effect.Class (class MonadEffect, liftEffect)
|
||||||
@ -43,25 +36,27 @@ import Unsafe.Coerce (unsafeCoerce)
|
|||||||
import Web.File.Blob (Blob)
|
import Web.File.Blob (Blob)
|
||||||
import Web.File.Blob as Blob
|
import Web.File.Blob as Blob
|
||||||
|
|
||||||
foreign import data RawRequestBody :: Type
|
foreign import data RawBody :: Type
|
||||||
|
|
||||||
foreign import blobArrayBufferImpl :: Blob -> Effect (Promise ArrayBuffer)
|
foreign import blobArrayBufferImpl :: Blob -> Effect (Promise ArrayBuffer)
|
||||||
foreign import rawRequestBodySize :: RawRequestBody -> Effect Int
|
foreign import rawBodySize :: RawBody -> Effect Int
|
||||||
|
|
||||||
unsafeEmptyRawRequestBody :: RawRequestBody
|
unsafeStringRawBody :: String -> RawBody
|
||||||
unsafeEmptyRawRequestBody = unsafeCoerce Nullable.null
|
unsafeStringRawBody = unsafeCoerce
|
||||||
|
|
||||||
unsafeStringRawRequestBody :: String -> RawRequestBody
|
unsafeFormDataToRawBody :: RawFormData -> RawBody
|
||||||
unsafeStringRawRequestBody = unsafeCoerce
|
unsafeFormDataToRawBody = unsafeCoerce
|
||||||
|
|
||||||
unsafeFormDataToRawRequestBody :: RawFormData -> RawRequestBody
|
unsafeArrayBufferToRawBody :: ArrayBuffer -> RawBody
|
||||||
unsafeFormDataToRawRequestBody = unsafeCoerce
|
unsafeArrayBufferToRawBody = unsafeCoerce
|
||||||
|
|
||||||
unsafeArrayBufferToRawRequestBody :: ArrayBuffer -> RawRequestBody
|
unsafeBlobToRawBody :: forall m. MonadAff m => Blob -> m RawBody
|
||||||
unsafeArrayBufferToRawRequestBody = unsafeCoerce
|
unsafeBlobToRawBody = map unsafeArrayBufferToRawBody <<< liftAff <<< Promise.toAffE <<< blobArrayBufferImpl
|
||||||
|
|
||||||
unsafeBlobToRawRequestBody :: forall m. MonadAff m => Blob -> m RawRequestBody
|
data Credentials
|
||||||
unsafeBlobToRawRequestBody = map unsafeArrayBufferToRawRequestBody <<< liftAff <<< Promise.toAffE <<< blobArrayBufferImpl
|
= IncludeCredentials
|
||||||
|
| OmitCredentials
|
||||||
|
| SameSiteCredentials
|
||||||
|
|
||||||
data Body
|
data Body
|
||||||
= BodyString String (Maybe ContentType)
|
= BodyString String (Maybe ContentType)
|
||||||
@ -89,11 +84,11 @@ bodyHeaders (BodyString _ ct) = liftEffect $ Header.headers ct
|
|||||||
bodyHeaders (BodyArrayBuffer _ ct) = liftEffect $ Header.headers ct
|
bodyHeaders (BodyArrayBuffer _ ct) = liftEffect $ Header.headers ct
|
||||||
bodyHeaders (BodyBlob b) = liftEffect $ Header.headers <<< map (ContentType <<< MIME.fromString <<< unwrap) $ Blob.type_ b
|
bodyHeaders (BodyBlob b) = liftEffect $ Header.headers <<< map (ContentType <<< MIME.fromString <<< unwrap) $ Blob.type_ b
|
||||||
|
|
||||||
bodyToRaw :: forall m. MonadAff m => Body -> m (Maybe RawRequestBody)
|
bodyToRaw :: forall m. MonadAff m => Body -> m (Maybe RawBody)
|
||||||
bodyToRaw (BodyString body _) = pure $ Just $ unsafeStringRawRequestBody body
|
bodyToRaw (BodyString body _) = pure $ Just $ unsafeStringRawBody body
|
||||||
bodyToRaw (BodyArrayBuffer body _) = pure $ Just $ unsafeArrayBufferToRawRequestBody body
|
bodyToRaw (BodyArrayBuffer body _) = pure $ Just $ unsafeArrayBufferToRawBody body
|
||||||
bodyToRaw (BodyForm form') = map Just $ map unsafeFormDataToRawRequestBody $ Form.toRawFormData form'
|
bodyToRaw (BodyForm form') = map Just $ map unsafeFormDataToRawBody $ Form.toRawFormData form'
|
||||||
bodyToRaw (BodyBlob body) = map Just $ unsafeBlobToRawRequestBody body
|
bodyToRaw (BodyBlob body) = map Just $ unsafeBlobToRawBody body
|
||||||
bodyToRaw BodyEmpty = pure Nothing
|
bodyToRaw BodyEmpty = pure Nothing
|
||||||
|
|
||||||
data Method
|
data Method
|
||||||
@ -111,57 +106,3 @@ instance Eq Method where
|
|||||||
instance Show Method where
|
instance Show Method where
|
||||||
show = genericShow
|
show = genericShow
|
||||||
|
|
||||||
class Request :: Type -> Constraint
|
|
||||||
class Request a where
|
|
||||||
requestUrl :: forall m. MonadAff m => a -> m URL
|
|
||||||
requestMethod :: forall m. MonadAff m => a -> m Method
|
|
||||||
requestBody :: forall m. MonadAff m => a -> m Body
|
|
||||||
requestHeaders :: forall m. MonadAff m => a -> m Headers
|
|
||||||
|
|
||||||
instance Request (Method /\ URL /\ Body /\ Effect Headers) where
|
|
||||||
requestUrl = pure <<< extract
|
|
||||||
requestMethod = pure <<< extract
|
|
||||||
requestBody = pure <<< extract
|
|
||||||
requestHeaders req = do
|
|
||||||
hs <- liftEffect $ extract req
|
|
||||||
bodyHs <- bodyHeaders $ extract req
|
|
||||||
pure $ hs <> bodyHs
|
|
||||||
|
|
||||||
instance Request (Method /\ URL /\ Body /\ Headers) where
|
|
||||||
requestUrl = pure <<< extract
|
|
||||||
requestMethod = pure <<< extract
|
|
||||||
requestBody = pure <<< extract
|
|
||||||
requestHeaders req = do
|
|
||||||
let hs = extract req
|
|
||||||
bodyHs <- bodyHeaders $ extract req
|
|
||||||
pure $ hs <> bodyHs
|
|
||||||
|
|
||||||
instance Request (Method /\ URL /\ Body) where
|
|
||||||
requestUrl = pure <<< extract
|
|
||||||
requestMethod = pure <<< extract
|
|
||||||
requestBody = pure <<< extract
|
|
||||||
requestHeaders _ = pure mempty
|
|
||||||
|
|
||||||
instance Request (Method /\ URL /\ Headers) where
|
|
||||||
requestUrl = pure <<< extract
|
|
||||||
requestMethod = pure <<< extract
|
|
||||||
requestBody _ = pure BodyEmpty
|
|
||||||
requestHeaders = pure <<< extract
|
|
||||||
|
|
||||||
instance Request (Method /\ URL /\ Effect Headers) where
|
|
||||||
requestUrl = pure <<< extract
|
|
||||||
requestMethod = pure <<< extract
|
|
||||||
requestBody _ = pure BodyEmpty
|
|
||||||
requestHeaders = liftEffect <<< extract @(Effect Headers)
|
|
||||||
|
|
||||||
instance Request (Method /\ URL) where
|
|
||||||
requestUrl = pure <<< extract
|
|
||||||
requestMethod = pure <<< extract
|
|
||||||
requestBody _ = pure BodyEmpty
|
|
||||||
requestHeaders _ = pure mempty
|
|
||||||
|
|
||||||
instance Request URL where
|
|
||||||
requestUrl = pure
|
|
||||||
requestMethod _ = pure GET
|
|
||||||
requestBody _ = pure BodyEmpty
|
|
||||||
requestHeaders _ = pure mempty
|
|
||||||
|
Loading…
Reference in New Issue
Block a user