purescript-wai icon indicating copy to clipboard operation
purescript-wai copied to clipboard

Provide backend-specific types and use row polymorphism everywhere else

Open JordanMartinez opened this issue 5 years ago • 3 comments

Given that Request includes a backend-specific request object, it might be better to redefine that type via row polymorphism:

newtype Request otherRows
    = Request { method          :: H.Method 
              , rawPathInfo     :: String
              , httpVersion     :: H.HttpVersion
              , rawQueryString  :: String
              , requestHeaders  :: H.RequestHeaders
              , isSecure        :: Boolean
              , remoteHost      :: String 
              , pathInfo        :: Array String 
              , queryString     :: Object String 
              , body            :: Aff (Maybe Buffer)
              , bodyLength      :: RequestBodyLength
              , headerHost      :: String 
              , headerRange     :: Maybe String 
              , headerReferer   :: Maybe String 
              , headerUserAgent :: Maybe String
              , rawHeader       :: Maybe Buffer
              | otherRows
              }

newtype RequestNodeJs =
  RequestNodeJs (Request (nodeRequest :: Maybe HTTP.Request))

defaultRequest would need to be changed. There's two ways:

  • change it to a RecordBuilder API, so that one can build it
  • specify a backend-specific one for each

JordanMartinez avatar May 25 '20 23:05 JordanMartinez

Hey @JordanMartinez, I really appreciate having you jump in! The only problem that I have with this approach is that we need to add params to the Request type. I want a solution that avoids end-user having to pass a tag around.

I am looking for a solution that keeps the type very simple without leaking the internal type. End-users should only access it if they know what they are doing.

With the help of @paluh, I was thinking about keeping it simple and go with this approach:

newtype Request 
    = Request { method          :: H.Method 
              , rawPathInfo     :: String
              , httpVersion     :: H.HttpVersion
              , httpType        :: String
              , rawQueryString  :: String
              , requestHeaders  :: H.RequestHeaders
              , isSecure        :: Boolean
              , remoteHost      :: String 
              , pathInfo        :: Array String 
              , queryString     :: Object String 
              , body            :: Aff (Maybe Buffer)
              , bodyLength      :: RequestBodyLength
              , headerHost      :: String 
              , headerRange     :: Maybe String 
              , headerReferer   :: Maybe String 
              , headerUserAgent :: Maybe String
              , rawHeader       :: Maybe Buffer
              , nodeRequest     :: Maybe Foreign
              }

Have a function like nodeHttpRequest :: Request -> Maybe HTTP.Request which allows one to extract the node request object using the httpType field by pattern matching.

Someone else suggested that I follow Hyper's approach https://github.com/purescript-hyper/hyper/blob/master/src/Hyper/Node/Server.purs#L53-L54

Woody88 avatar May 29 '20 15:05 Woody88

I think @paluh's approach makes sense. On second thought, I don't think it's worth it to try to keep things backend-unspecific yet because we don't yet have strong compiler support for non-JS backends.

JordanMartinez avatar May 29 '20 20:05 JordanMartinez

Just for a reference (and possible further discussion) I've also proposed this quite lightweight type safe form of extensible existential:

https://try.purescript.org/?gist=d0bff9054bfe49a916365f2b431afa0c

paluh avatar May 31 '20 10:05 paluh