This isn’t exactly true TBH, but it’s not not true either 
It roughly depends on what capabilities your static server has.
S3 lets you set a custom content type to whatever you want, but it has no support for content negotiation. So you can easily make an index that is either HTML or the new JSON type, but you can’t make a single endpoint that does both transparently. You can however make two endpoints if you want, a JSON and a HTML one, and then use client configuration to select between them. You could also slap a cloudfront distribution in front of S3 and use a lambda@edge task to handle content negotiation.
Github pages only has a set number of content types that it understands. text/html being one of them, but the custom content types not. You’d not be able to support the new JSON api on Github pages unless they added support for it. That being said, we could add application/json
as an alias for application/vnd.pypi.simple+json
(the non versioned content type) and then you could also host it on Github Pages with the same caveats as S3 (a single endpoint can ONLY be html OR json).
Apache has built in support for this, so can fully support it with just a static directory + configuration.
Other servers will vary, but at a minimum they can support multiple URLs.
It’s probably worthwhile to spell it out in the PEP, but since a repository isn’t required to support both JSON and HTML at the same URL and can make either the default, there’s no reason why a particular repository has to restrict themselves to a single endpoint. They can simply rely on configuration and having users pick either the JSON or the HTML endpoint depending on the capabilities of their client. Content Negotiation degrades gracefully here.
TUF requires distinctly named targets, they’re not URLs, they’re string keys of “files”, but it’s application specific what those string keys actually refer to. The PEP mentions this, but we can just have two different targets in TUF, one for HTML and one for JSON, and just have the target key include the content type. It doesn’t have to match the actual URL being requested If I remember correctly the TUF stuff already diverges the target key from the URL because I think instead of /simple/requests/
it does /simple/requests.html
.
I had a comment on one of the earlier drafts that didn’t (yet) bubble into the PEP.
Content Negotiation is a standard HTTP feature, and when it can’t find an acceptable content type to serve (either because the client asked for none, or because it asked for only ones the server didn’t understand) it allows servers to either error (with a HTTP 406) or to serve a default content type.
I think the PEP should generally leave it up to the individual repository to decide what to do when content negotiation fails. Personally I’m a fan of having no Accept
header fail, because that scenario is primarily going to be automated clients and that will encourage them to add an appropriate Accept
header. If we let the repository pick though, we’re more flexible and can possibly cover more edge cases.
Browsers do send an Accept
header. Most websites are using content negotiation without people ever noticing
.
Edge browser’s default Accept
header looks like this:
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Which roughly translates to:
I prefer HTML, then I prefer XHTML, then I prefer XML, then I prefer some image types, then I prefer absolutely anything.
Most modern browsers will have a similar default accept header.
So that would mean that as long as a repository supported text/html
, browsers would get that (well technically the individual repository implementation gets to pick what it serves, since content negotiation is the client asking nicely, and then the server picking). If that repository no longer supported text/html
, it would get a JSON response.
JSON normally isn’t pretty printed by default, but most browsers have a light weight addon you can install to get it. For instance, I use JSON Lite on Edge.
We should expand upon that for sure. Roughly speaking the justification is because it removes the requirement to coordinate between client and server or to have end users care about whether an URL is JSON or HTML.
Like take pip for instance, of course pip can manage it’s own default pretty easily. That’s not a problem.
However, let’s say I have a private repository and it supports JSON. How do I tell pip about this?
Well if I just do --index-url https://example.com/my-json-repo/
, pip has no way to know if that is JSON or HTML, so it’s going to have to assume it’s HTML. So pip would have to do something like --json-index-url https://example.com/my-json-repo/
.
Now you could say “can’t pip just request the url regardless, and dispatch off of whatever the returned Content-Type is?”, and yes, you definitely can. Which is basically exactly what Content Negotiation is 
In fact, pip already is using content negotiation, when it makes a HTTP request it passes an Accept: text/html
header, so if you wanted to do “dispatch based on the returned content type, but have separate URLs for JSON vs HTML”, pip would have to update it’s Accept
header to list both the HTML and the JSON content type.
There is no plan to have PyPI drop support for HTML responses. The PEP already states:
Similar to clients, it is expected that most repositories will continue to support HTML responses for a long time, or forever. It should be possible for a repository to choose to only support the new formats.
Which is primarily intended to give random private repositories the right to not bother implementing HTML responses if they don’t want to, but the PEP expects that most repositories are not going to drop support for HTML anytime soon, maybe never.
We don’t have a reasonable way to require people to make a migration plan. Like we can certainly put some words in a PEP to say that, but we have no recourse to force them to do so. I prefer to give people the tools they need to handle it, and assume that they’ll make reasonable choices for their situation. For PyPI we wouldn’t drop text/html
support without a PEP.