1
2
Fork
You've already forked soafe
0
A SOAP client generator for Rust (forked from https://github.com/netwo-io/savon)
Rust 96.4%
Nix 3.6%
2025年05月06日 12:24:16 +02:00
.helix add development stuff 2025年05月06日 11:40:23 +02:00
assets add assets 2020年04月24日 18:08:49 +02:00
soafe-test chore: rename savon to soafe 2025年05月06日 12:24:16 +02:00
src chore: rename savon to soafe 2025年05月06日 12:24:16 +02:00
.envrc add development stuff 2025年05月06日 11:40:23 +02:00
.gitignore add development stuff 2025年05月06日 11:40:23 +02:00
Cargo.toml chore: rename savon to soafe 2025年05月06日 12:24:16 +02:00
flake.lock add development stuff 2025年05月06日 11:40:23 +02:00
flake.nix add development stuff 2025年05月06日 11:40:23 +02:00
README.md chore: rename savon to soafe 2025年05月06日 12:24:16 +02:00

soafe, a SOAP client generator for Rust

This project is a fork of https://github.com/netwo-io/savon

soafe generates code from a WSDL file, that you can then include in your project. It will generate serialization and deserialization code, along with an async HTTP client API (based on reqwest).

Usage

in Cargo.toml:

[dependencies]
soafe = "0.2"

in build.rs:

fn main(){letout_dir=env::var("OUT_DIR").unwrap();lets=soafe::generate::gen_write("./assets/example.wsdl",&out_dir).unwrap();}

Finally, in your code:

mod soap{include!(concat!(env!("OUT_DIR"),"/example.rs"));}

You can then use it as follows:

letclient=soap::StockQuoteService::new("http://example.com".to_string());letres=client.get_last_trade_price(soap::GetLastTradePriceInput(TradePriceRequest{ticker_symbol: "SOAP".to_string()})).await?;

Under the hood

If you use the following WSDL file as input:

<?xml version="1.0"?>
<definitions name="StockQuote"
 targetNamespace="http://example.com/stockquote.wsdl"
 xmlns:tns="http://example.com/stockquote.wsdl"
 xmlns:xsd1="http://example.com/stockquote.xsd"
 xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
 xmlns="http://schemas.xmlsoap.org/wsdl/">
 <types>
 <schema targetNamespace="http://example.com/stockquote.xsd"
 xmlns="http://www.w3.org/2000/10/XMLSchema">
 <element name="TradePriceRequest">
 <complexType>
 <all>
 <element name="tickerSymbol" type="string"/>
 </all>
 </complexType>
 </element>
 <element name="TradePrice">
 <complexType>
 <all>
 <element name="price" type="float"/>
 </all>
 </complexType>
 </element>
 </schema>
 </types>
 <message name="GetLastTradePriceInput">
 <part name="body" element="xsd1:TradePriceRequest"/>
 </message>
 <message name="GetLastTradePriceOutput">
 <part name="body" element="xsd1:TradePrice"/>
 </message>
 <portType name="StockQuotePortType">
 <operation name="GetLastTradePrice">
 <input message="tns:GetLastTradePriceInput"/>
 <output message="tns:GetLastTradePriceOutput"/>
 </operation>
 </portType>
 <binding name="StockQuoteSoapBinding" type="tns:StockQuotePortType">
 <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
 <operation name="GetLastTradePrice">
 <soap:operation soapAction="http://example.com/GetLastTradePrice"/>
 <input>
 <soap:body use="literal"/>
 </input>
 <output>
 <soap:body use="literal"/>
 </output>
 </operation>
 </binding>
 <service name="StockQuoteService">
 <documentation>My first service</documentation>
 <port name="StockQuotePort" binding="tns:StockQuoteSoapBinding">
 <soap:address location="http://example.com/stockquote"/>
 </port>
 </service>
</definitions>

It will generate this code:

usesoafe::internal::xmltree;usesoafe::rpser::xml::*;#[derive(Clone, Debug, Default)]pubstruct TradePriceRequest{pubticker_symbol: String,}implsoafe::generate::ToElementsforTradePriceRequest{fn to_elements(&self)-> Vec<xmltree::Element>{vec![vec![xmltree::Element::node("tickerSymbol").with_text(self.ticker_symbol.to_string())]].drain(..).flatten().collect()}}implsoafe::generate::FromElementforTradePriceRequest{fn from_element(element: &xmltree::Element)-> Result<Self,soafe::Error>{Ok(TradePriceRequest{ticker_symbol: element.get_at_path(&["tickerSymbol"]).and_then(|e|{e.get_text().map(|s|s.to_string()).ok_or(soafe::rpser::xml::Error::Empty)})?,})}}#[derive(Clone, Debug, Default)]pubstruct TradePrice{pubprice: f64,}implsoafe::generate::ToElementsforTradePrice{fn to_elements(&self)-> Vec<xmltree::Element>{vec![vec![xmltree::Element::node("price").with_text(self.price.to_string())]].drain(..).flatten().collect()}}implsoafe::generate::FromElementforTradePrice{fn from_element(element: &xmltree::Element)-> Result<Self,soafe::Error>{Ok(TradePrice{price: element.get_at_path(&["price"]).map_err(soafe::Error::from).and_then(|e|{e.get_text().ok_or(soafe::rpser::xml::Error::Empty).map_err(soafe::Error::from).and_then(|s|s.parse().map_err(soafe::Error::from))})?,})}}pubstruct StockQuoteService{pubbase_url: String,pubclient: soafe::internal::reqwest::Client,}pubmod messages{usesuper::*;#[derive(Clone, Debug, Default)]pubstruct GetLastTradePriceOutput(pubTradePrice);implsoafe::generate::ToElementsforGetLastTradePriceOutput{fn to_elements(&self)-> Vec<xmltree::Element>{self.0.to_elements()}}implsoafe::generate::FromElementforGetLastTradePriceOutput{fn from_element(element: &xmltree::Element)-> Result<Self,soafe::Error>{TradePrice::from_element(element).map(GetLastTradePriceOutput)}}#[derive(Clone, Debug, Default)]pubstruct GetLastTradePriceInput(pubTradePriceRequest);implsoafe::generate::ToElementsforGetLastTradePriceInput{fn to_elements(&self)-> Vec<xmltree::Element>{self.0.to_elements()}}implsoafe::generate::FromElementforGetLastTradePriceInput{fn from_element(element: &xmltree::Element)-> Result<Self,soafe::Error>{TradePriceRequest::from_element(element).map(GetLastTradePriceInput)}}}#[allow(dead_code)]implStockQuoteService{pubfn new(base_url: String)-> Self{Self::with_client(base_url,soafe::internal::reqwest::Client::new())}pubfn with_client(base_url: String,client: soafe::internal::reqwest::Client)-> Self{StockQuoteService{base_url,client}}pubasyncfn get_last_trade_price(&self,get_last_trade_price_input: messages::GetLastTradePriceInput,)-> Result<Result<messages::GetLastTradePriceOutput,()>,soafe::Error>{soafe::http::request_response(&self.client,&self.base_url,"http://example.com/stockquote.wsdl","GetLastTradePrice",&get_last_trade_price_input,).await}}