whatwg · GitHub

It's mentioned that the api is heavily inspired by the path-to-regexp library.

That library also supports transforming the parameters back into a path, thus providing two way transformations.

I didn't see this support mentioned in this proposal. I think it would be great to add that. Any issues with doing that?

It would help to know more about the use cases for reverse compiling. Can you describe more about when and why you would do this?

Perhaps this is related to the URI templates usage mentioned by @jasnell here?

https://twitter.com/jasnell/status/1339743882448236544

While matching URLs has use cases in the native web platform (like service worker scopes), I'm not familiar with a similar use case for generating URLs from a template and parameters. So I just want to understand more about the use cases for web developers.

Thanks!

2 replies

@wanderview

I guess I can see how you might want to generate URLs to link to on a page based on variables like user or product id. But what advantages does a pattern based compile offer over using js template strings?
For example, https://example.com/user/${id}.

@dyoder

Client code doesn't need to know the structure of the URL. This preserves the opacity of URLs, decoupling client code from the URL structure.

Good question -- I should have laid out the use cases.

As I see it, the url parser takes something a bit unwieldly -- a long string -- and turns it into something that is much easier to work with -- a JavaScript Object-like structure, via result.pathname.groups. That object structure, or a full object clone, might be passed throughout the application. TypeScript typing might be constructed around that simple, flat object, etc.

In other parts of the application, we might want to build hyperlinks dynamically, based on mutations made to the (cloned object). Yes, we could use template literals for that, but now we are "repeating ourselves" as far as the names and order of the parameters, and seems like a translation that is quite prone to human error. Should we decide we need to revisit how the url's are constructed, it would be difficult to find all the places that need to be adjusted to conform to the new url pattern. In short, we are lacking DRY.

My mental analogy is JSON parsing vs stringifying, being used to serialize and then deserialize to an object. Having a consistence parser / stringifier in a two way fashion is a boon for working with objects.

I see this function as doing a small subset of what JSON can do (and with a totally different string structure). While the "object" structure of what you can get out of a URL is much more limited, I think the benefits of an "inverse function" still apply.

3 replies

@wanderview

Thanks for the explanation. Looking at the implementation in path-to-regexp, compile() also seems to do data validation to ensure the new url matches the pattern.

If you have any concrete examples of compile() usage, particularly in the browser, that might help. @blakeembrey do you know?

From my perspective it would not be hard to add compile() to liburlpattern. We would have to consider what kind of API shape would make sense for URLPattern.

I think a big hurdle here would be possible competition with URI templates. Are they more commonly used or better? Of course, having to implement a second parser for URI templates would be higher cost. We already have a parsed format in URLPattern.

Anyway good stuff to consider in January. Thanks!

@blakeembrey

I'm not too sure where it's used for examples, but the use case is basically as @bahrus outlined. The ability to define a route once for accepting input (URLs) and routing to (<a />, redirects, etc) - you don't need to define a thing twice. It's possible to do it with template string in JavaScript too, but you'd want a template string function to correctly serialize the strings (e.g. you mostly want to encodeURIComponent for each parameter automatically to avoid serialization issues). The other downside with JS template strings is portability - it's a small feature to be able to define routes in plain text.

Adding compile() based on the pattern support should be simple - path-to-regexp implementation is pretty short (even with the regexp validation built in). One caveat with the implementation of this is the * feature - if it means .* in regexp, it becomes unclear how to reverse it properly because an input of a/b/c would be URI encoded incorrectly when going back to a string. It's a big reason for the removal of the wildcard in recent releases of path-to-regexp.

Even with that caveat though, I realized a simple workaround the other day when we messaged about adding * back to path-to-regexp - we can have a wrapper object for "safe strings" (inspiration in handlebars) that are already encoded so they aren't double encoded. Getting into the weeds here, so let me know if that doesn't make any sense.

@blakeembrey

A trivial personal project example is something like https://github.com/blakeembrey/react-route#usepathcompile, where you can re-use the same strings to route from and to in a React.js application. There's no real users of the project except me, but the idea is the same in other frameworks.

But what advantages does a pattern based compile offer over using js template strings? For example, https://example.com/user/${id}.

One thing is encoding of contextually reserved characters, e.g. "/", "?", "#" and segment-leading "." in some portion which is meant to be a single path segment. A tagged template can take care of that, though I think few people realize it's necessary if there's a chance of encountering values that are directly or indirectly from user input. Anecdotally at least, I've found bugs caused by this at two jobs. This isn't nec. specific to generative URL patterns, but they help since most url pattern systems provide enough info to ensure a generated URL "round trips" (i.e. you should not be able to generate a URL that doesn't also match the pattern that generated it.)

edit: I see @blakeembrey already mentioned this. (This is my first time seeing subthreads on Github, threw me off a bit!)

0 replies

I think this is something I want to pursue in the future, but not yet. I feel like I have enough work getting matching specified and launched. I'd like to tackle generating URLs later in a v2.

0 replies

The application router abstract-state-router uses compile functionality.

Developers are not required to pass in every parameter to navigate to a new screen – they can navigate from /company/1234/employee/69/purchases to ``/company/1234/employee/420/home` by calling

abstractStateRouter.go('company.employee.home', { employeeId: 420 })

without specifying the company id (since that is redundant in the context the company state or any of its child states).

0 replies

I'd like to see the ability to generate URLs from templates as well. FWIW, we implemented URL template destructuring based on a subset of RFC 6570.

The advantage of this client code doesn't need to know the structure of the URL. This preserves the opacity of URLs, decoupling client code from the URL structure. Another advantage is that we handle URL encoding as a part of this.

Throughout our applications, we don't "hardcode" the URLs, even in links. We generate them programmatically based on the routes, similar to the approach described by @TehShrike. The routes are named, so they can be referenced logically. For example, in a blogging application, we might generate a link to the blog editor like so:

router.link({ name: "edit blog", parameters: key: "my-first-blog", nickname: "dan" })

In fact, we even do this for API resources.

One of the advantages of using a subset of URL Templates (6570) is that you get this for free.

(This is sort of a compilation of a discussion that started in ticket #58.)

0 replies

Note, I've filed enhancement issue #73 to consider this for the future.

0 replies

Read the original on github.com ↗