87 lines
3.7 KiB
Go
87 lines
3.7 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.
|
|
const ContractVersion = "0.9.0"
|
|
|
|
// 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)
|
|
}
|