ooni-probe-cli/internal/engine/ooapi/doc.go

164 lines
5.5 KiB
Go
Raw Normal View History

engine/ooapi: autogenerated API with login and caching (#234) * internal/engine/ooapi: auto-generated API client * feat: introduce the callers abstraction * feat: implement API caching on disk * feat: implement cloneWithToken when we require login * feat: implement login * fix: do not cache all APIs * feat: start making space for more tests * feat: implement caching policy * feat: write tests for caching layer * feat: add integration tests and fix some minor issues * feat: write much more unit tests * feat: add some more easy unit tests * feat: add tests that use a local server While there, make sure many fields we care about are OK. * doc: write basic documentation * fix: tweak sentence * doc: improve ooapi documentation * doc(ooapi): other documentation improvements * fix(ooapi): remove caching for most APIs We discussed this topic yesterday with @FedericoCeratto. The only place where we want LRU caching is MeasurementMeta. * feat(ooapi): improve handling of errors during login This was also discussed yesterday with @FedericoCeratto * fix(swaggerdiff_test.go): temporarily disable Before I work on this, I need to tend onto other tasks. * fix(ootest): add one more test case We're going towards 100% coverage of this package, as it ought to be. * feat(ooapi): test cases for when the probe clock is off * fix(ooapi): change test to have 100% unittest coverage * feat: sync server and client APIs definition Companion PR: https://github.com/ooni/api/pull/218 * fix(ooapi): start testing again against API * fix(ooapi): only generate each file once * chore: set version to 3.7.0-alpha While there, make sure we don't always skip a currently failing riseupvpn test, and slightly clarify the readme. * fix(kvstore): less scoped error message
2021-03-04 11:51:07 +01:00
// Package ooapi contains clients for the OONI API. We
// automatically generate the code in this package from
// the apimodel and internal/generator packages. For
// each OONI API, we define up to three data structures:
//
// 1. a data structure representing the API;
//
// 2. a caching data structure, if the API
// supports caching;
//
// 3. an auto-login data structure, if the API
// requires login.
//
// The rest of this documentation page describes these
// three data structures and the design and architecture
// of this package. Refer to subpackages for more
// information on how to specify an API.
//
// API data structure
//
// For each API, this package defines a data structure
// representing the API. For example, for the TorTargets API,
// we define the TorTargetsAPI data structure.
//
// The API data structure defines a method named Call that
// allows calling the specified API. Call takes as arguments
// a context and the request for the API and returns the
// API response or an error.
//
// Request and response messages live inside the apimodel
// subpackage. We name them after the API. Thus, for
// the TorTargets API, the request is TorTargetsRequest,
// and the response is TorTargetsResponse.
//
// API data structures are cheap to create and do not
// mutate. They should be used in place and then forgotten
// off once the API call is complete.
//
// Unless explicitly indicated, the zero value of every
// API data structure is a valid API data structure.
//
// In terms of dependencies, APIs certainly need an http.Client
// to communicate with the OONI backend. To represent such a
// client, we use the HTTPClient interface. If you do not tell
// an API which http.Client to use, we will default to the
// standard library's http.DefaultClient.
//
// An API also depends on a JSONCodec. That is, on a data
// structures that encodes data to/from JSON. If you do not
// specify explicitly a JSONCodec, we will use the Go
// standard library's JSON implementation.
//
// When an API requires authentication, you need to tell
// it which authentication token to use. This gives you
// control over obtaining the token and is the low-level
// way of interacting with authenticated APIs. We recommend
// using the auto-login wrappers instead (see below).
//
// Authenticated APIs also define the WithToken method. This
// method takes as argument a token and returns a copy of the
// original API using the given token. We use this method
// to implement auto-login wrappers.
//
// For each API, we also define two interfaces:
//
// 1. the Caller interface represents the possibility of
// calling a specific API with the correct arguments;
//
// 2. the Cloner interface represents the possibility of
// calling WithToken on the given API.
//
// They abstract the interaction between the API type and
// its caching and auto-login wrappers.
//
// Caching
//
// If an API supports caching, we define a type whose name
// ends in Cache. The TorTargets API cache, for example,
// is TorTargetsCache. These caching types wrap the API type
// and provide the caching functionality.
//
// Because the cache needs to read from and write to the
// disk, a caching type needs a KVStore. A KVStore is
// an interface that allow you to bind a specific key to
// a given blob of bytes and to retrieve such bytes later.
//
// Caches use the gob data format from the Go standard
// library (`encoding/gob`). We abstract this dependency
// using the GobCodec interface. By default, when you
// do not specify a GobCodec we use the implementation
// of gob from the Go standard library.
//
// See the example describing caching for more information
// on how to use caching.
//
// Auto-login
//
// If an API supports auto-login, we define a type whose
// name ends with WithLogin. The TorTargets auto-login struct,
// for example, is called TorTargetsAPIWithLogin.
//
// Auto-login wrappers need to store persistent data. We
// use a KVStore for that (see above). We encode login data
// using JSON. To this end, we use a JSONCodec (also
// described above).
//
// See the example describing auto-login for more information
// on how to use auto-login.
//
// Design
//
// Most of the code in this package is auto-generated from the
// data model in ./apimodel and the definition of APIs provided
// by ./internal/generator/spec.go.
//
// We keep the generated files up-to-date by running
//
// go generate ./...
//
// We have tests that ensure that the definition of the API
// used here is reasonably close to the server's one.
//
// Testing
//
// The following command
//
// go test ./...
//
// will, among other things, ensure that the our API spec
// is consistent with the server's one. Running
//
// go test -short ./...
//
// will exclude most (slow) integration tests.
//
// Architecture
//
// The ./apimodel package contains the definition of request
// and response messages. We rely on tagging to specify how
// we should encode and decode messages.
//
// The ./internal/generator contains code to generate most
// code in this package. In particular, the spec.go file is
// the specification of the APIs.
//
// Notable generated files
//
// - apis.go: contains APIs (e.g., TorTargetsAPI);
//
// - caching.go: contains caching wrappers for every API
// that declares that it needs a cache (e.g., TorTargetsCache);
//
// - callers.go: contains Callers;
//
// - cloners.go: contains the Cloners;
//
// - login.go: contains auto-login wrappers (e.g.,
// TorTargetsAPIWithLogin);
//
// - requests.go: contains code to generate http.Requests.
//
// - responses.go: code to parse http.Responses.
package ooapi