PEP691: Switch to a List for Project, Address more Feedback (#2653)
This commit is contained in:
parent
1cba25dc56
commit
da131037fd
180
pep-0691.rst
180
pep-0691.rst
|
@ -35,7 +35,7 @@ There are two major issues with an HTML-based API:
|
|||
fully support HTML5.
|
||||
|
||||
- HTML5 is primarily designed as a markup language to present documents for human
|
||||
consumption. Our use of it is driven largely for historical reasons and accidental
|
||||
consumption. Our use of it is driven largely for historical and accidental
|
||||
reasons, and it's unlikely anyone would design an API that relied on it if
|
||||
they were starting from scratch.
|
||||
|
||||
|
@ -178,10 +178,9 @@ Project List
|
|||
~~~~~~~~~~~~
|
||||
|
||||
The root URL ``/`` for this PEP (which represents the base URL) will be a JSON encoded
|
||||
dictionary which has a single key, ``projects``, which is itself a dictionary where each
|
||||
key is a string of the normalized project name, and the value is a dictionary with a
|
||||
single key, ``url``, which represents the URL that the project can be fetched from. As
|
||||
an example:
|
||||
dictionary which has a single key, ``projects``, which is an array where each entry
|
||||
is a dictionary with a single key, ``name``, which represents string of the project
|
||||
name. As an example:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -189,13 +188,31 @@ an example:
|
|||
"meta": {
|
||||
"api-version": "1.0"
|
||||
},
|
||||
"projects": {
|
||||
"frob": {"url": "/frob/"},
|
||||
"spamspamspam": {"url": "/spamspamspam/"}
|
||||
}
|
||||
"projects": [
|
||||
{"name": "Frob"},
|
||||
{"name": "spamspamspam"},
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
The ``name`` field is the same as the one from :pep:`503`, which does not specify
|
||||
whether it is the non-normalized display name or the normalized name. In practice
|
||||
different implementations of these PEPs are choosing differently here, so relying
|
||||
on it being either non-normalized or normalized is relying on an implementation
|
||||
detail of the repository in question.
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
While the ``projects`` key is an array, and thus is required to be in some kind
|
||||
of an order, neither :pep:`503` nor this PEP requires any specific ordering nor
|
||||
that the ordering is consistent from one request to the next. Mentally this is
|
||||
best thought of as a set, but both JSON and HTML lack the functionality to have
|
||||
sets.
|
||||
|
||||
|
||||
Project Detail
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -286,6 +303,15 @@ As an example:
|
|||
}
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
While the ``files`` key is an array, and thus is required to be in some kind
|
||||
of an order, neither :pep:`503` nor this PEP requires any specific ordering nor
|
||||
that the ordering is consistent from one request to the next. Mentally this is
|
||||
best thought of as a set, but both JSON and HTML lack the functionality to have
|
||||
sets.
|
||||
|
||||
|
||||
Content-Types
|
||||
-------------
|
||||
|
||||
|
@ -336,10 +362,11 @@ negotiation, the flow is roughly:
|
|||
1. The client makes an HTTP request containing an ``Accept`` header listing all
|
||||
of the version+format content types that they are able to understand.
|
||||
2. The server inspects that header, selects one of the listed content types,
|
||||
then returns a response using that content type.
|
||||
then returns a response using that content type (treating the absence of
|
||||
an ``Accept`` header as ``Accept: */*``).
|
||||
3. If the server does not support any of the content types in the ``Accept``
|
||||
header or if the client did not provide an ``Accept`` header at all, then
|
||||
they are able to choose between 3 different options for how to respond:
|
||||
header then they are able to choose between 3 different options for how to
|
||||
respond:
|
||||
|
||||
a. Select a default content type other than what the client has requested
|
||||
and return a response with that.
|
||||
|
@ -828,6 +855,41 @@ with each other. Overall I think it's more confusing if the ``+html`` version do
|
|||
exist.
|
||||
|
||||
|
||||
Why v1.0 and not v1.1 or v2.0?
|
||||
------------------------------
|
||||
|
||||
This PEP is still wholly backwards compatible with clients that could read the
|
||||
existing v1.0 API, can still continue to read the API after these changes have
|
||||
been made. In :pep:`629`, the qualification for a major version bump is:
|
||||
|
||||
Incrementing the major version is used to signal a backwards incompatible
|
||||
change such that existing clients would no longer be expected to be able to
|
||||
meaningfully use the API.
|
||||
|
||||
The changes in this PEP do not meet that bar, nothing has changed in a way that
|
||||
existing clients would no longer be expected to be able to meaningfully use the
|
||||
API.
|
||||
|
||||
That means we should still be within the v1.x version line.
|
||||
|
||||
The question of whether we should be v1.1 or v1.0 is a more interesting one, and
|
||||
there are a few ways of looking at it:
|
||||
|
||||
- We've exposed new features to the API (the project name on the project
|
||||
page, multiple hashes), which is a sign that we should increment the minor
|
||||
version.
|
||||
- The new features exist wholly within the JSON serialization, which means that
|
||||
no client that currently is requesting the HTML 1.0 page, would ever see any
|
||||
of the new features anyways, so for them it is effectively still v1.0.
|
||||
- No major client has implemented support for PEP 629 yet, which means that the
|
||||
minor version numbering is largely academic at this point anyways, since it
|
||||
exists to let clients provide feedback to end users.
|
||||
|
||||
The second and third points above end up making the first point kind of
|
||||
meaningless, and with that, it makes more sense to just call everything v1.0
|
||||
and be stricter about updating versions into the future.
|
||||
|
||||
|
||||
Appendix 1: Survey of use cases to cover
|
||||
========================================
|
||||
|
||||
|
@ -881,6 +943,100 @@ how they use the Simple + JSON APIs today or how they currently plan to use it:
|
|||
- XML-RPC Call: ``list_packages_with_serial``
|
||||
|
||||
|
||||
Appendix 2: Rough Underlying Data Models
|
||||
========================================
|
||||
|
||||
These are not intended to perfectly match the server, client, or wire
|
||||
formats. Rather, these are concpetual models, put to code to make them
|
||||
more explicit as to the abstract models underlining the repository API
|
||||
as it evolved through :pep:`503`, :pep:`529`, :pep:`629`, :pep:`658`,
|
||||
and now this PEP, :pep:`691`.
|
||||
|
||||
The existing HTML, and the new JSON serialization of these models then
|
||||
represent how these underlying concpetual models get mapped onto the
|
||||
actual wire formats.
|
||||
|
||||
How servers or clients choose to model this data is out of scope for
|
||||
this PEP.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@dataclass
|
||||
class Meta:
|
||||
api_version: Literal["1.0"]
|
||||
|
||||
|
||||
@dataclass
|
||||
class Project:
|
||||
# Normalized or Non-Normalized Name
|
||||
name: str
|
||||
# Computed in JSON, Included in HTML
|
||||
url: str | None
|
||||
|
||||
|
||||
@dataclass
|
||||
class File:
|
||||
filename: str
|
||||
url: str
|
||||
# Limited to a len() of 1 in HTML
|
||||
hashes: dict[str, str]
|
||||
gpg_sig: bool | None
|
||||
requires_python: str | None
|
||||
|
||||
|
||||
@dataclass
|
||||
class PEP529File(File):
|
||||
yanked: bool | str
|
||||
|
||||
|
||||
# Simple Index page (/simple/)
|
||||
@dataclass
|
||||
class PEP503_Index:
|
||||
projects: set[Project]
|
||||
|
||||
|
||||
@dataclass
|
||||
class PEP629_Index(PEP503_Index):
|
||||
meta: Meta
|
||||
|
||||
|
||||
@dataclass
|
||||
class Index(PEP629_Index):
|
||||
pass
|
||||
|
||||
|
||||
# Simple Detail page (/simple/$PROJECT/)
|
||||
@dataclass
|
||||
class PEP503_Detail:
|
||||
files: set[File]
|
||||
|
||||
|
||||
@dataclass
|
||||
class PEP529_Detail(PEP503_Detail):
|
||||
files: set[PEP529File]
|
||||
|
||||
|
||||
@dataclass
|
||||
class PEP629_Detail(PEP529_Detail):
|
||||
meta: Meta
|
||||
|
||||
|
||||
@dataclass
|
||||
class PEP658_Detail(PEP629_Detail):
|
||||
# Limited to a len() of 1 in HTML
|
||||
dist_info_metadata: bool | dict[str, str]
|
||||
|
||||
|
||||
@dataclass
|
||||
class PEP691_Detail(PEP658_Detail):
|
||||
name: str # Normalized Name
|
||||
|
||||
|
||||
@dataclass
|
||||
class Detail(PEP691_Detail):
|
||||
pass
|
||||
|
||||
|
||||
Copyright
|
||||
=========
|
||||
|
||||
|
|
Loading…
Reference in New Issue