App

Struct App 

Source
pub struct App<State, Error> { /* private fields */ }
Expand description

A tide-disco server application.

An App is a collection of API modules, plus a global State. Modules can be registered by constructing an Api for each module and calling App::register_module. Once all of the desired modules are registered, the app can be converted into an asynchronous server task using App::serve.

Note that the App is bound to a binary serialization version VER. This format only applies to application-level endpoints like /version and /healthcheck. The binary format version in use by any given API module may differ, depending on the supported version of the API.

Implementations§

Source§

impl<State: Send + Sync + 'static, Error: 'static> App<State, Error>

Source

pub fn with_state(state: State) -> Self

Create a new App with a given state.

Source

pub fn module<'a, ModuleError, ModuleVersion>( &'a mut self, base_url: &'a str, api: impl Into<Value>, ) -> Result<Module<'a, State, Error, ModuleError, ModuleVersion>, AppError>
where Error: Error + From<ModuleError>, ModuleError: Send + Sync + 'static, ModuleVersion: StaticVersionType + 'static,

Create and register an API module.

Creates a new Api with the given api specification and returns an RAII guard for this API. The guard can be used to access the API module, configure it, and populate its handlers. When Module::register is called on the guard (or the guard is dropped), the module will be registered in this App as if by calling register_module.

Source

pub fn register_module<ModuleError, ModuleVersion>( &mut self, base_url: &str, api: Api<State, ModuleError, ModuleVersion>, ) -> Result<&mut Self, AppError>
where Error: Error + From<ModuleError>, ModuleError: Send + Sync + 'static, ModuleVersion: StaticVersionType + 'static,

Register an API module.

The module api will be registered as an implementation of the module hosted under the URL prefix base_url.

§Versioning

Multiple versions of the same Api may be registered by calling this function several times with the same base_url, and passing in different APIs which must have different major versions. The API version can be set using Api::with_version.

When multiple versions of the same API are registered, requests for endpoints directly under the base URL, like GET /base_url/endpoint, will always be dispatched to the latest available version of the API. There will in addition be an extension of base_url for each major version registered, so GET /base_url/v1/endpoint will always dispatch to the endpoint handler in the module with major version 1, if it exists, regardless of what the latest version is.

It is an error to register multiple versions of the same module with the same major version. It is not an error to register non-sequential versions of a module. For example, you could have /base_url/v2 and /base_url/v4, but not v1 or v3. Requests for v1 or v3 will simply fail.

The intention of this functionality is to allow for non-disruptive breaking updates. Rather than deploying a new major version of the API with breaking changes in place of the old version, breaking all your clients, you can continue to serve the old version for some period of time under a version prefix. Clients can point at this version prefix until they update their software to use the new version, on their own time.

Note that non-breaking changes (e.g. new endpoints) can be deployed in place of an existing API without even incrementing the major version. The need for serving two versions of an API simultaneously only arises when you have breaking changes.

Source

pub fn with_version(&mut self, version: Version) -> &mut Self

Set the application version.

The version information will automatically be included in responses to GET /version.

This is the version of the overall application, which may encompass several APIs, each with their own version. Changes to the version of any of the APIs which make up this application should imply a change to the application version, but the application version may also change without changing any of the API versions.

This version is optional, as the /version endpoint will automatically include the version of each registered API, which is usually enough to uniquely identify the application. Set this explicitly if you want to track the version of additional behavior or interfaces which are not encompassed by the sub-modules of this application.

If you set an application version, it is a good idea to use the version of the application crate found in Cargo.toml. This can be automatically found at build time using the environment variable CARGO_PKG_VERSION and the env! macro. As long as the following code is contained in the application crate, it should result in a reasonable version:

app.with_version(env!("CARGO_PKG_VERSION").parse().unwrap());
Source

pub fn version(&self) -> AppVersion

Get the version of this application.

Source

pub async fn health(&self, req: RequestParams, state: &State) -> AppHealth

Check the health of each registered module in response to a request.

The response includes a status code for each module, which will be StatusCode::OK if the module is healthy. Detailed health status from each module is not included in the response (due to type erasure) but can be queried using module_health or by hitting the endpoint GET /:module/healthcheck.

Source

pub async fn module_health( &self, req: RequestParams, state: &State, module: &str, major_version: Option<u64>, ) -> Option<Response>

Check the health of the named module.

The resulting Response has a status code which is StatusCode::OK if the module is healthy. The response body is constructed from the results of the module’s registered healthcheck handler. If the module does not have an explicit healthcheck handler, the response will be a HealthStatus.

major_version can be used to query the health status of a specific version of the desired module. If it is not provided, the most recent supported version will be queried.

If there is no module with the given name or version, returns None.

Source§

impl<State, Error> App<State, Error>
where State: Send + Sync + 'static, Error: 'static + Error,

Source

pub async fn serve<L, VER>(self, listener: L, bind_version: VER) -> Result<()>
where L: ToListener<Arc<Self>>, VER: StaticVersionType + 'static,

Serve the App asynchronously.

VER controls the binary format version used for responses to top-level endpoints like /version and /healthcheck. All endpoints for specific API modules will use the format version of that module (ModuleVersion when the module was registered).

Trait Implementations§

Source§

impl<State: Debug, Error: Debug> Debug for App<State, Error>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<State, Error> Freeze for App<State, Error>

§

impl<State, Error> !RefUnwindSafe for App<State, Error>

§

impl<State, Error> Send for App<State, Error>
where State: Sync + Send,

§

impl<State, Error> Sync for App<State, Error>
where State: Sync + Send,

§

impl<State, Error> Unpin for App<State, Error>

§

impl<State, Error> !UnwindSafe for App<State, Error>

Blanket Implementations§

§

impl<T> Any for T
where T: 'static + ?Sized,

§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<T> Borrow<T> for T
where T: ?Sized,

§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
§

impl<T> BorrowMut<T> for T
where T: ?Sized,

§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> From<T> for T

§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
§

impl<T, U> Into<U> for T
where U: From<T>,

§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more