unisonweb / unison

A friendly programming language from the future
https://unison-lang.org
Other
5.75k stars 269 forks source link

WIP: HTTP client builtins #1692

Closed pchiusano closed 2 years ago

pchiusano commented 4 years ago

DRAFT, in progress, a mess right now.

Working on API for HTTP, HTTPs clients.


unique type Http.Method 
  = GET | HEAD | POST | PUT | DELETE | CONNECT | OPTIONS | TRACE | PATCH

unique type Http.Request g
  = { method : Method
    , headers : [(Text,Text)] 
    , url : Text
    , body : Body g
    , timeout : Duration
    }

-- allow streaming requests / responses - the streams have access to `g`
-- so you can do things like streaming upload of a file
unique type Body g = { mimeType : MimeType, bytes : '{g, Stream Bytes} () }

unique type MimeType = MimeType Text
unique type Http.StatusCode = StatusCode Nat

unique type Http.Status
  = { code : Http.StatusCode, message : Text }

unique type Http.Version 
  = { major : Nat, minor : Nat }

unique type Http.Response g
  = { status : Http.Status
    , version : Http.Version
    , headers : [(Text,Text)]
    , body : Body g
    }

-- this should just do the right thing when url is http vs https
Http.send : Http.Request g ->{g, Http.Client} Http.Response (Body {Http.Client})

-- the Http.Client handler is in charge of config for things like TLS, etc
Http.client.run.handler : Request {Http.Client,g} a ->{IO,g} a
Http.client.run : '{g, Http.Client} a ->{g,IO} a

Questions:

/cc @stew

aryairani commented 4 years ago

Awesome!

Some thoughts off the top of my head:

/cc @rossabaker — I know it will look different in Unison than in Scala, but any thoughts? :)

pchiusano commented 4 years ago

I think @stew has more thoughts on this too, we just discussed offline. But quick summary is will likely just have a builtin TLS implementation (binding to Haskell tls library) and a pure unison http library that uses the tls library plus tcp sockets.

stew commented 4 years ago

Here are some of my thoughts:

pchiusano commented 4 years ago

Okay, great, so sounds like we're leaning toward: HTTP(S) client library is pure Unison, rather than builtin, but it uses TCP sockets (already in IO) and a to be written builtin TLS implementation (see #1693) for the HTTPS part. We just focus on HTTP 1.1 for now since HTTP2 is like 50x more work and isn't needed right away. I'd guess an HTTP2 client could still be pure Unison though and maybe someone will be interested in taking that on as a library effort.

I think it is good to make things pure Unison (rather than builtins) when they reasonably can be... agree that reimplementing TLS feels crazy.

@stew will confirm that http 1.1 client could just be reasonably pure Unison given a TLS implementation and builtins for TCP sockets and threading which already exist. Main question is: is https literally just http over a tls-based TCP connection? If that's all it is, then "should be nbd."

aryairani commented 4 years ago

If this "cat" is to be believed, then:

HTTPS is just the HTTP protocol but with data encryption using SSL/TLS.

but I'm hesitant to trust anything without a torso.

rossabaker commented 4 years ago

So, http4s has constants for every method in the IANA registry as well as support for custom methods. It's good to be permissive as a client, because someone will eventually need to call some arrogantly verbed API. The specs slowly add new ones, so modeling it as a sum type now means breaking changes later.

But this is Unison, so those changes in due time will be graceful, and what you have now will work almost everywhere.

pchiusano commented 4 years ago

Cool, thanks @rossabaker. In that case I might just do:

unique type Http.Method = Method Text

-- and then just have some named constants to prevent spelling errors
Http.Method.GET = Method "GET"
Http.Method.POST = Method "POST"
rossabaker commented 4 years ago

If you want to be a standards pedant, there are strings that aren't valid HTTP methods, and you might consider Text -> Optional Method smart constructor.

method = token
token = 1*tchar
tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
    "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA

In Haskell, I've been experimenting with pattern synonyms for things that are intuitively sum types today, but need an escape hatch for futureproofing or other weird shit. I don't know whether Unison has anything of the sort, but it's a satisfying idiom that I'd apply to http4s' Method if we had it in Scala: https://github.com/brendanhay/amazonka/pull/597

These are exotic cases, and your simple model above should work well in practice.

ceedubs commented 2 years ago

There is always room for improvement, but I think that we can say mission accomplished on this one! https://share.unison-lang.org/@stew/code/latest/namespaces/public/projects/httpclient/latest