Generating all URLs through the Resource and URL modules

Hi devs,

I’d like us to generate every XWiki URL (pages, attachments, skins, webjars, tmp, users, exports…) through the Resource and URL modules, with the same per-format rules that already parse incoming URLs. XWikiURLFactory and its subclasses would become thin adapters over it, and could later be deprecated.

The full design is at https://design.xwiki.org/xwiki/bin/view/Proposal/URLSerialization

Why

  • Parsing goes through the URL format, but generating doesn’t: there’s no serializer for pages and attachments, and the url normalizer still returns null (XWIKI-17023).
  • The server URL logic exists twice in oldcore with different fallbacks, and XWIKI-24569 / PR #5855 would add a third copy behind a new URLFactory role.
  • Serializers disagree on what they return: some add the context path, authentication doesn’t (its callers do), and user-resource returns an absolute URL from the old factory.
  • url.standard.hideViewAction, documented since 7.2M1, has no effect, because generation never reads StandardURLConfiguration. This proposal fixes it.

Proposal in short

URL generation becomes the exact inverse of parsing, in three stages:

  1. Resource (resource-api): what is addressed.
  2. URL format (url-scheme-*): how a reference is written in a path. Each (format, type) pair has a serializer and a resolver, tested for the round trip. The format returns the path from the webapp root, without the context path, plus the target wiki.
  3. Location (url-default, independent of the container): context path, server URL of the target wiki, and the three outputs (relative, absolute for the current request, canonical), through the contextpath, url and new canonicalurl normalizers.

Callers don’t get a new role. They pick the kind of URL by picking the lookup:

  • ResourceReferenceSerializer<ResourceReference, ExtendedURL>: relative, with the context path (exists);
  • ResourceReferenceSerializer<ResourceReference, URL>: absolute, for the current request (new);
  • ResourceReferenceSerializer<ResourceReference, URL> with hint canonical: absolute, using only the configuration (new). Reset password and emails use it.

Other notable points:

  • Move EntityResourceReference, EntityResourceAction, SkinsResourceReference and ResourcesResourceReference from resource-default to resource-api, so url-api stops depending on an implementation module.
  • Rename url-container to url-servlet, since its code is servlet-specific, and keep servlet code out of url-default behind one internal role.
  • One server URL resolver in url-default, replacing the two copies in oldcore. PR #5855 would be closed in favor of this.
  • Serializers that follow the new contract (no context path) get a distinct hint (<format>/path). Existing extension serializers keep working unchanged. The old registrations of the platform serializers move to legacy, as was done for standard/tmp in 14.7.

What could go wrong

  • Code that calls the default serializer and then the contextpath normalizer for the authentication type would get the context path twice. Platform callers change in the same commit; extensions doing this need a release-notes entry.
  • Wikis that set url.standard.hideViewAction=true would start getting URLs without /view/ (that’s the bug fix).
  • Webjars and tmp URLs containing a space would use %20 instead of +.

Questions

The design page lists 9 open questions. The ones I’d most like opinions on:

  • Q5: stop reading the undocumented per-wiki showviewaction / usedefaultaction preferences (keeping the xwiki.cfg keys as fallbacks)?
  • Q7: canonical / canonicalurl as the hint names?
  • Q8: keep “relative if same host” in the oldcore adapter for now?
  • Q9: a distinct hint for new-contract serializers, rather than detecting old ones heuristically?

WDYT?

Thanks

PS: This post was co-written with Claude Code.

That feels like a severe API breakage that seems hard to justify and would need a separate vote, not just a simple release note entry unless you’re saying that there are no such extensions?

Are they used? Have they been mentioned on the forum, on xwiki.org, did you ask XWiki SAS if they used it for client projects? I find this hard to answer without knowing how undocumented/unused they actually are.

What are the trade-offs here?

No idea, could you elaborate more what the consequences are?

Again no idea what new-contract serializers are.

I of course find the idea interesting for consistency.
I won’t develop on all the backward compatibility challenges raised by Michael.
What I’d like to mention is if we want to add client-side (i.e., JavaScript) URLs generation as part of the scope?