textmachine/platform/internal/httpapi/capabilities.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.7.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)
}