-
Notifications
You must be signed in to change notification settings - Fork 6k
[New Generator] Rust API client generator #6092
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| /target/ | ||
| **/*.rs.bk | ||
| Cargo.lock |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| [package] | ||
| name = "petstore-client" | ||
| version = "0.1.0" | ||
| authors = ["Vladimir Pouzanov <farcaller@gmail.com>"] | ||
|
|
||
| [dependencies] | ||
| serde = "*" | ||
| serde_derive = "*" | ||
| serde_yaml = "*" | ||
| serde_json = "*" | ||
| base64 = "*" | ||
| futures = "*" | ||
| hyper = "*" | ||
| url = "*" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would you mind annotating which dependency version is the codegen targeting?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yep, as soon as I figure those myself :-) so far the generated code doesn't compile |
||
|
|
||
| [dev-dependencies] | ||
| tokio-core = "*" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| extern crate petstore_client; | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. a sample file, not to be part of generated api |
||
| extern crate hyper; | ||
| extern crate tokio_core; | ||
| extern crate futures; | ||
|
|
||
| use hyper::Client; | ||
| use hyper::client::HttpConnector; | ||
| use tokio_core::reactor::Core; | ||
| use futures::{Future}; | ||
|
|
||
| fn main() { | ||
| let mut core = Core::new().expect("failed to init core"); | ||
| let handle = core.handle(); | ||
|
|
||
| let http_connector = HttpConnector::new(4, &handle); | ||
|
|
||
| let client = Client::configure().connector(http_connector).build(&handle); | ||
| let api = "http://petstore.swagger.io:80/v2"; | ||
|
|
||
| let new_pet = petstore_client::models::Pet::new("barker".to_owned(), vec![]).with_id(1337); | ||
|
|
||
| let apicli = petstore_client::apis::client::APIClient::new( | ||
| petstore_client::apis::configuration::Configuration::new( | ||
| Client::configure().connector(HttpConnector::new(4, &handle)).build(&handle))); | ||
|
|
||
| let work = apicli.pet_api().add_pet(&new_pet) | ||
| // petstore_client::apis::add_pet(api, &client, &new_pet) | ||
| .and_then(|_| { | ||
| petstore_client::apis::update_pet_with_form( | ||
| api, | ||
| &client, | ||
| 1337, | ||
| "barko", | ||
| "escaped") | ||
| }) | ||
| .and_then(|_| { | ||
| petstore_client::apis::get_pet_by_id( | ||
| api, | ||
| &client, | ||
| 1337) | ||
| }) | ||
| .and_then(|pet| { | ||
| println!("pet: {:?}", pet); | ||
| futures::future::ok(()) | ||
| }); | ||
|
|
||
| core.run(work).expect("failed to run core"); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| use hyper; | ||
| use serde_json; | ||
| use futures::{Future, Stream}; | ||
| use futures; | ||
|
|
||
| use super::models; | ||
| use super::Error; | ||
|
|
||
| pub fn add_pet<C: hyper::client::Connect>( | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. rust naming guidelines dictate |
||
| prefix: &str, | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure about what's the common pattern for api use, really. This sample client will require two things: a http (or https) prefix as a string and the hyper.rs Client (the web client) plus any arguments. |
||
| cli: &hyper::client::Client<C>, | ||
| pet: &models::Pet, | ||
| ) -> Box<Future<Item = (), Error = Error>> { | ||
| let mut req = hyper::Request::new( | ||
| hyper::Method::Post, | ||
| format!("{}/pet", prefix).parse().unwrap()); | ||
| let serialized = serde_json::to_string(pet).unwrap(); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no error handling for brevity of the example. |
||
| req.headers_mut().set(hyper::header::ContentType::json()); | ||
| req.headers_mut().set(hyper::header::ContentLength(serialized.len() as u64)); | ||
| req.set_body(serialized); | ||
|
|
||
| Box::new( | ||
| cli.request(req).and_then(|res| { res.body().concat2() }) | ||
| .map_err(|e| Error::from(e)) | ||
| .and_then(|_| futures::future::ok(())) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the api doesn't dictate the return value so nothing is returned even though the sample server returns a pet instance. npm server choked up on |
||
| ) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| use std::rc::Rc; | ||
|
|
||
| use hyper; | ||
| use super::configuration::Configuration; | ||
| use super::pet_api; | ||
|
|
||
| pub struct APIClient<C: hyper::client::Connect> { | ||
| configuration: Rc<Configuration<C>>, | ||
|
|
||
| pet_api: Box<pet_api::PetAPI>, | ||
| } | ||
|
|
||
| impl<C: hyper::client::Connect> APIClient<C> { | ||
| pub fn new(configuration: Configuration<C>) -> APIClient<C> { | ||
| let rc = Rc::new(configuration); | ||
|
|
||
| APIClient { | ||
| configuration: rc.clone(), | ||
| pet_api: Box::new(pet_api::PetAPIImpl::new(rc.clone())), | ||
| } | ||
| } | ||
|
|
||
| pub fn pet_api(&self) -> &pet_api::PetAPI { | ||
| self.pet_api.as_ref() | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| use hyper; | ||
|
|
||
| pub struct Configuration<C: hyper::client::Connect> { | ||
| pub base_path: String, | ||
| pub client: hyper::client::Client<C>, | ||
| } | ||
|
|
||
| impl<C: hyper::client::Connect> Configuration<C> { | ||
| pub fn new(client: hyper::client::Client<C>) -> Configuration<C> { | ||
| Configuration { | ||
| base_path: "http://petstore.swagger.io:80/v2".to_owned(), | ||
| client: client, | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| use hyper; | ||
| use serde_json; | ||
| use futures::{Future, Stream}; | ||
|
|
||
| use super::models; | ||
| use super::Error; | ||
|
|
||
| pub fn get_pet_by_id<C: hyper::client::Connect>( | ||
| prefix: &str, | ||
| cli: &hyper::client::Client<C>, | ||
| pet_id: i64, | ||
| ) -> Box<Future<Item = models::Pet, Error = Error>> { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (Here and in other generated methods)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ack.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For other generators (e.g. PHP, Ruby), there's a corresponding "WithHttpInfo" method (e.g. getPetByIdWithHttpInfo) to return a list with the response (if any), HTTP status code and HTTP headers. Not sure if Rust supports returning a list. If not, we will need to create an ApiResponse object with response, status and headers as properties. For Rust, we can follow similar approach by creating a corresponding
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we can return response object along with the parsed body. Let's focus on making the current implementation compileable and then we can improve.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's also worth sharing other API clients usually come with a corresponding "Async" method (e.g. addPetAsync) for async function call. Not sure how that should be done in Rust but worth thinking ahead with this future requirement.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All this code is async-only. I don't think that it makes sense to have a matching sync version.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah ok. Good to know. One less thing to consider then. |
||
| Box::new( | ||
| cli.get(format!("{}/pet/{}", prefix, pet_id).parse().unwrap()) | ||
|
|
||
| .and_then(|res| { res.body().concat2() }).map_err(|e| Error::from(e)) | ||
|
|
||
| .and_then(|body| { | ||
| let parsed: Result<models::Pet, _> = serde_json::from_slice(&body); | ||
| parsed.map_err(|e| Error::from(e)) | ||
| }).map_err(|e| Error::from(e)) | ||
| ) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| use hyper; | ||
| use serde_json; | ||
|
|
||
| #[derive(Debug)] | ||
| pub enum Error { | ||
| Hyper(hyper::Error), | ||
| Serde(serde_json::Error), | ||
| } | ||
|
|
||
| impl From<hyper::Error> for Error { | ||
| fn from(e: hyper::Error) -> Self { | ||
| return Error::Hyper(e) | ||
| } | ||
| } | ||
|
|
||
| impl From<serde_json::Error> for Error { | ||
| fn from(e: serde_json::Error) -> Self { | ||
| return Error::Serde(e) | ||
| } | ||
| } | ||
|
|
||
| use super::models; | ||
|
|
||
| mod get_pet_by_id_api; | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. there's a single namespace, so modules (and files) would have to be named differently from the actual functions. |
||
| pub use self::get_pet_by_id_api::get_pet_by_id; | ||
|
|
||
| mod update_pet_with_form_api; | ||
| pub use self::update_pet_with_form_api::update_pet_with_form; | ||
|
|
||
| mod add_pet_api; | ||
| pub use self::add_pet_api::add_pet; | ||
|
|
||
| pub mod configuration; | ||
| pub mod client; | ||
|
|
||
| mod pet_api; | ||
| pub use self::pet_api::PetAPI; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| use std::rc::Rc; | ||
| use std::borrow::Borrow; | ||
|
|
||
| use hyper; | ||
| use serde_json; | ||
| use futures; | ||
| use futures::{Future, Stream}; | ||
|
|
||
| use super::{Error, configuration, models}; | ||
|
|
||
| pub trait PetAPI { | ||
| fn add_pet(&self, pet: &models::Pet) -> Box<Future<Item = (), Error = Error>>; | ||
| } | ||
|
|
||
| pub struct PetAPIImpl<C: hyper::client::Connect> { | ||
| configuration: Rc<configuration::Configuration<C>>, | ||
| } | ||
|
|
||
| impl<C: hyper::client::Connect> PetAPIImpl<C> { | ||
| pub fn new(configuration: Rc<configuration::Configuration<C>>) -> PetAPIImpl<C> { | ||
| PetAPIImpl { | ||
| configuration: configuration, | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl<C: hyper::client::Connect>PetAPI for PetAPIImpl<C> { | ||
| fn add_pet(&self, pet: &models::Pet) -> Box<Future<Item = (), Error = Error>> { | ||
| let configuration: &configuration::Configuration<C> = self.configuration.borrow(); | ||
| let mut req = hyper::Request::new( | ||
| hyper::Method::Post, | ||
| format!("{}/pet", configuration.base_path).parse().unwrap()); | ||
| let serialized = serde_json::to_string(pet).unwrap(); | ||
| req.headers_mut().set(hyper::header::ContentType::json()); | ||
| req.headers_mut().set(hyper::header::ContentLength(serialized.len() as u64)); | ||
| req.set_body(serialized); | ||
|
|
||
| Box::new( | ||
| configuration.client.request(req).and_then(|res| { res.body().concat2() }) | ||
| .map_err(|e| Error::from(e)) | ||
| .and_then(|_| futures::future::ok(())) | ||
| ) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| use hyper; | ||
| use futures::{Future, Stream}; | ||
| use url; | ||
| use futures; | ||
|
|
||
| use super::Error; | ||
|
|
||
| pub fn update_pet_with_form<C: hyper::client::Connect>( | ||
| prefix: &str, | ||
| cli: &hyper::client::Client<C>, | ||
| pet_id: i64, | ||
| name: &str, | ||
| status: &str, | ||
| ) -> Box<Future<Item = (), Error = Error>> { | ||
| let mut req = hyper::Request::new( | ||
| hyper::Method::Post, | ||
| format!("{}/pet/{}", prefix, pet_id).parse().unwrap()); | ||
| let body = url::form_urlencoded::Serializer::new(String::new()) | ||
| .append_pair("name", name) | ||
| .append_pair("status", status) | ||
| .finish(); | ||
| req.headers_mut().set(hyper::header::ContentType::form_url_encoded()); | ||
| req.headers_mut().set(hyper::header::ContentLength(body.len() as u64)); | ||
| req.set_body(body); | ||
|
|
||
| Box::new( | ||
| cli.request(req).and_then(|res| { res.body().concat2() }) | ||
| .map_err(|e| Error::from(e)) | ||
| .and_then(|_| futures::future::ok(())) | ||
| ) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| #[macro_use] | ||
| extern crate serde_derive; | ||
|
|
||
| extern crate hyper; | ||
| extern crate serde_json; | ||
| extern crate futures; | ||
| extern crate url; | ||
|
|
||
| pub mod apis; | ||
| pub mod models; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| /// Pet catehgry | ||
| /// | ||
| /// A category for a pet | ||
| #[derive(Debug, Serialize, Deserialize)] | ||
| pub struct Category { | ||
| id: Option<i64>, | ||
| name: Option<String>, | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| mod pet; | ||
| pub use self::pet::Pet; | ||
|
|
||
| mod category; | ||
| pub use self::category::Category; | ||
|
|
||
| mod tag; | ||
| pub use self::tag::Tag; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| /// a Pet | ||
| /// | ||
| /// A pet for sale in the pet store | ||
| #[derive(Debug, Serialize, Deserialize)] | ||
| pub struct Pet { | ||
| id: Option<i64>, | ||
| category: Option<super::Category>, | ||
| name: String, | ||
| #[serde(rename = "photoUrls")] photo_urls: Vec<String>, | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. again, snake case here, and renamed fields need an annotation. |
||
| tags: Vec<super::Tag>, | ||
| status: Option<String>, | ||
| } | ||
|
|
||
| impl Pet { | ||
| pub fn new(name: String, photo_urls: Vec<String>) -> Pet { | ||
| Pet { | ||
| id: None, | ||
| category: None, | ||
| name: name, | ||
| photo_urls: photo_urls, | ||
| tags: Vec::new(), | ||
| status: None, | ||
| } | ||
| } | ||
|
|
||
| pub fn set_id(&mut self, id: i64) { | ||
| self.id = Some(id); | ||
| } | ||
|
|
||
| pub fn with_id(mut self, id: i64) -> Pet { | ||
| self.id = Some(id); | ||
| self | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| /// Pet Tag | ||
| /// | ||
| /// A tag for a pet | ||
| #[derive(Debug, Serialize, Deserialize)] | ||
| pub struct Tag { | ||
| id: Option<i64>, | ||
| name: Option<String>, | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these settings would be exposed as flags.