stdlib icon indicating copy to clipboard operation
stdlib copied to clipboard

Add a `new()` primitive to the `uri` package.

Open vxern opened this issue 1 year ago • 5 comments

Inspired by the request.new() and response.new() functions from the gleam_http package, and while working with Uris, I thought that it would also be a good idea to be able to do the same with Uri.

Provisionally, the implementation of the function would look as follows:

pub fn new() -> Uri {
  Uri(
    scheme: None,
    userinfo: None,
    host: None,
    port: None,
    path: "",
    query: None,
    fragment: None,
  )
}

This would create a completely bare Uri object that the developer could then go ahead and build on top of. I have created a related issue here that would implement 'builder' primitives to set fields on the Uri object. Coupled, these primitives would create a really nice pattern for building out a Uri, but even without those 'setter' primitives being present yet, the developer could still utilise this implementation of new() as follows:

let uri = Uri(..uri.new(), scheme: "http", host: "localhost")

This primitive would make cases like the following taken from uri_test.gleam more concise:

uri.Uri(Some("ftp"), None, None, None, "", None, None)
|> uri.to_string
|> should.equal("ftp:")

allowing them to be switched out for:

uri.Uri(..uri.new(), scheme: Some("ftp"))
|> uri.to_string
|> should.equal("ftp:")

and coupled with the 'setter' primitive proposal mentioned earlier (here), if that proposal were to be implemented:

uri.new()
|> uri.set_scheme("ftp")
|> uri.to_string
|> should.equal("ftp:")

If okay'd, I'd be happy to go ahead and implement this myself.

vxern avatar May 31 '24 21:05 vxern

If I'm reading the URI syntax description correctly, it seems that at a minimum scheme and path are required in order to have a minimally valid URI. If that is indeed correct, then I would think that new might arguably be a bit better implemented as follows, as I don't imagine it would make sense to not specify a scheme:

pub fn new(scheme: String) -> Uri {
  Uri(
    scheme: Option(scheme),
    userinfo: None,
    host: None,
    port: None,
    path: "",
    query: None,
    fragment: None,
  )
}

Your examples might then become slightly simpler. For example:

uri.new("ftp")
|> uri.to_string
|> should.equal("ftp:")

Arguably, defaulting path to an empty string likely doesn't make sense either since that's equivalent to no path at all, which, again, seems to be invalid, but URI validation is a big can of worms to deal with, so perhaps better left for a separate discussion.

chuckwondo avatar Jul 22 '24 13:07 chuckwondo

That sounds sensible to me!

That said, given we're unlikely to get the builder API is there still a use case for this function?

lpil avatar Jul 25 '24 12:07 lpil

That sounds sensible to me!

That said, given we're unlikely to get the builder API is there still a use case for this function?

Probably not.

chuckwondo avatar Jul 25 '24 16:07 chuckwondo

Even if we do not have builders, would it not be valuable to still have a function (or perhaps even a constant Uri.empty) that would eliminate the boilerplate needed to create a complete Uri?

Referring back to this usage:

let uri = Uri(..uri.new(), scheme: "http", host: "localhost")

vxern avatar Jul 25 '24 17:07 vxern

OK, sounds good.

lpil avatar Jul 26 '24 10:07 lpil

So, the issue can be closed because of #798, I suppose?

abs0luty avatar Oct 26 '25 19:10 abs0luty

Thank you

lpil avatar Oct 26 '25 23:10 lpil