energy_api/lib.rs
1#![deny(unsafe_code)]
2#![deny(missing_docs)]
3//! # energy-api
4//!
5//! Rust client and server bindings for the German energy market API-Webdienste
6//! (MaKo — Marktkommunikation).
7//!
8//! ## Module layout
9//!
10//! ```text
11//! energy_api
12//! ├── models/ OpenAPI/AsyncAPI types shared by all APIs
13//! ├── transport/ HTTP + mTLS builder, JWS sign/verify
14//! ├── directory/ Verzeichnisdienst — REST client, WebSocket client, server
15//! ├── client/ Electricity API clients (feature = "client")
16//! │ ├── control_measures NB/LF and MSB send calls
17//! │ └── malo_ident LF and NB callback calls
18//! └── server/ Electricity API servers (feature = "server")
19//! ├── control_measures MSB and NB/LF receive handlers + axum router
20//! ├── malo_ident NB and LF receive handlers + axum router
21//! └── wim_order MSB receive handler (iMS Anmeldung) + NB callbacks
22//! ```
23//!
24//! ## Feature flags
25//!
26//! | Feature | Enables |
27//! |-------------|----------------------------------------------------------|
28//! | `client` | HTTP clients for all APIs (reqwest + rustls) |
29//! | `server` | Axum router factories for server implementations |
30//! | `websocket` | WebSocket subscription client (tokio-tungstenite) |
31//! | `crypto` | JWS ECDSA-SHA256 sign/verify for directory records (p256)|
32//!
33//! ## Quick start
34//!
35//! ### Look up an endpoint via the directory
36//!
37//! ```no_run
38//! # #[cfg(feature = "client")]
39//! # async fn example() -> Result<(), energy_api::Error> {
40//! use energy_api::directory::DirectoryServiceClient;
41//! use url::Url;
42//!
43//! let base = Url::parse("https://verzeichnisdienst.example.de/")?;
44//! let client = DirectoryServiceClient::new_insecure(base)?;
45//! let (record, _cert, _sig) = client
46//! .get_record("1234567890723", "controlMeasuresV1", 1)
47//! .await?;
48//! println!("{}", record.url);
49//! # Ok(())
50//! # }
51//! ```
52//!
53//! ### Send a grid control command
54//!
55//! ```no_run
56//! # #[cfg(feature = "client")]
57//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
58//! use energy_api::client::ControlMeasuresClient;
59//! use energy_api::models::electricity::{
60//! CommandControl, LocationId, NeloId, MaximumPowerValue,
61//! };
62//! use url::Url;
63//! use uuid::Uuid;
64//!
65//! let client = ControlMeasuresClient::new(
66//! Url::parse("https://msb.example.de/")?,
67//! reqwest::Client::new(),
68//! );
69//! client.send_konfiguration(
70//! Uuid::new_v4(),
71//! "2025-06-01T10:00:00.000Z",
72//! // `NeloId::new` validates the ASCII-Verfahren check digit.
73//! &LocationId::NetworkLocation(NeloId::new("E1234848431")?),
74//! &CommandControl {
75//! maximum_power_value: MaximumPowerValue("10.5".into()),
76//! execution_time_from: "2025-06-01T10:00:00Z".into(),
77//! execution_time_until: None,
78//! },
79//! None,
80//! ).await?;
81//! # Ok(())
82//! # }
83//! ```
84
85#![allow(clippy::too_many_arguments)]
86#![allow(clippy::large_enum_variant)]
87
88pub mod directory;
89pub mod error;
90pub mod models;
91pub mod spec_version;
92pub mod transport;
93
94#[cfg(feature = "client")]
95pub mod client;
96
97#[cfg(feature = "server")]
98pub mod server;
99
100pub use error::Error;