Documentation ¶
Overview ¶
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.
Index ¶
- Variables
- type CheckInAPI
- type CheckInCaller
- type CheckReportIDAPI
- type CheckReportIDCaller
- type GobCodec
- type HTTPClient
- type JSONCodec
- type KVStore
- type LoginAPI
- type LoginCaller
- type MeasurementMetaAPI
- type MeasurementMetaCache
- type MeasurementMetaCaller
- type OpenReportAPI
- type OpenReportCaller
- type PsiphonConfigAPI
- type PsiphonConfigAPIWithLogin
- type PsiphonConfigCaller
- type PsiphonConfigCloner
- type RegisterAPI
- type RegisterCaller
- type RequestMaker
- type SubmitMeasurementAPI
- type SubmitMeasurementCaller
- type TemplateExecutor
- type TestHelpersAPI
- type TestHelpersCaller
- type TorTargetsAPI
- type TorTargetsAPIWithLogin
- type TorTargetsCaller
- type TorTargetsCloner
- type URLsAPI
- type URLsCaller
Constants ¶
This section is empty.
Variables ¶
var ( ErrEmptyField = errors.New("apiclient: empty field") ErrHTTPFailure = errors.New("apiclient: http request failed") ErrJSONLiteralNull = errors.New("apiclient: server returned us a literal null") ErrMissingToken = errors.New("apiclient: missing auth token") )
Errors defined by this package. In addition to these errors, this package may of course return any other stdlib specific error.
Functions ¶
This section is empty.
Types ¶
type CheckInAPI ¶
type CheckInAPI struct { BaseURL string // optional HTTPClient HTTPClient // optional JSONCodec JSONCodec // optional RequestMaker RequestMaker // optional UserAgent string // optional }
CheckInAPI implements the CheckIn API.
func (*CheckInAPI) Call ¶
func (api *CheckInAPI) Call(ctx context.Context, req *apimodel.CheckInRequest) (*apimodel.CheckInResponse, error)
Call calls the CheckIn API.
type CheckInCaller ¶
type CheckInCaller interface {
Call(ctx context.Context, req *apimodel.CheckInRequest) (*apimodel.CheckInResponse, error)
}
CheckInCaller represents any type exposing a method like CheckInAPI.Call.
type CheckReportIDAPI ¶
type CheckReportIDAPI struct { BaseURL string // optional HTTPClient HTTPClient // optional JSONCodec JSONCodec // optional RequestMaker RequestMaker // optional UserAgent string // optional }
CheckReportIDAPI implements the CheckReportID API.
func (*CheckReportIDAPI) Call ¶
func (api *CheckReportIDAPI) Call(ctx context.Context, req *apimodel.CheckReportIDRequest) (*apimodel.CheckReportIDResponse, error)
Call calls the CheckReportID API.
type CheckReportIDCaller ¶
type CheckReportIDCaller interface {
Call(ctx context.Context, req *apimodel.CheckReportIDRequest) (*apimodel.CheckReportIDResponse, error)
}
CheckReportIDCaller represents any type exposing a method like CheckReportIDAPI.Call.
type GobCodec ¶
type GobCodec interface { // Encode encodes v as a serialized gob byte slice. Encode(v interface{}) ([]byte, error) // Decode decodes the serialized gob byte slice into v. Decode(b []byte, v interface{}) error }
GobCodec is a Gob encoder and decoder.
type HTTPClient ¶
type HTTPClient interface { // Do should work like http.Client.Do. Do(req *http.Request) (*http.Response, error) }
HTTPClient is the interface of a generic HTTP client.
type JSONCodec ¶
type JSONCodec interface { // Encode encodes v as a serialized JSON byte slice. Encode(v interface{}) ([]byte, error) // Decode decodes the serialized JSON byte slice into v. Decode(b []byte, v interface{}) error }
JSONCodec is a JSON encoder and decoder.
type KVStore ¶
type KVStore interface { // Get gets a value from the key-value store. Get(key string) ([]byte, error) // Set stores a value into the key-value store. Set(key string, value []byte) error }
KVStore is a key-value store.
type LoginAPI ¶
type LoginAPI struct { BaseURL string // optional HTTPClient HTTPClient // optional JSONCodec JSONCodec // optional RequestMaker RequestMaker // optional UserAgent string // optional }
LoginAPI implements the Login API.
func (*LoginAPI) Call ¶
func (api *LoginAPI) Call(ctx context.Context, req *apimodel.LoginRequest) (*apimodel.LoginResponse, error)
Call calls the Login API.
type LoginCaller ¶
type LoginCaller interface {
Call(ctx context.Context, req *apimodel.LoginRequest) (*apimodel.LoginResponse, error)
}
LoginCaller represents any type exposing a method like LoginAPI.Call.
type MeasurementMetaAPI ¶
type MeasurementMetaAPI struct { BaseURL string // optional HTTPClient HTTPClient // optional JSONCodec JSONCodec // optional RequestMaker RequestMaker // optional UserAgent string // optional }
MeasurementMetaAPI implements the MeasurementMeta API.
func (*MeasurementMetaAPI) Call ¶
func (api *MeasurementMetaAPI) Call(ctx context.Context, req *apimodel.MeasurementMetaRequest) (*apimodel.MeasurementMetaResponse, error)
Call calls the MeasurementMeta API.
type MeasurementMetaCache ¶
type MeasurementMetaCache struct { API MeasurementMetaCaller // mandatory GobCodec GobCodec // optional KVStore KVStore // mandatory }
MeasurementMetaCache implements caching for MeasurementMetaAPI.
func (*MeasurementMetaCache) Call ¶
func (c *MeasurementMetaCache) Call(ctx context.Context, req *apimodel.MeasurementMetaRequest) (*apimodel.MeasurementMetaResponse, error)
Call calls the API and implements caching.
type MeasurementMetaCaller ¶
type MeasurementMetaCaller interface {
Call(ctx context.Context, req *apimodel.MeasurementMetaRequest) (*apimodel.MeasurementMetaResponse, error)
}
MeasurementMetaCaller represents any type exposing a method like MeasurementMetaAPI.Call.
type OpenReportAPI ¶
type OpenReportAPI struct { BaseURL string // optional HTTPClient HTTPClient // optional JSONCodec JSONCodec // optional RequestMaker RequestMaker // optional UserAgent string // optional }
OpenReportAPI implements the OpenReport API.
func (*OpenReportAPI) Call ¶
func (api *OpenReportAPI) Call(ctx context.Context, req *apimodel.OpenReportRequest) (*apimodel.OpenReportResponse, error)
Call calls the OpenReport API.
type OpenReportCaller ¶
type OpenReportCaller interface {
Call(ctx context.Context, req *apimodel.OpenReportRequest) (*apimodel.OpenReportResponse, error)
}
OpenReportCaller represents any type exposing a method like OpenReportAPI.Call.
type PsiphonConfigAPI ¶
type PsiphonConfigAPI struct { BaseURL string // optional HTTPClient HTTPClient // optional JSONCodec JSONCodec // optional Token string // mandatory RequestMaker RequestMaker // optional UserAgent string // optional }
PsiphonConfigAPI implements the PsiphonConfig API.
func (*PsiphonConfigAPI) Call ¶
func (api *PsiphonConfigAPI) Call(ctx context.Context, req *apimodel.PsiphonConfigRequest) (apimodel.PsiphonConfigResponse, error)
Call calls the PsiphonConfig API.
func (*PsiphonConfigAPI) WithToken ¶
func (api *PsiphonConfigAPI) WithToken(token string) PsiphonConfigCaller
WithToken returns a copy of the API where the value of the Token field is replaced with token.
type PsiphonConfigAPIWithLogin ¶
type PsiphonConfigAPIWithLogin struct { API PsiphonConfigCloner // mandatory JSONCodec JSONCodec // optional KVStore KVStore // mandatory RegisterAPI RegisterCaller // mandatory LoginAPI LoginCaller // mandatory }
PsiphonConfigAPIWithLogin implements login for PsiphonConfigAPI.
func (*PsiphonConfigAPIWithLogin) Call ¶
func (api *PsiphonConfigAPIWithLogin) Call(ctx context.Context, req *apimodel.PsiphonConfigRequest) (apimodel.PsiphonConfigResponse, error)
Call logins, if needed, then calls the API.
type PsiphonConfigCaller ¶
type PsiphonConfigCaller interface {
Call(ctx context.Context, req *apimodel.PsiphonConfigRequest) (apimodel.PsiphonConfigResponse, error)
}
PsiphonConfigCaller represents any type exposing a method like PsiphonConfigAPI.Call.
type PsiphonConfigCloner ¶
type PsiphonConfigCloner interface {
WithToken(token string) PsiphonConfigCaller
}
PsiphonConfigCaller represents any type exposing a method like PsiphonConfigAPI.WithToken.
type RegisterAPI ¶
type RegisterAPI struct { BaseURL string // optional HTTPClient HTTPClient // optional JSONCodec JSONCodec // optional RequestMaker RequestMaker // optional UserAgent string // optional }
RegisterAPI implements the Register API.
func (*RegisterAPI) Call ¶
func (api *RegisterAPI) Call(ctx context.Context, req *apimodel.RegisterRequest) (*apimodel.RegisterResponse, error)
Call calls the Register API.
type RegisterCaller ¶
type RegisterCaller interface {
Call(ctx context.Context, req *apimodel.RegisterRequest) (*apimodel.RegisterResponse, error)
}
RegisterCaller represents any type exposing a method like RegisterAPI.Call.
type RequestMaker ¶
type RequestMaker interface { // NewRequest creates a new HTTP request. NewRequest(ctx context.Context, method, URL string, body io.Reader) (*http.Request, error) }
RequestMaker makes an HTTP request.
type SubmitMeasurementAPI ¶
type SubmitMeasurementAPI struct { BaseURL string // optional HTTPClient HTTPClient // optional JSONCodec JSONCodec // optional RequestMaker RequestMaker // optional TemplateExecutor TemplateExecutor // optional UserAgent string // optional }
SubmitMeasurementAPI implements the SubmitMeasurement API.
func (*SubmitMeasurementAPI) Call ¶
func (api *SubmitMeasurementAPI) Call(ctx context.Context, req *apimodel.SubmitMeasurementRequest) (*apimodel.SubmitMeasurementResponse, error)
Call calls the SubmitMeasurement API.
type SubmitMeasurementCaller ¶
type SubmitMeasurementCaller interface {
Call(ctx context.Context, req *apimodel.SubmitMeasurementRequest) (*apimodel.SubmitMeasurementResponse, error)
}
SubmitMeasurementCaller represents any type exposing a method like SubmitMeasurementAPI.Call.
type TemplateExecutor ¶
type TemplateExecutor interface { // Execute takes in input a template string and some piece of data. It // returns either a string where template parameters have been replaced, // on success, or an error, on failure. Execute(tmpl string, v interface{}) (string, error) }
TemplateExecutor parses and executes a text template.
type TestHelpersAPI ¶
type TestHelpersAPI struct { BaseURL string // optional HTTPClient HTTPClient // optional JSONCodec JSONCodec // optional RequestMaker RequestMaker // optional UserAgent string // optional }
TestHelpersAPI implements the TestHelpers API.
func (*TestHelpersAPI) Call ¶
func (api *TestHelpersAPI) Call(ctx context.Context, req *apimodel.TestHelpersRequest) (apimodel.TestHelpersResponse, error)
Call calls the TestHelpers API.
type TestHelpersCaller ¶
type TestHelpersCaller interface {
Call(ctx context.Context, req *apimodel.TestHelpersRequest) (apimodel.TestHelpersResponse, error)
}
TestHelpersCaller represents any type exposing a method like TestHelpersAPI.Call.
type TorTargetsAPI ¶
type TorTargetsAPI struct { BaseURL string // optional HTTPClient HTTPClient // optional JSONCodec JSONCodec // optional Token string // mandatory RequestMaker RequestMaker // optional UserAgent string // optional }
TorTargetsAPI implements the TorTargets API.
func (*TorTargetsAPI) Call ¶
func (api *TorTargetsAPI) Call(ctx context.Context, req *apimodel.TorTargetsRequest) (apimodel.TorTargetsResponse, error)
Call calls the TorTargets API.
func (*TorTargetsAPI) WithToken ¶
func (api *TorTargetsAPI) WithToken(token string) TorTargetsCaller
WithToken returns a copy of the API where the value of the Token field is replaced with token.
type TorTargetsAPIWithLogin ¶
type TorTargetsAPIWithLogin struct { API TorTargetsCloner // mandatory JSONCodec JSONCodec // optional KVStore KVStore // mandatory RegisterAPI RegisterCaller // mandatory LoginAPI LoginCaller // mandatory }
TorTargetsAPIWithLogin implements login for TorTargetsAPI.
func (*TorTargetsAPIWithLogin) Call ¶
func (api *TorTargetsAPIWithLogin) Call(ctx context.Context, req *apimodel.TorTargetsRequest) (apimodel.TorTargetsResponse, error)
Call logins, if needed, then calls the API.
type TorTargetsCaller ¶
type TorTargetsCaller interface {
Call(ctx context.Context, req *apimodel.TorTargetsRequest) (apimodel.TorTargetsResponse, error)
}
TorTargetsCaller represents any type exposing a method like TorTargetsAPI.Call.
type TorTargetsCloner ¶
type TorTargetsCloner interface {
WithToken(token string) TorTargetsCaller
}
TorTargetsCaller represents any type exposing a method like TorTargetsAPI.WithToken.
type URLsAPI ¶
type URLsAPI struct { BaseURL string // optional HTTPClient HTTPClient // optional JSONCodec JSONCodec // optional RequestMaker RequestMaker // optional UserAgent string // optional }
URLsAPI implements the URLs API.
func (*URLsAPI) Call ¶
func (api *URLsAPI) Call(ctx context.Context, req *apimodel.URLsRequest) (*apimodel.URLsResponse, error)
Call calls the URLs API.
type URLsCaller ¶
type URLsCaller interface {
Call(ctx context.Context, req *apimodel.URLsRequest) (*apimodel.URLsResponse, error)
}
URLsCaller represents any type exposing a method like URLsAPI.Call.
Source Files ¶
Directories ¶
Path | Synopsis |
---|---|
Package apimodel describes the data types used by OONI's API.
|
Package apimodel describes the data types used by OONI's API. |
internal
|
|
generator
Command generator generates code in the ooapi package.
|
Command generator generates code in the ooapi package. |
openapi
Package openapi contains data structures for Swagger v2.0.
|
Package openapi contains data structures for Swagger v2.0. |