webwire_cli/
lib.rs

1//! # Webwire command-line Interface
2//!
3//! [![Crates.io](https://img.shields.io/crates/v/webwire-cli)](https://crates.io/crates/webwire-cli)
4//! [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/webwire/webwire-cli/Rust)](https://github.com/webwire/webwire-cli/actions)
5//!
6//! [![Discord Chat](https://img.shields.io/discord/726922033039933472?label=Discord+Chat&color=%23677bc4&logo=discord&logoColor=white&style=for-the-badge)](https://discord.gg/jjD6aWG)
7//!
8//! ![webwire logo](https://webwire.dev/logo.svg)
9//!
10//! Webwire is a **contract-first API system** which features an
11//! interface description language a network protocol and
12//! code generator for both servers and clients.
13//!
14//! This repository contains the the **command-line interface** used
15//! to validate Webwire IDL files and generate code and documentation.
16//!
17//! To learn more about webwire in general please visit the documentation
18//! repository [webwire/webwire-docs](https://github.com/webwire/webwire-docs).
19//!
20//! # Example
21//!
22//! The following example assumes a Rust server and a TypeScript client. Webwire
23//! is by no means limited to those two but those languages show the potential of
24//! webwire best.
25//!
26//! Given the following IDL file:
27//!
28//! ```webwire
29//! struct HelloRequest {
30//!     name: String,
31//! }
32//!
33//! struct HelloResponse {
34//!     message: String,
35//! }
36//!
37//! service Hello {
38//!     hello: HelloRequest -> HelloResponse
39//! }
40//! ```
41//!
42//! The server and client files can be generated using the code generator:
43//!
44//! ```bash
45//! $ webwire gen rust < api/chat.ww > server/src/api.rs
46//! $ webwire gen ts < api/chat.ww > client/src/api.ts
47//! ```
48//!
49//! A Rust server implementation for the given code would look like this:
50//!
51//! ```rust,ignore
52//! use std::net::SocketAddr;
53//! use std::sync::{Arc};
54//!
55//! use async_trait::async_trait;
56//!
57//! use ::api::chat;
58//!
59//! use ::webwire::server::hyper::MakeHyperService;
60//! use ::webwire::server::session::{Auth, AuthError};
61//! use ::webwire::{Response, Router, Server, ConsumerError};
62//!
63//! struct ChatService {
64//!     #[allow(dead_code)]
65//!     session: Arc<Session>,
66//!     server: Arc<Server<Session>>,
67//! }
68//!
69//! #[async_trait]
70//! impl chat::Server<Session> for ChatService {
71//!     async fn send(&self, message: &chat::Message) -> Response<Result<(), chat::SendError>> {
72//!         let client = chat::ClientConsumer(&*self.server);
73//!         assert!(matches!(client.on_message(message).await, Err(ConsumerError::Broadcast)));
74//!         Ok(Ok(()))
75//!     }
76//! }
77//!
78//! #[derive(Default)]
79//! struct Session {}
80//!
81//! struct Sessions {}
82//!
83//! impl Sessions {
84//!     pub fn new() -> Self {
85//!         Self {}
86//!     }
87//! }
88//!
89//! #[async_trait]
90//! impl webwire::SessionHandler<Session> for Sessions {
91//!     async fn auth(&self, _auth: Option<Auth>) -> Result<Session, AuthError> {
92//!         Ok(Session::default())
93//!     }
94//!     async fn connect(&self, _session: &Session) {}
95//!     async fn disconnect(&self, _session: &Session) {}
96//! }
97//!
98//! #[tokio::main]
99//! async fn main() {
100//!     // Create session handler
101//!     let session_handler = Sessions::new();
102//!
103//!     // Create service router
104//!     let router = Arc::new(Router::<Session>::new());
105//!
106//!     // Create webwire server
107//!     let server = Arc::new(webwire::server::Server::new(
108//!         session_handler,
109//!         router.clone(),
110//!     ));
111//!
112//!     // Register services
113//!     router.service(chat::ServerProvider({
114//!         let server = server.clone();
115//!         move |session| ChatService {
116//!             session,
117//!             server: server.clone(),
118//!         }
119//!     }));
120//!
121//!     // Start hyper service
122//!     let addr = SocketAddr::from(([0, 0, 0, 0], 2323));
123//!     let make_service = MakeHyperService { server };
124//!     let server = hyper::Server::bind(&addr).serve(make_service);
125//!
126//!     if let Err(e) = server.await {
127//!         eprintln!("server error: {}", e);
128//!     }
129//! }
130//! ```
131//!
132//! A TypeScript client using the generated code would look like that:
133//!
134//! ```typescript
135//! import { Client } from 'webwire'
136//! import api from 'api' // this is the generated code
137//!
138//! let client = new Client('http://localhost:8000/', [
139//!     api.chat.ClientProvider({
140//!         async on_message(message) {
141//!             console.log("Message received:", message)
142//!         }
143//!     })
144//! ])
145//!
146//! assert(await client.connect())
147//!
148//! let chat = api.chat.ServerConsumer(client)
149//! let response = await chat.message({ text: "Hello world!" })
150//!
151//! assert(response.Ok === null)
152//! ```
153//!
154//! ## License
155//!
156//! Licensed under either of
157//!
158//! - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or <http://www.apache.org/licenses/LICENSE-2.0)>
159//! - MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT)>
160//!
161//! at your option.
162pub mod codegen;
163pub mod common;
164pub mod idl;
165pub mod schema;