118 lines
6.3 KiB
Go
118 lines
6.3 KiB
Go
package httpapi
|
|
|
|
import "net/http"
|
|
|
|
// ContractVersion is the version of the ratified contract this build serves
|
|
// (`docs/architecture/14-api-contract/openapi.yaml`, `info.version`).
|
|
//
|
|
// It is a CONSTANT and it is the only place a non-streaming client learns which contract it is
|
|
// talking to. While the major is `0` a differing MINOR carries breaking changes by design, so a
|
|
// client generated against another one refuses to work and says so — which is why this must be
|
|
// raised in the same commit as the code that implements a new minor, and never as a courtesy
|
|
// afterwards.
|
|
// ⚠ 0.11.0 was the ORDER FORM's minor (D39.196, unified backlog row 279) and it lived for HOURS.
|
|
// 0.12.0 is the same form's correction: `Run.ordered_chapters` became nullable and `ordered_units`
|
|
// arrived beside it, because the chapter figure a character order used to publish was the SPAN it
|
|
// reached into and overstated what was bought by up to a whole chapter — worst on the cheapest order
|
|
// there is. That changes the wire this build serves, so the number moves with it, in this same
|
|
// change and not as a courtesy afterwards.
|
|
//
|
|
// ⚠ Why a bump and not an amendment inside 0.11.0, decided rather than assumed: 0.11.0's canon text
|
|
// was edited three times after its landing, and none of those was a change of FORM — an open
|
|
// vocabulary growing by one value, a defect note, and an ERRATUM correcting what the document said
|
|
// about members the wire already served. Prose and errata do not move a number; a served shape does.
|
|
// And 0.11.0 already has its acceptance act (D39.208), which closes it. See the pack's report.
|
|
//
|
|
// ⚠ THE GATE IS RED BETWEEN THE TWO LANDINGS, and which side is ahead says which of the two orders
|
|
// is being followed. The ratified one is CODE FIRST: this constant is raised with the change that
|
|
// implements the minor, the gate goes red because the canon still reads the EARLIER version, and the
|
|
// canon's own landing clears it. The reverse — canon first, code behind, the gate red because the
|
|
// canon reads a LATER minor — is refused deliberately, because in that window the wire announces a
|
|
// version it does not serve: errata 04.09-в is the day that cost a working day, and 0.13.0 is the day
|
|
// it happened again and stood for a full day, until the next session of this zone read its battery.
|
|
//
|
|
// ⛔ AND WHAT THE GATE CANNOT SEE, said here because this constant is where a reader comes looking: it
|
|
// compares VERSIONS, not SHAPES. Three separate untruths in the 0.11.0 text passed it in one day —
|
|
// the bar described in chapters while the wire sent units, `ordered_chapters: 0` promised where the
|
|
// wire sent 2, three values of a vocabulary that had four — because the NUMBER matched each time. The
|
|
// bump keeps the number from lying; it does not close the blind spot, which is unified backlog row 309.
|
|
//
|
|
// ⚠ 0.13.1 is the canon's CORRECTING minor (D39.235 §6) and this constant did not follow it for a day:
|
|
// the canon moved first and the gate stood red the whole time, which is the reverse of the order the
|
|
// paragraph above ratifies. The number is brought to the canon here rather than the other way round,
|
|
// because the canon is the one that is right — the wire this build serves is the 0.13.1 shape.
|
|
const ContractVersion = "0.13.1"
|
|
|
|
// Capabilities is what this deployment can do: one flat document, the same for every account.
|
|
type Capabilities struct {
|
|
// Pairs is what this deployment can translate, and what it merely knows about. Unavailable ones
|
|
// are LISTED rather than omitted: "absent" and "listed as unavailable" are different facts to a
|
|
// user waiting for one.
|
|
Pairs []LanguagePair
|
|
// IntakeEnabled is whether this deployment takes books at all. False is a read-only instance,
|
|
// and without the field a client discovers that only by spending a user's upload.
|
|
IntakeEnabled bool
|
|
IntakeMaxBytes int64
|
|
// ExportFormats is what `POST /books/{bookId}/exports` accepts. Empty means none are built here,
|
|
// which is the honest answer while the export path is not built (deferred to P8).
|
|
ExportFormats []string
|
|
// BankCorrectionsEnabled is whether this deployment serves the correction door,
|
|
// `POST /books/{bookId}/bank/corrections`. False means the path answers 404 and a client does
|
|
// not offer the correction UI — machine-readable so nobody learns it by failing a user's save
|
|
// (canon §Capabilities; the same fact that decides the route's mount).
|
|
BankCorrectionsEnabled bool
|
|
// PageSizeDefault is how many rows a collection returns when `limit` is omitted. It is the
|
|
// DEPLOYMENT's number rather than a constant of the contract, and every read path takes its
|
|
// default from the same place this answers from.
|
|
PageSizeDefault int
|
|
}
|
|
|
|
// LanguagePair is one direction, as the wire carries it.
|
|
type LanguagePair struct {
|
|
Source string
|
|
Target string
|
|
Available bool
|
|
}
|
|
|
|
type wireCapabilities struct {
|
|
ContractVersion string `json:"contract_version"`
|
|
LanguagePairs []wireLanguagePair `json:"language_pairs"`
|
|
IntakeEnabled bool `json:"intake_enabled"`
|
|
IntakeMaxBytes int64 `json:"intake_max_bytes"`
|
|
ExportFormats []string `json:"export_formats"`
|
|
BankCorrectionsEnabled bool `json:"bank_corrections_enabled"`
|
|
PageSizeDefault int `json:"page_size_default"`
|
|
}
|
|
|
|
type wireLanguagePair struct {
|
|
Source string `json:"source"`
|
|
Target string `json:"target"`
|
|
State string `json:"state"`
|
|
}
|
|
|
|
func (h *v0) capabilities(w http.ResponseWriter, r *http.Request) {
|
|
if _, ok := principal(w, r); !ok {
|
|
return
|
|
}
|
|
out := wireCapabilities{
|
|
ContractVersion: ContractVersion,
|
|
LanguagePairs: make([]wireLanguagePair, 0, len(h.caps.Pairs)),
|
|
IntakeEnabled: h.caps.IntakeEnabled,
|
|
IntakeMaxBytes: h.caps.IntakeMaxBytes,
|
|
ExportFormats: h.caps.ExportFormats,
|
|
BankCorrectionsEnabled: h.caps.BankCorrectionsEnabled,
|
|
PageSizeDefault: h.caps.PageSizeDefault,
|
|
}
|
|
if out.ExportFormats == nil {
|
|
out.ExportFormats = []string{} // an empty collection is an empty array, never null
|
|
}
|
|
for _, p := range h.caps.Pairs {
|
|
state := "unavailable"
|
|
if p.Available {
|
|
state = "available"
|
|
}
|
|
out.LanguagePairs = append(out.LanguagePairs,
|
|
wireLanguagePair{Source: p.Source, Target: p.Target, State: state})
|
|
}
|
|
h.writeJSON(w, r, http.StatusOK, out)
|
|
}
|