[Rust Server] Frunk - LabelledGeneric - support (#3552)

Derive the LabelledGeneric trait on Swagger models.  This allows
conversion between structurally similar types by using
https://docs.rs/frunk/0.2.2/frunk/#transmogrifying.

Exit if example fails to run
This commit is contained in:
Richard Whitehouse 2019-08-17 11:03:38 +01:00 committed by GitHub
parent aa4ead2a6d
commit 44fda895d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 669 additions and 519 deletions

View File

@ -38,4 +38,8 @@ for spec_path in modules/openapi-generator/src/test/resources/*/rust-server/* ;
$@" $@"
java $JAVA_OPTS -jar $executable $args java $JAVA_OPTS -jar $executable $args
if [ $? -ne 0 ]; then
exit $?
fi
done done

View File

@ -615,10 +615,6 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
} }
for (CodegenParameter param : op.headerParams) { for (CodegenParameter param : op.headerParams) {
// If a header uses UUIDs, we need to import the UUID package.
if (param.dataType.equals(uuidType)) {
additionalProperties.put("apiUsesUuid", true);
}
processParam(param, op); processParam(param, op);
// Give header params a name in camel case. CodegenParameters don't have a nameInCamelCase property. // Give header params a name in camel case. CodegenParameters don't have a nameInCamelCase property.
@ -925,7 +921,15 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
String modelName = entry.getKey(); String modelName = entry.getKey();
CodegenModel model = entry.getValue(); CodegenModel model = entry.getValue();
if (uuidType.equals(model.dataType)) {
additionalProperties.put("apiUsesUuid", true);
}
for (CodegenProperty prop : model.vars) { for (CodegenProperty prop : model.vars) {
if (prop.dataType.equals(uuidType)) {
additionalProperties.put("apiUsesUuid", true);
}
String xmlName = modelXmlNames.get(prop.dataType); String xmlName = modelXmlNames.get(prop.dataType);
if (xmlName != null) { if (xmlName != null) {
prop.vendorExtensions.put("itemXmlName", xmlName); prop.vendorExtensions.put("itemXmlName", xmlName);
@ -1132,6 +1136,11 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
private void processParam(CodegenParameter param, CodegenOperation op) { private void processParam(CodegenParameter param, CodegenOperation op) {
String example = null; String example = null;
// If a parameter uses UUIDs, we need to import the UUID package.
if (param.dataType.equals(uuidType)) {
additionalProperties.put("apiUsesUuid", true);
}
if (param.isString) { if (param.isString) {
param.vendorExtensions.put("formatString", "\\\"{}\\\""); param.vendorExtensions.put("formatString", "\\\"{}\\\"");
example = "\"" + ((param.example != null) ? param.example : "") + "\".to_string()"; example = "\"" + ((param.example != null) ? param.example : "") + "\".to_string()";

View File

@ -9,42 +9,69 @@ license = "Unlicense"
[features] [features]
default = ["client", "server"] default = ["client", "server"]
client = ["serde_json", {{#usesUrlEncodedForm}}"serde_urlencoded", {{/usesUrlEncodedForm}} {{#usesXml}}"serde-xml-rs", {{/usesXml}}"serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "url", "uuid"] client = [{{#usesUrlEncodedForm}}"serde_urlencoded", {{/usesUrlEncodedForm}}"serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "url"]
server = ["serde_json", {{#usesXml}}"serde-xml-rs", {{/usesXml}}"serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "tokio-proto", "tokio-tls", "regex", "percent-encoding", "url", "uuid"] server = ["serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "tokio-proto", "tokio-tls", "regex", "percent-encoding", "url"]
conversion = ["frunk", "frunk_derives", "frunk_core", "frunk-enum-core", "frunk-enum-derive"]
[dependencies] [dependencies]
# Required by example server. # Common
#
chrono = { version = "0.4", features = ["serde"] } chrono = { version = "0.4", features = ["serde"] }
futures = "0.1" futures = "0.1"
hyper = {version = "0.11", optional = true}
hyper-tls = {version = "0.1.2", optional = true}
swagger = "2" swagger = "2"
# Not required by example server.
#
lazy_static = "0.2" lazy_static = "0.2"
log = "0.3.0" log = "0.3.0"
mime = "0.2.6" mime = "0.2.6"
multipart = {version = "0.13.3"} multipart = "0.13.3"
native-tls = {version = "0.1.4", optional = true}
openssl = {version = "0.9.14", optional = true}
percent-encoding = {version = "1.0.0", optional = true}
regex = {version = "0.2", optional = true}
serde = "1.0" serde = "1.0"
serde_derive = "1.0" serde_derive = "1.0"
serde_json = "1.0"
# Crates included if required by the API definition
{{#apiUsesUuid}}
uuid = {version = "0.5", features = ["serde", "v4"]}
{{/apiUsesUuid}}
{{#usesXml}}
# TODO: this should be updated to point at the official crate once
# https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream
serde-xml-rs = {git = "git://github.com/Metaswitch/serde-xml-rs.git" , branch = "master"}
{{/usesXml}}
# Common between server and client features
hyper = {version = "0.11", optional = true}
hyper-tls = {version = "0.1.2", optional = true}
native-tls = {version = "0.1.4", optional = true}
openssl = {version = "0.9.14", optional = true}
serde_ignored = {version = "0.0.4", optional = true} serde_ignored = {version = "0.0.4", optional = true}
serde_json = {version = "1.0", optional = true}
serde_urlencoded = {version = "0.5.1", optional = true}
tokio-core = {version = "0.1.6", optional = true} tokio-core = {version = "0.1.6", optional = true}
url = {version = "1.5", optional = true}
# Client-specific
{{#usesUrlEncodedForm}}serde_urlencoded = {version = "0.5.1", optional = true}{{/usesUrlEncodedForm}}
# Server-specific
percent-encoding = {version = "1.0.0", optional = true}
regex = {version = "0.2", optional = true}
tokio-proto = {version = "0.1.1", optional = true} tokio-proto = {version = "0.1.1", optional = true}
tokio-tls = {version = "0.1.3", optional = true, features = ["tokio-proto"]} tokio-tls = {version = "0.1.3", optional = true, features = ["tokio-proto"]}
url = {version = "1.5", optional = true}
uuid = {version = "0.5", optional = true, features = ["serde", "v4"]} # Other optional crates
# ToDo: this should be updated to point at the official crate once frunk = { version = "0.3.0", optional = true }
# https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream frunk_derives = { version = "0.3.0", optional = true }
{{#usesXml}}serde-xml-rs = {git = "git://github.com/Metaswitch/serde-xml-rs.git" , branch = "master", optional = true}{{/usesXml}} frunk_core = { version = "0.3.0", optional = true }
frunk-enum-derive = { version = "0.2.0", optional = true }
frunk-enum-core = { version = "0.2.0", optional = true }
[dev-dependencies] [dev-dependencies]
clap = "2.25" clap = "2.25"
error-chain = "0.12" error-chain = "0.12"
{{^apiUsesUuid}}
uuid = {version = "0.5", features = ["serde", "v4"]}
{{/apiUsesUuid}}
[[example]]
name = "client"
required-features = ["client"]
[[example]]
name = "server"
required-features = ["server"]

View File

@ -5,22 +5,20 @@
{{/appDescription}} {{/appDescription}}
## Overview ## Overview
This client/server was generated by the [openapi-generator] This client/server was generated by the [openapi-generator]
(https://openapi-generator.tech) project. (https://openapi-generator.tech) project. By using the
By using the [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote server, you can easily generate a server stub. [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote
- server, you can easily generate a server stub.
To see how to make this your own, look here: To see how to make this your own, look here:
[README]((https://openapi-generator.tech)) [README]((https://openapi-generator.tech))
- API version: {{{appVersion}}} - API version: {{{appVersion}}}
{{^hideGenerationTimestamp}} {{^hideGenerationTimestamp}}- Build date: {{{generatedDate}}}{{/hideGenerationTimestamp}}
- Build date: {{{generatedDate}}}
{{/hideGenerationTimestamp}} {{#infoUrl}}For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}}){{/infoUrl}}
{{#infoUrl}}
For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}})
{{/infoUrl}}
This autogenerated project defines an API crate `{{{packageName}}}` which contains: This autogenerated project defines an API crate `{{{packageName}}}` which contains:
* An `Api` trait defining the API in Rust. * An `Api` trait defining the API in Rust.
@ -29,15 +27,17 @@ This autogenerated project defines an API crate `{{{packageName}}}` which contai
* A router which accepts HTTP requests and invokes the appropriate `Api` method for each operation. * A router which accepts HTTP requests and invokes the appropriate `Api` method for each operation.
It also contains an example server and client which make use of `{{{packageName}}}`: It also contains an example server and client which make use of `{{{packageName}}}`:
* The example server starts up a web server using the `{{{packageName}}}` router,
and supplies a trivial implementation of `Api` which returns failure for every operation. * The example server starts up a web server using the `{{{packageName}}}`
* The example client provides a CLI which lets you invoke any single operation on the router, and supplies a trivial implementation of `Api` which returns failure
`{{{packageName}}}` client by passing appropriate arguments on the command line. for every operation.
* The example client provides a CLI which lets you invoke
any single operation on the `{{{packageName}}}` client by passing appropriate
arguments on the command line.
You can use the example server and client as a basis for your own code. You can use the example server and client as a basis for your own code.
See below for [more detail on implementing a server](#writing-a-server). See below for [more detail on implementing a server](#writing-a-server).
## Examples ## Examples
Run examples with: Run examples with:
@ -52,14 +52,14 @@ To pass in arguments to the examples, put them after `--`, for example:
cargo run --example client -- --help cargo run --example client -- --help
``` ```
### Running the server ### Running the example server
To run the server, follow these simple steps: To run the server, follow these simple steps:
``` ```
cargo run --example server cargo run --example server
``` ```
### Running a client ### Running the example client
To run a client, follow one of the following simple steps: To run a client, follow one of the following simple steps:
```{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}} ```{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}
@ -73,43 +73,23 @@ The examples can be run in HTTPS mode by passing in the flag `--https`, for exam
cargo run --example server -- --https cargo run --example server -- --https
``` ```
This will use the keys/certificates from the examples directory. Note that the server chain is signed with This will use the keys/certificates from the examples directory. Note that the
`CN=localhost`. server chain is signed with `CN=localhost`.
## Using the generated library
## Writing a server The generated library has a few optional features that can be activated through Cargo.
The server example is designed to form the basis for implementing your own server. Simply follow these steps. * `server`
* This defaults to enabled and creates the basic skeleton of a server implementation based on hyper
* To create the server stack you'll need to provide an implementation of the API trait to provide the server function.
* `client`
* This defaults to enabled and creates the basic skeleton of a client implementation based on hyper
* The constructed client implements the API trait by making remote API call.
* `conversions`
* This defaults to disabled and creates extra derives on models to allow "transmogrification" between objects of structurally similar types.
* Set up a new Rust project, e.g., with `cargo init --bin`. See https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section for how to use features in your `Cargo.toml`.
* Insert `{{{packageName}}}` into the `members` array under [workspace] in the root `Cargo.toml`, e.g., `members = [ "{{{packageName}}}" ]`.
* Add `{{{packageName}}} = {version = "{{{appVersion}}}", path = "{{{packageName}}}"}` under `[dependencies]` in the root `Cargo.toml`.
* Copy the `[dependencies]` and `[dev-dependencies]` from `{{{packageName}}}/Cargo.toml` into the root `Cargo.toml`'s `[dependencies]` section.
* Copy all of the `[dev-dependencies]`, but only the `[dependencies]` that are required by the example server. These should be clearly indicated by comments.
* Remove `"optional = true"` from each of these lines if present.
Each autogenerated API will contain an implementation stub and main entry point, which should be copied into your project the first time:
```
cp {{{packageName}}}/examples/server.rs src/main.rs
cp {{{packageName}}}/examples/server_lib/mod.rs src/lib.rs
cp {{{packageName}}}/examples/server_lib/server.rs src/server.rs
```
Now
* From `src/main.rs`, remove the `mod server_lib;` line, and uncomment and fill in the `extern crate` line with the name of this server crate.
* Move the block of imports "required by the service library" from `src/main.rs` to `src/lib.rs` and uncomment.
* Change the `let server = server::Server {};` line to `let server = SERVICE_NAME::server().unwrap();` where `SERVICE_NAME` is the name of the server crate.
* Run `cargo build` to check it builds.
* Run `cargo fmt` to reformat the code.
* Commit the result before making any further changes (lest format changes get confused with your own updates).
Now replace the implementations in `src/server.rs` with your own code as required.
## Updating your server to track API changes
Later, if the API changes, you can copy new sections from the autogenerated API stub into your implementation.
Alternatively, implement the now-missing methods based on the compiler's error messages.
## Documentation for API Endpoints ## Documentation for API Endpoints

View File

@ -12,10 +12,10 @@ extern crate serde_urlencoded;
{{#apiUsesMultipart}} {{#apiUsesMultipart}}
extern crate multipart; extern crate multipart;
{{/apiUsesMultipart}} {{/apiUsesMultipart}}
{{#apiUsesUuid}} {{#apiUsesUuid}}
use uuid; extern crate uuid;
{{/apiUsesUuid}} {{/apiUsesUuid}}
use hyper; use hyper;
use hyper::header::{Headers, ContentType}; use hyper::header::{Headers, ContentType};
use hyper::Uri; use hyper::Uri;

View File

@ -7,9 +7,9 @@ extern crate futures;
#[macro_use] #[macro_use]
extern crate swagger; extern crate swagger;
#[allow(unused_extern_crates)] #[allow(unused_extern_crates)]
extern crate uuid;
extern crate clap; extern crate clap;
extern crate tokio_core; extern crate tokio_core;
extern crate uuid;
use swagger::{ContextBuilder, EmptyContext, XSpanIdString, Has, Push, AuthData}; use swagger::{ContextBuilder, EmptyContext, XSpanIdString, Has, Push, AuthData};

View File

@ -20,7 +20,9 @@ extern crate futures;
extern crate chrono; extern crate chrono;
#[macro_use] #[macro_use]
extern crate error_chain; extern crate error_chain;
{{#apiUsesUuid}}extern crate uuid;{{/apiUsesUuid}} {{#apiUsesUuid}}
extern crate uuid;
{{/apiUsesUuid}}
use openssl::x509::X509_FILETYPE_PEM; use openssl::x509::X509_FILETYPE_PEM;
use openssl::ssl::{SslAcceptorBuilder, SslMethod}; use openssl::ssl::{SslAcceptorBuilder, SslMethod};

View File

@ -6,9 +6,11 @@ use futures::{self, Future};
use chrono; use chrono;
use std::collections::HashMap; use std::collections::HashMap;
use std::marker::PhantomData; use std::marker::PhantomData;
{{#apiUsesUuid}}use uuid;{{/apiUsesUuid}}
use swagger; use swagger;
use swagger::{Has, XSpanIdString}; use swagger::{Has, XSpanIdString};
{{#apiUsesUuid}}
use uuid;
{{/apiUsesUuid}}
use {{{externCrateName}}}::{Api, ApiError{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}, use {{{externCrateName}}}::{Api, ApiError{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}},
{{{operationId}}}Response{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} {{{operationId}}}Response{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}

View File

@ -1,40 +1,53 @@
#![allow(missing_docs, trivial_casts, unused_variables, unused_mut, unused_imports, unused_extern_crates, non_camel_case_types)] #![allow(missing_docs, trivial_casts, unused_variables, unused_mut, unused_imports, unused_extern_crates, non_camel_case_types)]
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
{{#apiUsesUuid}}extern crate uuid;{{/apiUsesUuid}}
{{#usesXml}}extern crate serde_xml_rs;{{/usesXml}}
extern crate futures;
extern crate chrono;
#[macro_use] #[macro_use]
extern crate lazy_static; extern crate lazy_static;
#[macro_use] #[macro_use]
extern crate log; extern crate log;
extern crate mime; #[macro_use]
extern crate serde_derive;
// Logically this should be in the client and server modules, but rust doesn't allow `macro_use` from a module.
#[cfg(any(feature = "client", feature = "server"))] #[cfg(any(feature = "client", feature = "server"))]
#[macro_use] #[macro_use]
extern crate hyper; extern crate hyper;
#[cfg(any(feature = "client", feature = "server"))]
extern crate swagger;
#[macro_use] #[macro_use]
extern crate url; extern crate url;
// Crates for conversion support
#[cfg(feature = "conversion")]
#[macro_use]
extern crate frunk_derives;
#[cfg(feature = "conversion")]
#[macro_use]
extern crate frunk_enum_derive;
#[cfg(feature = "conversion")]
extern crate frunk_core;
extern crate mime;
extern crate serde;
extern crate serde_json;
{{#usesXml}}extern crate serde_xml_rs;{{/usesXml}}
extern crate futures;
extern crate chrono;
extern crate swagger;
{{#apiUsesUuid}}
extern crate uuid;
{{/apiUsesUuid}}
use futures::Stream; use futures::Stream;
use std::io::Error; use std::io::Error;
#[allow(unused_imports)] #[allow(unused_imports)]
use std::collections::HashMap; use std::collections::HashMap;
pub use futures::Future;
#[cfg(any(feature = "client", feature = "server"))] #[cfg(any(feature = "client", feature = "server"))]
mod mimetypes; mod mimetypes;
#[deprecated(note = "Import swagger-rs directly")]
pub use swagger::{ApiError, ContextWrapper}; pub use swagger::{ApiError, ContextWrapper};
#[deprecated(note = "Import futures directly")]
pub use futures::Future;
pub const BASE_PATH: &'static str = "{{{basePathWithoutHost}}}"; pub const BASE_PATH: &'static str = "{{{basePathWithoutHost}}}";
pub const API_VERSION: &'static str = "{{{appVersion}}}"; pub const API_VERSION: &'static str = "{{{appVersion}}}";

View File

@ -1,6 +1,5 @@
#![allow(unused_imports, unused_qualifications, unused_extern_crates)] #![allow(unused_imports, unused_qualifications, unused_extern_crates)]
extern crate chrono; extern crate chrono;
extern crate uuid;
{{#usesXml}} {{#usesXml}}
use serde_xml_rs; use serde_xml_rs;
@ -16,7 +15,9 @@ use std::collections::HashMap;
use models; use models;
use swagger; use swagger;
use std::string::ParseError; use std::string::ParseError;
{{#apiUsesUuid}}
use uuid;
{{/apiUsesUuid}}
{{#models}}{{#model}} {{#models}}{{#model}}
{{#description}}/// {{{description}}} {{#description}}/// {{{description}}}
@ -25,7 +26,8 @@ use std::string::ParseError;
/// which helps with FFI. /// which helps with FFI.
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Serialize, Deserialize, Eq, Ord)]{{#xmlName}} #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGenericEnum))]{{#xmlName}}
#[serde(rename = "{{{xmlName}}}")]{{/xmlName}} #[serde(rename = "{{{xmlName}}}")]{{/xmlName}}
pub enum {{{classname}}} { {{#allowableValues}}{{#enumVars}} pub enum {{{classname}}} { {{#allowableValues}}{{#enumVars}}
#[serde(rename = {{{value}}})] #[serde(rename = {{{value}}})]
@ -50,6 +52,7 @@ impl ::std::str::FromStr for {{{classname}}} {
} }
} }
{{/isEnum}}{{^isEnum}}{{#dataType}}{{! newtype}}#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)] {{/isEnum}}{{^isEnum}}{{#dataType}}{{! newtype}}#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
{{#xmlName}}#[serde(rename = "{{{xmlName}}}")]{{/xmlName}} {{#xmlName}}#[serde(rename = "{{{xmlName}}}")]{{/xmlName}}
pub struct {{{classname}}}({{{dataType}}}); pub struct {{{classname}}}({{{dataType}}});
@ -97,6 +100,7 @@ where
} }
{{/itemXmlName}}{{/vendorExtensions}}{{! vec}}#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] {{/itemXmlName}}{{/vendorExtensions}}{{! vec}}#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct {{{classname}}}({{#vendorExtensions}}{{#itemXmlName}}#[serde(serialize_with = "wrap_in_{{{itemXmlName}}}")]{{/itemXmlName}}{{/vendorExtensions}}Vec<{{{arrayModelType}}}>); pub struct {{{classname}}}({{#vendorExtensions}}{{#itemXmlName}}#[serde(serialize_with = "wrap_in_{{{itemXmlName}}}")]{{/itemXmlName}}{{/vendorExtensions}}Vec<{{{arrayModelType}}}>);
impl ::std::convert::From<Vec<{{{arrayModelType}}}>> for {{{classname}}} { impl ::std::convert::From<Vec<{{{arrayModelType}}}>> for {{{classname}}} {
@ -157,7 +161,8 @@ impl ::std::ops::DerefMut for {{{classname}}} {
} }
} }
{{/arrayModelType}}{{^arrayModelType}}{{! general struct}}#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]{{#xmlName}} {{/arrayModelType}}{{^arrayModelType}}{{! general struct}}#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]{{#xmlName}}
#[serde(rename = "{{{xmlName}}}")]{{/xmlName}} #[serde(rename = "{{{xmlName}}}")]{{/xmlName}}
pub struct {{{classname}}} { pub struct {{{classname}}} {
{{#vars}}{{#description}} /// {{{description}}} {{#vars}}{{#description}} /// {{{description}}}

View File

@ -8,7 +8,7 @@ extern crate mime;
extern crate chrono; extern crate chrono;
extern crate percent_encoding; extern crate percent_encoding;
extern crate url; extern crate url;
{{^apiUsesUuid}} {{#apiUsesUuid}}
extern crate uuid; extern crate uuid;
{{/apiUsesUuid}} {{/apiUsesUuid}}
{{#apiUsesMultipart}} {{#apiUsesMultipart}}
@ -32,9 +32,6 @@ use serde_json;
{{#usesXml}} {{#usesXml}}
use serde_xml_rs; use serde_xml_rs;
{{/usesXml}} {{/usesXml}}
{{#apiUsesUuid}}
use uuid;
{{/apiUsesUuid}}
#[allow(unused_imports)] #[allow(unused_imports)]
use std::collections::{HashMap, BTreeMap}; use std::collections::{HashMap, BTreeMap};

View File

@ -7,42 +7,59 @@ license = "Unlicense"
[features] [features]
default = ["client", "server"] default = ["client", "server"]
client = ["serde_json", "serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "url", "uuid"] client = ["serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "url"]
server = ["serde_json", "serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "tokio-proto", "tokio-tls", "regex", "percent-encoding", "url", "uuid"] server = ["serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "tokio-proto", "tokio-tls", "regex", "percent-encoding", "url"]
conversion = ["frunk", "frunk_derives", "frunk_core", "frunk-enum-core", "frunk-enum-derive"]
[dependencies] [dependencies]
# Required by example server. # Common
#
chrono = { version = "0.4", features = ["serde"] } chrono = { version = "0.4", features = ["serde"] }
futures = "0.1" futures = "0.1"
hyper = {version = "0.11", optional = true}
hyper-tls = {version = "0.1.2", optional = true}
swagger = "2" swagger = "2"
# Not required by example server.
#
lazy_static = "0.2" lazy_static = "0.2"
log = "0.3.0" log = "0.3.0"
mime = "0.2.6" mime = "0.2.6"
multipart = {version = "0.13.3"} multipart = "0.13.3"
native-tls = {version = "0.1.4", optional = true}
openssl = {version = "0.9.14", optional = true}
percent-encoding = {version = "1.0.0", optional = true}
regex = {version = "0.2", optional = true}
serde = "1.0" serde = "1.0"
serde_derive = "1.0" serde_derive = "1.0"
serde_json = "1.0"
# Crates included if required by the API definition
# Common between server and client features
hyper = {version = "0.11", optional = true}
hyper-tls = {version = "0.1.2", optional = true}
native-tls = {version = "0.1.4", optional = true}
openssl = {version = "0.9.14", optional = true}
serde_ignored = {version = "0.0.4", optional = true} serde_ignored = {version = "0.0.4", optional = true}
serde_json = {version = "1.0", optional = true}
serde_urlencoded = {version = "0.5.1", optional = true}
tokio-core = {version = "0.1.6", optional = true} tokio-core = {version = "0.1.6", optional = true}
url = {version = "1.5", optional = true}
# Client-specific
# Server-specific
percent-encoding = {version = "1.0.0", optional = true}
regex = {version = "0.2", optional = true}
tokio-proto = {version = "0.1.1", optional = true} tokio-proto = {version = "0.1.1", optional = true}
tokio-tls = {version = "0.1.3", optional = true, features = ["tokio-proto"]} tokio-tls = {version = "0.1.3", optional = true, features = ["tokio-proto"]}
url = {version = "1.5", optional = true}
uuid = {version = "0.5", optional = true, features = ["serde", "v4"]}
# ToDo: this should be updated to point at the official crate once
# https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream
# Other optional crates
frunk = { version = "0.3.0", optional = true }
frunk_derives = { version = "0.3.0", optional = true }
frunk_core = { version = "0.3.0", optional = true }
frunk-enum-derive = { version = "0.2.0", optional = true }
frunk-enum-core = { version = "0.2.0", optional = true }
[dev-dependencies] [dev-dependencies]
clap = "2.25" clap = "2.25"
error-chain = "0.12" error-chain = "0.12"
uuid = {version = "0.5", features = ["serde", "v4"]}
[[example]]
name = "client"
required-features = ["client"]
[[example]]
name = "server"
required-features = ["server"]

View File

@ -3,10 +3,11 @@
API under test API under test
## Overview ## Overview
This client/server was generated by the [openapi-generator] This client/server was generated by the [openapi-generator]
(https://openapi-generator.tech) project. (https://openapi-generator.tech) project. By using the
By using the [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote server, you can easily generate a server stub. [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote
- server, you can easily generate a server stub.
To see how to make this your own, look here: To see how to make this your own, look here:
@ -14,6 +15,9 @@ To see how to make this your own, look here:
- API version: 1.0.7 - API version: 1.0.7
This autogenerated project defines an API crate `multipart-v3` which contains: This autogenerated project defines an API crate `multipart-v3` which contains:
* An `Api` trait defining the API in Rust. * An `Api` trait defining the API in Rust.
* Data types representing the underlying data model. * Data types representing the underlying data model.
@ -21,15 +25,17 @@ This autogenerated project defines an API crate `multipart-v3` which contains:
* A router which accepts HTTP requests and invokes the appropriate `Api` method for each operation. * A router which accepts HTTP requests and invokes the appropriate `Api` method for each operation.
It also contains an example server and client which make use of `multipart-v3`: It also contains an example server and client which make use of `multipart-v3`:
* The example server starts up a web server using the `multipart-v3` router,
and supplies a trivial implementation of `Api` which returns failure for every operation. * The example server starts up a web server using the `multipart-v3`
* The example client provides a CLI which lets you invoke any single operation on the router, and supplies a trivial implementation of `Api` which returns failure
`multipart-v3` client by passing appropriate arguments on the command line. for every operation.
* The example client provides a CLI which lets you invoke
any single operation on the `multipart-v3` client by passing appropriate
arguments on the command line.
You can use the example server and client as a basis for your own code. You can use the example server and client as a basis for your own code.
See below for [more detail on implementing a server](#writing-a-server). See below for [more detail on implementing a server](#writing-a-server).
## Examples ## Examples
Run examples with: Run examples with:
@ -44,14 +50,14 @@ To pass in arguments to the examples, put them after `--`, for example:
cargo run --example client -- --help cargo run --example client -- --help
``` ```
### Running the server ### Running the example server
To run the server, follow these simple steps: To run the server, follow these simple steps:
``` ```
cargo run --example server cargo run --example server
``` ```
### Running a client ### Running the example client
To run a client, follow one of the following simple steps: To run a client, follow one of the following simple steps:
``` ```
@ -65,43 +71,23 @@ The examples can be run in HTTPS mode by passing in the flag `--https`, for exam
cargo run --example server -- --https cargo run --example server -- --https
``` ```
This will use the keys/certificates from the examples directory. Note that the server chain is signed with This will use the keys/certificates from the examples directory. Note that the
`CN=localhost`. server chain is signed with `CN=localhost`.
## Using the generated library
## Writing a server The generated library has a few optional features that can be activated through Cargo.
The server example is designed to form the basis for implementing your own server. Simply follow these steps. * `server`
* This defaults to enabled and creates the basic skeleton of a server implementation based on hyper
* To create the server stack you'll need to provide an implementation of the API trait to provide the server function.
* `client`
* This defaults to enabled and creates the basic skeleton of a client implementation based on hyper
* The constructed client implements the API trait by making remote API call.
* `conversions`
* This defaults to disabled and creates extra derives on models to allow "transmogrification" between objects of structurally similar types.
* Set up a new Rust project, e.g., with `cargo init --bin`. See https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section for how to use features in your `Cargo.toml`.
* Insert `multipart-v3` into the `members` array under [workspace] in the root `Cargo.toml`, e.g., `members = [ "multipart-v3" ]`.
* Add `multipart-v3 = {version = "1.0.7", path = "multipart-v3"}` under `[dependencies]` in the root `Cargo.toml`.
* Copy the `[dependencies]` and `[dev-dependencies]` from `multipart-v3/Cargo.toml` into the root `Cargo.toml`'s `[dependencies]` section.
* Copy all of the `[dev-dependencies]`, but only the `[dependencies]` that are required by the example server. These should be clearly indicated by comments.
* Remove `"optional = true"` from each of these lines if present.
Each autogenerated API will contain an implementation stub and main entry point, which should be copied into your project the first time:
```
cp multipart-v3/examples/server.rs src/main.rs
cp multipart-v3/examples/server_lib/mod.rs src/lib.rs
cp multipart-v3/examples/server_lib/server.rs src/server.rs
```
Now
* From `src/main.rs`, remove the `mod server_lib;` line, and uncomment and fill in the `extern crate` line with the name of this server crate.
* Move the block of imports "required by the service library" from `src/main.rs` to `src/lib.rs` and uncomment.
* Change the `let server = server::Server {};` line to `let server = SERVICE_NAME::server().unwrap();` where `SERVICE_NAME` is the name of the server crate.
* Run `cargo build` to check it builds.
* Run `cargo fmt` to reformat the code.
* Commit the result before making any further changes (lest format changes get confused with your own updates).
Now replace the implementations in `src/server.rs` with your own code as required.
## Updating your server to track API changes
Later, if the API changes, you can copy new sections from the autogenerated API stub into your implementation.
Alternatively, implement the now-missing methods based on the compiler's error messages.
## Documentation for API Endpoints ## Documentation for API Endpoints

View File

@ -7,9 +7,9 @@ extern crate futures;
#[macro_use] #[macro_use]
extern crate swagger; extern crate swagger;
#[allow(unused_extern_crates)] #[allow(unused_extern_crates)]
extern crate uuid;
extern crate clap; extern crate clap;
extern crate tokio_core; extern crate tokio_core;
extern crate uuid;
use swagger::{ContextBuilder, EmptyContext, XSpanIdString, Has, Push, AuthData}; use swagger::{ContextBuilder, EmptyContext, XSpanIdString, Has, Push, AuthData};

View File

@ -21,7 +21,6 @@ extern crate chrono;
#[macro_use] #[macro_use]
extern crate error_chain; extern crate error_chain;
use openssl::x509::X509_FILETYPE_PEM; use openssl::x509::X509_FILETYPE_PEM;
use openssl::ssl::{SslAcceptorBuilder, SslMethod}; use openssl::ssl::{SslAcceptorBuilder, SslMethod};
use openssl::error::ErrorStack; use openssl::error::ErrorStack;

View File

@ -6,7 +6,6 @@ use futures::{self, Future};
use chrono; use chrono;
use std::collections::HashMap; use std::collections::HashMap;
use std::marker::PhantomData; use std::marker::PhantomData;
use swagger; use swagger;
use swagger::{Has, XSpanIdString}; use swagger::{Has, XSpanIdString};

View File

@ -1,40 +1,50 @@
#![allow(missing_docs, trivial_casts, unused_variables, unused_mut, unused_imports, unused_extern_crates, non_camel_case_types)] #![allow(missing_docs, trivial_casts, unused_variables, unused_mut, unused_imports, unused_extern_crates, non_camel_case_types)]
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate futures;
extern crate chrono;
#[macro_use] #[macro_use]
extern crate lazy_static; extern crate lazy_static;
#[macro_use] #[macro_use]
extern crate log; extern crate log;
extern crate mime; #[macro_use]
extern crate serde_derive;
// Logically this should be in the client and server modules, but rust doesn't allow `macro_use` from a module.
#[cfg(any(feature = "client", feature = "server"))] #[cfg(any(feature = "client", feature = "server"))]
#[macro_use] #[macro_use]
extern crate hyper; extern crate hyper;
#[cfg(any(feature = "client", feature = "server"))]
extern crate swagger;
#[macro_use] #[macro_use]
extern crate url; extern crate url;
// Crates for conversion support
#[cfg(feature = "conversion")]
#[macro_use]
extern crate frunk_derives;
#[cfg(feature = "conversion")]
#[macro_use]
extern crate frunk_enum_derive;
#[cfg(feature = "conversion")]
extern crate frunk_core;
extern crate mime;
extern crate serde;
extern crate serde_json;
extern crate futures;
extern crate chrono;
extern crate swagger;
use futures::Stream; use futures::Stream;
use std::io::Error; use std::io::Error;
#[allow(unused_imports)] #[allow(unused_imports)]
use std::collections::HashMap; use std::collections::HashMap;
pub use futures::Future;
#[cfg(any(feature = "client", feature = "server"))] #[cfg(any(feature = "client", feature = "server"))]
mod mimetypes; mod mimetypes;
#[deprecated(note = "Import swagger-rs directly")]
pub use swagger::{ApiError, ContextWrapper}; pub use swagger::{ApiError, ContextWrapper};
#[deprecated(note = "Import futures directly")]
pub use futures::Future;
pub const BASE_PATH: &'static str = ""; pub const BASE_PATH: &'static str = "";
pub const API_VERSION: &'static str = "1.0.7"; pub const API_VERSION: &'static str = "1.0.7";

View File

@ -1,6 +1,5 @@
#![allow(unused_imports, unused_qualifications, unused_extern_crates)] #![allow(unused_imports, unused_qualifications, unused_extern_crates)]
extern crate chrono; extern crate chrono;
extern crate uuid;
use serde::ser::Serializer; use serde::ser::Serializer;
@ -10,8 +9,8 @@ use swagger;
use std::string::ParseError; use std::string::ParseError;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct MultipartRequest { pub struct MultipartRequest {
#[serde(rename = "string_field")] #[serde(rename = "string_field")]
pub string_field: String, pub string_field: String,
@ -42,6 +41,7 @@ impl MultipartRequest {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct MultipartRequestObjectField { pub struct MultipartRequestObjectField {
#[serde(rename = "field_a")] #[serde(rename = "field_a")]
pub field_a: String, pub field_a: String,

View File

@ -8,7 +8,6 @@ extern crate mime;
extern crate chrono; extern crate chrono;
extern crate percent_encoding; extern crate percent_encoding;
extern crate url; extern crate url;
extern crate uuid;
extern crate multipart; extern crate multipart;
use std::sync::Arc; use std::sync::Arc;

View File

@ -7,42 +7,62 @@ license = "Unlicense"
[features] [features]
default = ["client", "server"] default = ["client", "server"]
client = ["serde_json", "serde-xml-rs", "serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "url", "uuid"] client = ["serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "url"]
server = ["serde_json", "serde-xml-rs", "serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "tokio-proto", "tokio-tls", "regex", "percent-encoding", "url", "uuid"] server = ["serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "tokio-proto", "tokio-tls", "regex", "percent-encoding", "url"]
conversion = ["frunk", "frunk_derives", "frunk_core", "frunk-enum-core", "frunk-enum-derive"]
[dependencies] [dependencies]
# Required by example server. # Common
#
chrono = { version = "0.4", features = ["serde"] } chrono = { version = "0.4", features = ["serde"] }
futures = "0.1" futures = "0.1"
hyper = {version = "0.11", optional = true}
hyper-tls = {version = "0.1.2", optional = true}
swagger = "2" swagger = "2"
# Not required by example server.
#
lazy_static = "0.2" lazy_static = "0.2"
log = "0.3.0" log = "0.3.0"
mime = "0.2.6" mime = "0.2.6"
multipart = {version = "0.13.3"} multipart = "0.13.3"
native-tls = {version = "0.1.4", optional = true}
openssl = {version = "0.9.14", optional = true}
percent-encoding = {version = "1.0.0", optional = true}
regex = {version = "0.2", optional = true}
serde = "1.0" serde = "1.0"
serde_derive = "1.0" serde_derive = "1.0"
serde_json = "1.0"
# Crates included if required by the API definition
uuid = {version = "0.5", features = ["serde", "v4"]}
# TODO: this should be updated to point at the official crate once
# https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream
serde-xml-rs = {git = "git://github.com/Metaswitch/serde-xml-rs.git" , branch = "master"}
# Common between server and client features
hyper = {version = "0.11", optional = true}
hyper-tls = {version = "0.1.2", optional = true}
native-tls = {version = "0.1.4", optional = true}
openssl = {version = "0.9.14", optional = true}
serde_ignored = {version = "0.0.4", optional = true} serde_ignored = {version = "0.0.4", optional = true}
serde_json = {version = "1.0", optional = true}
serde_urlencoded = {version = "0.5.1", optional = true}
tokio-core = {version = "0.1.6", optional = true} tokio-core = {version = "0.1.6", optional = true}
url = {version = "1.5", optional = true}
# Client-specific
# Server-specific
percent-encoding = {version = "1.0.0", optional = true}
regex = {version = "0.2", optional = true}
tokio-proto = {version = "0.1.1", optional = true} tokio-proto = {version = "0.1.1", optional = true}
tokio-tls = {version = "0.1.3", optional = true, features = ["tokio-proto"]} tokio-tls = {version = "0.1.3", optional = true, features = ["tokio-proto"]}
url = {version = "1.5", optional = true}
uuid = {version = "0.5", optional = true, features = ["serde", "v4"]} # Other optional crates
# ToDo: this should be updated to point at the official crate once frunk = { version = "0.3.0", optional = true }
# https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream frunk_derives = { version = "0.3.0", optional = true }
serde-xml-rs = {git = "git://github.com/Metaswitch/serde-xml-rs.git" , branch = "master", optional = true} frunk_core = { version = "0.3.0", optional = true }
frunk-enum-derive = { version = "0.2.0", optional = true }
frunk-enum-core = { version = "0.2.0", optional = true }
[dev-dependencies] [dev-dependencies]
clap = "2.25" clap = "2.25"
error-chain = "0.12" error-chain = "0.12"
[[example]]
name = "client"
required-features = ["client"]
[[example]]
name = "server"
required-features = ["server"]

View File

@ -3,10 +3,11 @@
API under test API under test
## Overview ## Overview
This client/server was generated by the [openapi-generator] This client/server was generated by the [openapi-generator]
(https://openapi-generator.tech) project. (https://openapi-generator.tech) project. By using the
By using the [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote server, you can easily generate a server stub. [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote
- server, you can easily generate a server stub.
To see how to make this your own, look here: To see how to make this your own, look here:
@ -14,6 +15,9 @@ To see how to make this your own, look here:
- API version: 1.0.7 - API version: 1.0.7
This autogenerated project defines an API crate `openapi-v3` which contains: This autogenerated project defines an API crate `openapi-v3` which contains:
* An `Api` trait defining the API in Rust. * An `Api` trait defining the API in Rust.
* Data types representing the underlying data model. * Data types representing the underlying data model.
@ -21,15 +25,17 @@ This autogenerated project defines an API crate `openapi-v3` which contains:
* A router which accepts HTTP requests and invokes the appropriate `Api` method for each operation. * A router which accepts HTTP requests and invokes the appropriate `Api` method for each operation.
It also contains an example server and client which make use of `openapi-v3`: It also contains an example server and client which make use of `openapi-v3`:
* The example server starts up a web server using the `openapi-v3` router,
and supplies a trivial implementation of `Api` which returns failure for every operation. * The example server starts up a web server using the `openapi-v3`
* The example client provides a CLI which lets you invoke any single operation on the router, and supplies a trivial implementation of `Api` which returns failure
`openapi-v3` client by passing appropriate arguments on the command line. for every operation.
* The example client provides a CLI which lets you invoke
any single operation on the `openapi-v3` client by passing appropriate
arguments on the command line.
You can use the example server and client as a basis for your own code. You can use the example server and client as a basis for your own code.
See below for [more detail on implementing a server](#writing-a-server). See below for [more detail on implementing a server](#writing-a-server).
## Examples ## Examples
Run examples with: Run examples with:
@ -44,14 +50,14 @@ To pass in arguments to the examples, put them after `--`, for example:
cargo run --example client -- --help cargo run --example client -- --help
``` ```
### Running the server ### Running the example server
To run the server, follow these simple steps: To run the server, follow these simple steps:
``` ```
cargo run --example server cargo run --example server
``` ```
### Running a client ### Running the example client
To run a client, follow one of the following simple steps: To run a client, follow one of the following simple steps:
``` ```
@ -71,43 +77,23 @@ The examples can be run in HTTPS mode by passing in the flag `--https`, for exam
cargo run --example server -- --https cargo run --example server -- --https
``` ```
This will use the keys/certificates from the examples directory. Note that the server chain is signed with This will use the keys/certificates from the examples directory. Note that the
`CN=localhost`. server chain is signed with `CN=localhost`.
## Using the generated library
## Writing a server The generated library has a few optional features that can be activated through Cargo.
The server example is designed to form the basis for implementing your own server. Simply follow these steps. * `server`
* This defaults to enabled and creates the basic skeleton of a server implementation based on hyper
* To create the server stack you'll need to provide an implementation of the API trait to provide the server function.
* `client`
* This defaults to enabled and creates the basic skeleton of a client implementation based on hyper
* The constructed client implements the API trait by making remote API call.
* `conversions`
* This defaults to disabled and creates extra derives on models to allow "transmogrification" between objects of structurally similar types.
* Set up a new Rust project, e.g., with `cargo init --bin`. See https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section for how to use features in your `Cargo.toml`.
* Insert `openapi-v3` into the `members` array under [workspace] in the root `Cargo.toml`, e.g., `members = [ "openapi-v3" ]`.
* Add `openapi-v3 = {version = "1.0.7", path = "openapi-v3"}` under `[dependencies]` in the root `Cargo.toml`.
* Copy the `[dependencies]` and `[dev-dependencies]` from `openapi-v3/Cargo.toml` into the root `Cargo.toml`'s `[dependencies]` section.
* Copy all of the `[dev-dependencies]`, but only the `[dependencies]` that are required by the example server. These should be clearly indicated by comments.
* Remove `"optional = true"` from each of these lines if present.
Each autogenerated API will contain an implementation stub and main entry point, which should be copied into your project the first time:
```
cp openapi-v3/examples/server.rs src/main.rs
cp openapi-v3/examples/server_lib/mod.rs src/lib.rs
cp openapi-v3/examples/server_lib/server.rs src/server.rs
```
Now
* From `src/main.rs`, remove the `mod server_lib;` line, and uncomment and fill in the `extern crate` line with the name of this server crate.
* Move the block of imports "required by the service library" from `src/main.rs` to `src/lib.rs` and uncomment.
* Change the `let server = server::Server {};` line to `let server = SERVICE_NAME::server().unwrap();` where `SERVICE_NAME` is the name of the server crate.
* Run `cargo build` to check it builds.
* Run `cargo fmt` to reformat the code.
* Commit the result before making any further changes (lest format changes get confused with your own updates).
Now replace the implementations in `src/server.rs` with your own code as required.
## Updating your server to track API changes
Later, if the API changes, you can copy new sections from the autogenerated API stub into your implementation.
Alternatively, implement the now-missing methods based on the compiler's error messages.
## Documentation for API Endpoints ## Documentation for API Endpoints

View File

@ -7,9 +7,9 @@ extern crate futures;
#[macro_use] #[macro_use]
extern crate swagger; extern crate swagger;
#[allow(unused_extern_crates)] #[allow(unused_extern_crates)]
extern crate uuid;
extern crate clap; extern crate clap;
extern crate tokio_core; extern crate tokio_core;
extern crate uuid;
use swagger::{ContextBuilder, EmptyContext, XSpanIdString, Has, Push, AuthData}; use swagger::{ContextBuilder, EmptyContext, XSpanIdString, Has, Push, AuthData};

View File

@ -20,7 +20,7 @@ extern crate futures;
extern crate chrono; extern crate chrono;
#[macro_use] #[macro_use]
extern crate error_chain; extern crate error_chain;
extern crate uuid;
use openssl::x509::X509_FILETYPE_PEM; use openssl::x509::X509_FILETYPE_PEM;
use openssl::ssl::{SslAcceptorBuilder, SslMethod}; use openssl::ssl::{SslAcceptorBuilder, SslMethod};

View File

@ -6,9 +6,9 @@ use futures::{self, Future};
use chrono; use chrono;
use std::collections::HashMap; use std::collections::HashMap;
use std::marker::PhantomData; use std::marker::PhantomData;
use swagger; use swagger;
use swagger::{Has, XSpanIdString}; use swagger::{Has, XSpanIdString};
use uuid;
use openapi_v3::{Api, ApiError, use openapi_v3::{Api, ApiError,
RequiredOctetStreamPutResponse, RequiredOctetStreamPutResponse,

View File

@ -6,6 +6,7 @@ extern crate openssl;
extern crate mime; extern crate mime;
extern crate chrono; extern crate chrono;
extern crate url; extern crate url;
extern crate uuid;
use hyper; use hyper;
use hyper::header::{Headers, ContentType}; use hyper::header::{Headers, ContentType};

View File

@ -1,40 +1,51 @@
#![allow(missing_docs, trivial_casts, unused_variables, unused_mut, unused_imports, unused_extern_crates, non_camel_case_types)] #![allow(missing_docs, trivial_casts, unused_variables, unused_mut, unused_imports, unused_extern_crates, non_camel_case_types)]
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serde_xml_rs;
extern crate futures;
extern crate chrono;
#[macro_use] #[macro_use]
extern crate lazy_static; extern crate lazy_static;
#[macro_use] #[macro_use]
extern crate log; extern crate log;
extern crate mime; #[macro_use]
extern crate serde_derive;
// Logically this should be in the client and server modules, but rust doesn't allow `macro_use` from a module.
#[cfg(any(feature = "client", feature = "server"))] #[cfg(any(feature = "client", feature = "server"))]
#[macro_use] #[macro_use]
extern crate hyper; extern crate hyper;
#[cfg(any(feature = "client", feature = "server"))]
extern crate swagger;
#[macro_use] #[macro_use]
extern crate url; extern crate url;
// Crates for conversion support
#[cfg(feature = "conversion")]
#[macro_use]
extern crate frunk_derives;
#[cfg(feature = "conversion")]
#[macro_use]
extern crate frunk_enum_derive;
#[cfg(feature = "conversion")]
extern crate frunk_core;
extern crate mime;
extern crate serde;
extern crate serde_json;
extern crate serde_xml_rs;
extern crate futures;
extern crate chrono;
extern crate swagger;
extern crate uuid;
use futures::Stream; use futures::Stream;
use std::io::Error; use std::io::Error;
#[allow(unused_imports)] #[allow(unused_imports)]
use std::collections::HashMap; use std::collections::HashMap;
pub use futures::Future;
#[cfg(any(feature = "client", feature = "server"))] #[cfg(any(feature = "client", feature = "server"))]
mod mimetypes; mod mimetypes;
#[deprecated(note = "Import swagger-rs directly")]
pub use swagger::{ApiError, ContextWrapper}; pub use swagger::{ApiError, ContextWrapper};
#[deprecated(note = "Import futures directly")]
pub use futures::Future;
pub const BASE_PATH: &'static str = ""; pub const BASE_PATH: &'static str = "";
pub const API_VERSION: &'static str = "1.0.7"; pub const API_VERSION: &'static str = "1.0.7";

View File

@ -1,6 +1,5 @@
#![allow(unused_imports, unused_qualifications, unused_extern_crates)] #![allow(unused_imports, unused_qualifications, unused_extern_crates)]
extern crate chrono; extern crate chrono;
extern crate uuid;
use serde_xml_rs; use serde_xml_rs;
use serde::ser::Serializer; use serde::ser::Serializer;
@ -9,7 +8,7 @@ use std::collections::{HashMap, BTreeMap};
use models; use models;
use swagger; use swagger;
use std::string::ParseError; use std::string::ParseError;
use uuid;
// Utility function for wrapping list elements when serializing xml // Utility function for wrapping list elements when serializing xml
@ -22,6 +21,7 @@ where
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct AnotherXmlArray(#[serde(serialize_with = "wrap_in_snake_another_xml_inner")]Vec<String>); pub struct AnotherXmlArray(#[serde(serialize_with = "wrap_in_snake_another_xml_inner")]Vec<String>);
impl ::std::convert::From<Vec<String>> for AnotherXmlArray { impl ::std::convert::From<Vec<String>> for AnotherXmlArray {
@ -93,6 +93,7 @@ impl AnotherXmlArray {
} }
#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
#[serde(rename = "snake_another_xml_inner")] #[serde(rename = "snake_another_xml_inner")]
pub struct AnotherXmlInner(String); pub struct AnotherXmlInner(String);
@ -140,6 +141,7 @@ impl AnotherXmlInner {
/// An XML object /// An XML object
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
#[serde(rename = "snake_another_xml_object")] #[serde(rename = "snake_another_xml_object")]
pub struct AnotherXmlObject { pub struct AnotherXmlObject {
#[serde(rename = "inner_string")] #[serde(rename = "inner_string")]
@ -176,6 +178,7 @@ impl AnotherXmlObject {
/// An XML object /// An XML object
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
#[serde(rename = "camelDuplicateXmlObject")] #[serde(rename = "camelDuplicateXmlObject")]
pub struct DuplicateXmlObject { pub struct DuplicateXmlObject {
#[serde(rename = "inner_string")] #[serde(rename = "inner_string")]
@ -217,6 +220,7 @@ impl DuplicateXmlObject {
/// Test a model containing a UUID /// Test a model containing a UUID
#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct UuidObject(uuid::Uuid); pub struct UuidObject(uuid::Uuid);
@ -266,6 +270,7 @@ where
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct XmlArray(#[serde(serialize_with = "wrap_in_camelXmlInner")]Vec<String>); pub struct XmlArray(#[serde(serialize_with = "wrap_in_camelXmlInner")]Vec<String>);
impl ::std::convert::From<Vec<String>> for XmlArray { impl ::std::convert::From<Vec<String>> for XmlArray {
@ -337,6 +342,7 @@ impl XmlArray {
} }
#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
#[serde(rename = "camelXmlInner")] #[serde(rename = "camelXmlInner")]
pub struct XmlInner(String); pub struct XmlInner(String);
@ -384,6 +390,7 @@ impl XmlInner {
/// An XML object /// An XML object
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
#[serde(rename = "camelXmlObject")] #[serde(rename = "camelXmlObject")]
pub struct XmlObject { pub struct XmlObject {
#[serde(rename = "innerString")] #[serde(rename = "innerString")]

View File

@ -7,42 +7,59 @@ license = "Unlicense"
[features] [features]
default = ["client", "server"] default = ["client", "server"]
client = ["serde_json", "serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "url", "uuid"] client = ["serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "url"]
server = ["serde_json", "serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "tokio-proto", "tokio-tls", "regex", "percent-encoding", "url", "uuid"] server = ["serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "tokio-proto", "tokio-tls", "regex", "percent-encoding", "url"]
conversion = ["frunk", "frunk_derives", "frunk_core", "frunk-enum-core", "frunk-enum-derive"]
[dependencies] [dependencies]
# Required by example server. # Common
#
chrono = { version = "0.4", features = ["serde"] } chrono = { version = "0.4", features = ["serde"] }
futures = "0.1" futures = "0.1"
hyper = {version = "0.11", optional = true}
hyper-tls = {version = "0.1.2", optional = true}
swagger = "2" swagger = "2"
# Not required by example server.
#
lazy_static = "0.2" lazy_static = "0.2"
log = "0.3.0" log = "0.3.0"
mime = "0.2.6" mime = "0.2.6"
multipart = {version = "0.13.3"} multipart = "0.13.3"
native-tls = {version = "0.1.4", optional = true}
openssl = {version = "0.9.14", optional = true}
percent-encoding = {version = "1.0.0", optional = true}
regex = {version = "0.2", optional = true}
serde = "1.0" serde = "1.0"
serde_derive = "1.0" serde_derive = "1.0"
serde_json = "1.0"
# Crates included if required by the API definition
# Common between server and client features
hyper = {version = "0.11", optional = true}
hyper-tls = {version = "0.1.2", optional = true}
native-tls = {version = "0.1.4", optional = true}
openssl = {version = "0.9.14", optional = true}
serde_ignored = {version = "0.0.4", optional = true} serde_ignored = {version = "0.0.4", optional = true}
serde_json = {version = "1.0", optional = true}
serde_urlencoded = {version = "0.5.1", optional = true}
tokio-core = {version = "0.1.6", optional = true} tokio-core = {version = "0.1.6", optional = true}
url = {version = "1.5", optional = true}
# Client-specific
# Server-specific
percent-encoding = {version = "1.0.0", optional = true}
regex = {version = "0.2", optional = true}
tokio-proto = {version = "0.1.1", optional = true} tokio-proto = {version = "0.1.1", optional = true}
tokio-tls = {version = "0.1.3", optional = true, features = ["tokio-proto"]} tokio-tls = {version = "0.1.3", optional = true, features = ["tokio-proto"]}
url = {version = "1.5", optional = true}
uuid = {version = "0.5", optional = true, features = ["serde", "v4"]}
# ToDo: this should be updated to point at the official crate once
# https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream
# Other optional crates
frunk = { version = "0.3.0", optional = true }
frunk_derives = { version = "0.3.0", optional = true }
frunk_core = { version = "0.3.0", optional = true }
frunk-enum-derive = { version = "0.2.0", optional = true }
frunk-enum-core = { version = "0.2.0", optional = true }
[dev-dependencies] [dev-dependencies]
clap = "2.25" clap = "2.25"
error-chain = "0.12" error-chain = "0.12"
uuid = {version = "0.5", features = ["serde", "v4"]}
[[example]]
name = "client"
required-features = ["client"]
[[example]]
name = "server"
required-features = ["server"]

View File

@ -3,10 +3,11 @@
No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
## Overview ## Overview
This client/server was generated by the [openapi-generator] This client/server was generated by the [openapi-generator]
(https://openapi-generator.tech) project. (https://openapi-generator.tech) project. By using the
By using the [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote server, you can easily generate a server stub. [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote
- server, you can easily generate a server stub.
To see how to make this your own, look here: To see how to make this your own, look here:
@ -14,6 +15,9 @@ To see how to make this your own, look here:
- API version: 0.0.1 - API version: 0.0.1
This autogenerated project defines an API crate `ops-v3` which contains: This autogenerated project defines an API crate `ops-v3` which contains:
* An `Api` trait defining the API in Rust. * An `Api` trait defining the API in Rust.
* Data types representing the underlying data model. * Data types representing the underlying data model.
@ -21,15 +25,17 @@ This autogenerated project defines an API crate `ops-v3` which contains:
* A router which accepts HTTP requests and invokes the appropriate `Api` method for each operation. * A router which accepts HTTP requests and invokes the appropriate `Api` method for each operation.
It also contains an example server and client which make use of `ops-v3`: It also contains an example server and client which make use of `ops-v3`:
* The example server starts up a web server using the `ops-v3` router,
and supplies a trivial implementation of `Api` which returns failure for every operation. * The example server starts up a web server using the `ops-v3`
* The example client provides a CLI which lets you invoke any single operation on the router, and supplies a trivial implementation of `Api` which returns failure
`ops-v3` client by passing appropriate arguments on the command line. for every operation.
* The example client provides a CLI which lets you invoke
any single operation on the `ops-v3` client by passing appropriate
arguments on the command line.
You can use the example server and client as a basis for your own code. You can use the example server and client as a basis for your own code.
See below for [more detail on implementing a server](#writing-a-server). See below for [more detail on implementing a server](#writing-a-server).
## Examples ## Examples
Run examples with: Run examples with:
@ -44,14 +50,14 @@ To pass in arguments to the examples, put them after `--`, for example:
cargo run --example client -- --help cargo run --example client -- --help
``` ```
### Running the server ### Running the example server
To run the server, follow these simple steps: To run the server, follow these simple steps:
``` ```
cargo run --example server cargo run --example server
``` ```
### Running a client ### Running the example client
To run a client, follow one of the following simple steps: To run a client, follow one of the following simple steps:
``` ```
@ -101,43 +107,23 @@ The examples can be run in HTTPS mode by passing in the flag `--https`, for exam
cargo run --example server -- --https cargo run --example server -- --https
``` ```
This will use the keys/certificates from the examples directory. Note that the server chain is signed with This will use the keys/certificates from the examples directory. Note that the
`CN=localhost`. server chain is signed with `CN=localhost`.
## Using the generated library
## Writing a server The generated library has a few optional features that can be activated through Cargo.
The server example is designed to form the basis for implementing your own server. Simply follow these steps. * `server`
* This defaults to enabled and creates the basic skeleton of a server implementation based on hyper
* To create the server stack you'll need to provide an implementation of the API trait to provide the server function.
* `client`
* This defaults to enabled and creates the basic skeleton of a client implementation based on hyper
* The constructed client implements the API trait by making remote API call.
* `conversions`
* This defaults to disabled and creates extra derives on models to allow "transmogrification" between objects of structurally similar types.
* Set up a new Rust project, e.g., with `cargo init --bin`. See https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section for how to use features in your `Cargo.toml`.
* Insert `ops-v3` into the `members` array under [workspace] in the root `Cargo.toml`, e.g., `members = [ "ops-v3" ]`.
* Add `ops-v3 = {version = "0.0.1", path = "ops-v3"}` under `[dependencies]` in the root `Cargo.toml`.
* Copy the `[dependencies]` and `[dev-dependencies]` from `ops-v3/Cargo.toml` into the root `Cargo.toml`'s `[dependencies]` section.
* Copy all of the `[dev-dependencies]`, but only the `[dependencies]` that are required by the example server. These should be clearly indicated by comments.
* Remove `"optional = true"` from each of these lines if present.
Each autogenerated API will contain an implementation stub and main entry point, which should be copied into your project the first time:
```
cp ops-v3/examples/server.rs src/main.rs
cp ops-v3/examples/server_lib/mod.rs src/lib.rs
cp ops-v3/examples/server_lib/server.rs src/server.rs
```
Now
* From `src/main.rs`, remove the `mod server_lib;` line, and uncomment and fill in the `extern crate` line with the name of this server crate.
* Move the block of imports "required by the service library" from `src/main.rs` to `src/lib.rs` and uncomment.
* Change the `let server = server::Server {};` line to `let server = SERVICE_NAME::server().unwrap();` where `SERVICE_NAME` is the name of the server crate.
* Run `cargo build` to check it builds.
* Run `cargo fmt` to reformat the code.
* Commit the result before making any further changes (lest format changes get confused with your own updates).
Now replace the implementations in `src/server.rs` with your own code as required.
## Updating your server to track API changes
Later, if the API changes, you can copy new sections from the autogenerated API stub into your implementation.
Alternatively, implement the now-missing methods based on the compiler's error messages.
## Documentation for API Endpoints ## Documentation for API Endpoints

View File

@ -7,9 +7,9 @@ extern crate futures;
#[macro_use] #[macro_use]
extern crate swagger; extern crate swagger;
#[allow(unused_extern_crates)] #[allow(unused_extern_crates)]
extern crate uuid;
extern crate clap; extern crate clap;
extern crate tokio_core; extern crate tokio_core;
extern crate uuid;
use swagger::{ContextBuilder, EmptyContext, XSpanIdString, Has, Push, AuthData}; use swagger::{ContextBuilder, EmptyContext, XSpanIdString, Has, Push, AuthData};

View File

@ -21,7 +21,6 @@ extern crate chrono;
#[macro_use] #[macro_use]
extern crate error_chain; extern crate error_chain;
use openssl::x509::X509_FILETYPE_PEM; use openssl::x509::X509_FILETYPE_PEM;
use openssl::ssl::{SslAcceptorBuilder, SslMethod}; use openssl::ssl::{SslAcceptorBuilder, SslMethod};
use openssl::error::ErrorStack; use openssl::error::ErrorStack;

View File

@ -6,7 +6,6 @@ use futures::{self, Future};
use chrono; use chrono;
use std::collections::HashMap; use std::collections::HashMap;
use std::marker::PhantomData; use std::marker::PhantomData;
use swagger; use swagger;
use swagger::{Has, XSpanIdString}; use swagger::{Has, XSpanIdString};

View File

@ -1,40 +1,50 @@
#![allow(missing_docs, trivial_casts, unused_variables, unused_mut, unused_imports, unused_extern_crates, non_camel_case_types)] #![allow(missing_docs, trivial_casts, unused_variables, unused_mut, unused_imports, unused_extern_crates, non_camel_case_types)]
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate futures;
extern crate chrono;
#[macro_use] #[macro_use]
extern crate lazy_static; extern crate lazy_static;
#[macro_use] #[macro_use]
extern crate log; extern crate log;
extern crate mime; #[macro_use]
extern crate serde_derive;
// Logically this should be in the client and server modules, but rust doesn't allow `macro_use` from a module.
#[cfg(any(feature = "client", feature = "server"))] #[cfg(any(feature = "client", feature = "server"))]
#[macro_use] #[macro_use]
extern crate hyper; extern crate hyper;
#[cfg(any(feature = "client", feature = "server"))]
extern crate swagger;
#[macro_use] #[macro_use]
extern crate url; extern crate url;
// Crates for conversion support
#[cfg(feature = "conversion")]
#[macro_use]
extern crate frunk_derives;
#[cfg(feature = "conversion")]
#[macro_use]
extern crate frunk_enum_derive;
#[cfg(feature = "conversion")]
extern crate frunk_core;
extern crate mime;
extern crate serde;
extern crate serde_json;
extern crate futures;
extern crate chrono;
extern crate swagger;
use futures::Stream; use futures::Stream;
use std::io::Error; use std::io::Error;
#[allow(unused_imports)] #[allow(unused_imports)]
use std::collections::HashMap; use std::collections::HashMap;
pub use futures::Future;
#[cfg(any(feature = "client", feature = "server"))] #[cfg(any(feature = "client", feature = "server"))]
mod mimetypes; mod mimetypes;
#[deprecated(note = "Import swagger-rs directly")]
pub use swagger::{ApiError, ContextWrapper}; pub use swagger::{ApiError, ContextWrapper};
#[deprecated(note = "Import futures directly")]
pub use futures::Future;
pub const BASE_PATH: &'static str = ""; pub const BASE_PATH: &'static str = "";
pub const API_VERSION: &'static str = "0.0.1"; pub const API_VERSION: &'static str = "0.0.1";

View File

@ -1,6 +1,5 @@
#![allow(unused_imports, unused_qualifications, unused_extern_crates)] #![allow(unused_imports, unused_qualifications, unused_extern_crates)]
extern crate chrono; extern crate chrono;
extern crate uuid;
use serde::ser::Serializer; use serde::ser::Serializer;
@ -9,4 +8,3 @@ use models;
use swagger; use swagger;
use std::string::ParseError; use std::string::ParseError;

View File

@ -8,7 +8,6 @@ extern crate mime;
extern crate chrono; extern crate chrono;
extern crate percent_encoding; extern crate percent_encoding;
extern crate url; extern crate url;
extern crate uuid;
use std::sync::Arc; use std::sync::Arc;
use std::marker::PhantomData; use std::marker::PhantomData;

View File

@ -7,42 +7,62 @@ license = "Unlicense"
[features] [features]
default = ["client", "server"] default = ["client", "server"]
client = ["serde_json", "serde_urlencoded", "serde-xml-rs", "serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "url", "uuid"] client = ["serde_urlencoded", "serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "url"]
server = ["serde_json", "serde-xml-rs", "serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "tokio-proto", "tokio-tls", "regex", "percent-encoding", "url", "uuid"] server = ["serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "tokio-proto", "tokio-tls", "regex", "percent-encoding", "url"]
conversion = ["frunk", "frunk_derives", "frunk_core", "frunk-enum-core", "frunk-enum-derive"]
[dependencies] [dependencies]
# Required by example server. # Common
#
chrono = { version = "0.4", features = ["serde"] } chrono = { version = "0.4", features = ["serde"] }
futures = "0.1" futures = "0.1"
hyper = {version = "0.11", optional = true}
hyper-tls = {version = "0.1.2", optional = true}
swagger = "2" swagger = "2"
# Not required by example server.
#
lazy_static = "0.2" lazy_static = "0.2"
log = "0.3.0" log = "0.3.0"
mime = "0.2.6" mime = "0.2.6"
multipart = {version = "0.13.3"} multipart = "0.13.3"
native-tls = {version = "0.1.4", optional = true}
openssl = {version = "0.9.14", optional = true}
percent-encoding = {version = "1.0.0", optional = true}
regex = {version = "0.2", optional = true}
serde = "1.0" serde = "1.0"
serde_derive = "1.0" serde_derive = "1.0"
serde_json = "1.0"
# Crates included if required by the API definition
uuid = {version = "0.5", features = ["serde", "v4"]}
# TODO: this should be updated to point at the official crate once
# https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream
serde-xml-rs = {git = "git://github.com/Metaswitch/serde-xml-rs.git" , branch = "master"}
# Common between server and client features
hyper = {version = "0.11", optional = true}
hyper-tls = {version = "0.1.2", optional = true}
native-tls = {version = "0.1.4", optional = true}
openssl = {version = "0.9.14", optional = true}
serde_ignored = {version = "0.0.4", optional = true} serde_ignored = {version = "0.0.4", optional = true}
serde_json = {version = "1.0", optional = true}
serde_urlencoded = {version = "0.5.1", optional = true}
tokio-core = {version = "0.1.6", optional = true} tokio-core = {version = "0.1.6", optional = true}
url = {version = "1.5", optional = true}
# Client-specific
serde_urlencoded = {version = "0.5.1", optional = true}
# Server-specific
percent-encoding = {version = "1.0.0", optional = true}
regex = {version = "0.2", optional = true}
tokio-proto = {version = "0.1.1", optional = true} tokio-proto = {version = "0.1.1", optional = true}
tokio-tls = {version = "0.1.3", optional = true, features = ["tokio-proto"]} tokio-tls = {version = "0.1.3", optional = true, features = ["tokio-proto"]}
url = {version = "1.5", optional = true}
uuid = {version = "0.5", optional = true, features = ["serde", "v4"]} # Other optional crates
# ToDo: this should be updated to point at the official crate once frunk = { version = "0.3.0", optional = true }
# https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream frunk_derives = { version = "0.3.0", optional = true }
serde-xml-rs = {git = "git://github.com/Metaswitch/serde-xml-rs.git" , branch = "master", optional = true} frunk_core = { version = "0.3.0", optional = true }
frunk-enum-derive = { version = "0.2.0", optional = true }
frunk-enum-core = { version = "0.2.0", optional = true }
[dev-dependencies] [dev-dependencies]
clap = "2.25" clap = "2.25"
error-chain = "0.12" error-chain = "0.12"
[[example]]
name = "client"
required-features = ["client"]
[[example]]
name = "server"
required-features = ["server"]

View File

@ -3,10 +3,11 @@
This spec is mainly for testing Petstore server and contains fake endpoints, models. Please do not use this for any other purpose. Special characters: \" \\ This spec is mainly for testing Petstore server and contains fake endpoints, models. Please do not use this for any other purpose. Special characters: \" \\
## Overview ## Overview
This client/server was generated by the [openapi-generator] This client/server was generated by the [openapi-generator]
(https://openapi-generator.tech) project. (https://openapi-generator.tech) project. By using the
By using the [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote server, you can easily generate a server stub. [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote
- server, you can easily generate a server stub.
To see how to make this your own, look here: To see how to make this your own, look here:
@ -14,6 +15,9 @@ To see how to make this your own, look here:
- API version: 1.0.0 - API version: 1.0.0
This autogenerated project defines an API crate `petstore-with-fake-endpoints-models-for-testing` which contains: This autogenerated project defines an API crate `petstore-with-fake-endpoints-models-for-testing` which contains:
* An `Api` trait defining the API in Rust. * An `Api` trait defining the API in Rust.
* Data types representing the underlying data model. * Data types representing the underlying data model.
@ -21,15 +25,17 @@ This autogenerated project defines an API crate `petstore-with-fake-endpoints-mo
* A router which accepts HTTP requests and invokes the appropriate `Api` method for each operation. * A router which accepts HTTP requests and invokes the appropriate `Api` method for each operation.
It also contains an example server and client which make use of `petstore-with-fake-endpoints-models-for-testing`: It also contains an example server and client which make use of `petstore-with-fake-endpoints-models-for-testing`:
* The example server starts up a web server using the `petstore-with-fake-endpoints-models-for-testing` router,
and supplies a trivial implementation of `Api` which returns failure for every operation. * The example server starts up a web server using the `petstore-with-fake-endpoints-models-for-testing`
* The example client provides a CLI which lets you invoke any single operation on the router, and supplies a trivial implementation of `Api` which returns failure
`petstore-with-fake-endpoints-models-for-testing` client by passing appropriate arguments on the command line. for every operation.
* The example client provides a CLI which lets you invoke
any single operation on the `petstore-with-fake-endpoints-models-for-testing` client by passing appropriate
arguments on the command line.
You can use the example server and client as a basis for your own code. You can use the example server and client as a basis for your own code.
See below for [more detail on implementing a server](#writing-a-server). See below for [more detail on implementing a server](#writing-a-server).
## Examples ## Examples
Run examples with: Run examples with:
@ -44,14 +50,14 @@ To pass in arguments to the examples, put them after `--`, for example:
cargo run --example client -- --help cargo run --example client -- --help
``` ```
### Running the server ### Running the example server
To run the server, follow these simple steps: To run the server, follow these simple steps:
``` ```
cargo run --example server cargo run --example server
``` ```
### Running a client ### Running the example client
To run a client, follow one of the following simple steps: To run a client, follow one of the following simple steps:
``` ```
@ -96,43 +102,23 @@ The examples can be run in HTTPS mode by passing in the flag `--https`, for exam
cargo run --example server -- --https cargo run --example server -- --https
``` ```
This will use the keys/certificates from the examples directory. Note that the server chain is signed with This will use the keys/certificates from the examples directory. Note that the
`CN=localhost`. server chain is signed with `CN=localhost`.
## Using the generated library
## Writing a server The generated library has a few optional features that can be activated through Cargo.
The server example is designed to form the basis for implementing your own server. Simply follow these steps. * `server`
* This defaults to enabled and creates the basic skeleton of a server implementation based on hyper
* To create the server stack you'll need to provide an implementation of the API trait to provide the server function.
* `client`
* This defaults to enabled and creates the basic skeleton of a client implementation based on hyper
* The constructed client implements the API trait by making remote API call.
* `conversions`
* This defaults to disabled and creates extra derives on models to allow "transmogrification" between objects of structurally similar types.
* Set up a new Rust project, e.g., with `cargo init --bin`. See https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section for how to use features in your `Cargo.toml`.
* Insert `petstore-with-fake-endpoints-models-for-testing` into the `members` array under [workspace] in the root `Cargo.toml`, e.g., `members = [ "petstore-with-fake-endpoints-models-for-testing" ]`.
* Add `petstore-with-fake-endpoints-models-for-testing = {version = "1.0.0", path = "petstore-with-fake-endpoints-models-for-testing"}` under `[dependencies]` in the root `Cargo.toml`.
* Copy the `[dependencies]` and `[dev-dependencies]` from `petstore-with-fake-endpoints-models-for-testing/Cargo.toml` into the root `Cargo.toml`'s `[dependencies]` section.
* Copy all of the `[dev-dependencies]`, but only the `[dependencies]` that are required by the example server. These should be clearly indicated by comments.
* Remove `"optional = true"` from each of these lines if present.
Each autogenerated API will contain an implementation stub and main entry point, which should be copied into your project the first time:
```
cp petstore-with-fake-endpoints-models-for-testing/examples/server.rs src/main.rs
cp petstore-with-fake-endpoints-models-for-testing/examples/server_lib/mod.rs src/lib.rs
cp petstore-with-fake-endpoints-models-for-testing/examples/server_lib/server.rs src/server.rs
```
Now
* From `src/main.rs`, remove the `mod server_lib;` line, and uncomment and fill in the `extern crate` line with the name of this server crate.
* Move the block of imports "required by the service library" from `src/main.rs` to `src/lib.rs` and uncomment.
* Change the `let server = server::Server {};` line to `let server = SERVICE_NAME::server().unwrap();` where `SERVICE_NAME` is the name of the server crate.
* Run `cargo build` to check it builds.
* Run `cargo fmt` to reformat the code.
* Commit the result before making any further changes (lest format changes get confused with your own updates).
Now replace the implementations in `src/server.rs` with your own code as required.
## Updating your server to track API changes
Later, if the API changes, you can copy new sections from the autogenerated API stub into your implementation.
Alternatively, implement the now-missing methods based on the compiler's error messages.
## Documentation for API Endpoints ## Documentation for API Endpoints

View File

@ -7,9 +7,9 @@ extern crate futures;
#[macro_use] #[macro_use]
extern crate swagger; extern crate swagger;
#[allow(unused_extern_crates)] #[allow(unused_extern_crates)]
extern crate uuid;
extern crate clap; extern crate clap;
extern crate tokio_core; extern crate tokio_core;
extern crate uuid;
use swagger::{ContextBuilder, EmptyContext, XSpanIdString, Has, Push, AuthData}; use swagger::{ContextBuilder, EmptyContext, XSpanIdString, Has, Push, AuthData};

View File

@ -20,7 +20,7 @@ extern crate futures;
extern crate chrono; extern crate chrono;
#[macro_use] #[macro_use]
extern crate error_chain; extern crate error_chain;
extern crate uuid;
use openssl::x509::X509_FILETYPE_PEM; use openssl::x509::X509_FILETYPE_PEM;
use openssl::ssl::{SslAcceptorBuilder, SslMethod}; use openssl::ssl::{SslAcceptorBuilder, SslMethod};

View File

@ -6,9 +6,9 @@ use futures::{self, Future};
use chrono; use chrono;
use std::collections::HashMap; use std::collections::HashMap;
use std::marker::PhantomData; use std::marker::PhantomData;
use swagger; use swagger;
use swagger::{Has, XSpanIdString}; use swagger::{Has, XSpanIdString};
use uuid;
use petstore_with_fake_endpoints_models_for_testing::{Api, ApiError, use petstore_with_fake_endpoints_models_for_testing::{Api, ApiError,
TestSpecialTagsResponse, TestSpecialTagsResponse,

View File

@ -8,6 +8,7 @@ extern crate chrono;
extern crate url; extern crate url;
extern crate serde_urlencoded; extern crate serde_urlencoded;
extern crate multipart; extern crate multipart;
extern crate uuid;
use hyper; use hyper;
use hyper::header::{Headers, ContentType}; use hyper::header::{Headers, ContentType};

View File

@ -1,40 +1,51 @@
#![allow(missing_docs, trivial_casts, unused_variables, unused_mut, unused_imports, unused_extern_crates, non_camel_case_types)] #![allow(missing_docs, trivial_casts, unused_variables, unused_mut, unused_imports, unused_extern_crates, non_camel_case_types)]
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serde_xml_rs;
extern crate futures;
extern crate chrono;
#[macro_use] #[macro_use]
extern crate lazy_static; extern crate lazy_static;
#[macro_use] #[macro_use]
extern crate log; extern crate log;
extern crate mime; #[macro_use]
extern crate serde_derive;
// Logically this should be in the client and server modules, but rust doesn't allow `macro_use` from a module.
#[cfg(any(feature = "client", feature = "server"))] #[cfg(any(feature = "client", feature = "server"))]
#[macro_use] #[macro_use]
extern crate hyper; extern crate hyper;
#[cfg(any(feature = "client", feature = "server"))]
extern crate swagger;
#[macro_use] #[macro_use]
extern crate url; extern crate url;
// Crates for conversion support
#[cfg(feature = "conversion")]
#[macro_use]
extern crate frunk_derives;
#[cfg(feature = "conversion")]
#[macro_use]
extern crate frunk_enum_derive;
#[cfg(feature = "conversion")]
extern crate frunk_core;
extern crate mime;
extern crate serde;
extern crate serde_json;
extern crate serde_xml_rs;
extern crate futures;
extern crate chrono;
extern crate swagger;
extern crate uuid;
use futures::Stream; use futures::Stream;
use std::io::Error; use std::io::Error;
#[allow(unused_imports)] #[allow(unused_imports)]
use std::collections::HashMap; use std::collections::HashMap;
pub use futures::Future;
#[cfg(any(feature = "client", feature = "server"))] #[cfg(any(feature = "client", feature = "server"))]
mod mimetypes; mod mimetypes;
#[deprecated(note = "Import swagger-rs directly")]
pub use swagger::{ApiError, ContextWrapper}; pub use swagger::{ApiError, ContextWrapper};
#[deprecated(note = "Import futures directly")]
pub use futures::Future;
pub const BASE_PATH: &'static str = "/v2"; pub const BASE_PATH: &'static str = "/v2";
pub const API_VERSION: &'static str = "1.0.0"; pub const API_VERSION: &'static str = "1.0.0";

View File

@ -1,6 +1,5 @@
#![allow(unused_imports, unused_qualifications, unused_extern_crates)] #![allow(unused_imports, unused_qualifications, unused_extern_crates)]
extern crate chrono; extern crate chrono;
extern crate uuid;
use serde_xml_rs; use serde_xml_rs;
use serde::ser::Serializer; use serde::ser::Serializer;
@ -9,10 +8,11 @@ use std::collections::{HashMap, BTreeMap};
use models; use models;
use swagger; use swagger;
use std::string::ParseError; use std::string::ParseError;
use uuid;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct AdditionalPropertiesClass { pub struct AdditionalPropertiesClass {
#[serde(rename = "map_property")] #[serde(rename = "map_property")]
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if="Option::is_none")]
@ -43,6 +43,7 @@ impl AdditionalPropertiesClass {
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct Animal { pub struct Animal {
#[serde(rename = "className")] #[serde(rename = "className")]
pub class_name: String, pub class_name: String,
@ -72,6 +73,7 @@ impl Animal {
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct AnimalFarm(Vec<Animal>); pub struct AnimalFarm(Vec<Animal>);
impl ::std::convert::From<Vec<Animal>> for AnimalFarm { impl ::std::convert::From<Vec<Animal>> for AnimalFarm {
@ -143,6 +145,7 @@ impl AnimalFarm {
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct ApiResponse { pub struct ApiResponse {
#[serde(rename = "code")] #[serde(rename = "code")]
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if="Option::is_none")]
@ -178,6 +181,7 @@ impl ApiResponse {
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct ArrayOfArrayOfNumberOnly { pub struct ArrayOfArrayOfNumberOnly {
#[serde(rename = "ArrayArrayNumber")] #[serde(rename = "ArrayArrayNumber")]
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if="Option::is_none")]
@ -203,6 +207,7 @@ impl ArrayOfArrayOfNumberOnly {
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct ArrayOfNumberOnly { pub struct ArrayOfNumberOnly {
#[serde(rename = "ArrayNumber")] #[serde(rename = "ArrayNumber")]
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if="Option::is_none")]
@ -228,6 +233,7 @@ impl ArrayOfNumberOnly {
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct ArrayTest { pub struct ArrayTest {
#[serde(rename = "array_of_string")] #[serde(rename = "array_of_string")]
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if="Option::is_none")]
@ -269,6 +275,7 @@ impl ArrayTest {
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct Capitalization { pub struct Capitalization {
#[serde(rename = "smallCamel")] #[serde(rename = "smallCamel")]
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if="Option::is_none")]
@ -320,6 +327,7 @@ impl Capitalization {
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct Cat { pub struct Cat {
#[serde(rename = "className")] #[serde(rename = "className")]
pub class_name: String, pub class_name: String,
@ -354,6 +362,7 @@ impl Cat {
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct CatAllOf { pub struct CatAllOf {
#[serde(rename = "declawed")] #[serde(rename = "declawed")]
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if="Option::is_none")]
@ -379,6 +388,7 @@ impl CatAllOf {
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
#[serde(rename = "Category")] #[serde(rename = "Category")]
pub struct Category { pub struct Category {
#[serde(rename = "id")] #[serde(rename = "id")]
@ -411,6 +421,7 @@ impl Category {
/// Model for testing model with \"_class\" property /// Model for testing model with \"_class\" property
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct ClassModel { pub struct ClassModel {
#[serde(rename = "_class")] #[serde(rename = "_class")]
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if="Option::is_none")]
@ -436,6 +447,7 @@ impl ClassModel {
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct Client { pub struct Client {
#[serde(rename = "client")] #[serde(rename = "client")]
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if="Option::is_none")]
@ -461,6 +473,7 @@ impl Client {
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct Dog { pub struct Dog {
#[serde(rename = "className")] #[serde(rename = "className")]
pub class_name: String, pub class_name: String,
@ -495,6 +508,7 @@ impl Dog {
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct DogAllOf { pub struct DogAllOf {
#[serde(rename = "breed")] #[serde(rename = "breed")]
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if="Option::is_none")]
@ -520,6 +534,7 @@ impl DogAllOf {
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct EnumArrays { pub struct EnumArrays {
// Note: inline enums are not fully supported by openapi-generator // Note: inline enums are not fully supported by openapi-generator
#[serde(rename = "just_symbol")] #[serde(rename = "just_symbol")]
@ -562,7 +577,8 @@ impl EnumArrays {
/// which helps with FFI. /// which helps with FFI.
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Serialize, Deserialize, Eq, Ord)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGenericEnum))]
pub enum EnumClass { pub enum EnumClass {
#[serde(rename = "_abc")] #[serde(rename = "_abc")]
_ABC, _ABC,
@ -604,6 +620,7 @@ impl EnumClass {
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct EnumTest { pub struct EnumTest {
// Note: inline enums are not fully supported by openapi-generator // Note: inline enums are not fully supported by openapi-generator
#[serde(rename = "enum_string")] #[serde(rename = "enum_string")]
@ -652,6 +669,7 @@ impl EnumTest {
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct FormatTest { pub struct FormatTest {
#[serde(rename = "integer")] #[serde(rename = "integer")]
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if="Option::is_none")]
@ -733,6 +751,7 @@ impl FormatTest {
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct HasOnlyReadOnly { pub struct HasOnlyReadOnly {
#[serde(rename = "bar")] #[serde(rename = "bar")]
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if="Option::is_none")]
@ -763,6 +782,7 @@ impl HasOnlyReadOnly {
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct List { pub struct List {
#[serde(rename = "123-list")] #[serde(rename = "123-list")]
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if="Option::is_none")]
@ -788,6 +808,7 @@ impl List {
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct MapTest { pub struct MapTest {
#[serde(rename = "map_map_of_string")] #[serde(rename = "map_map_of_string")]
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if="Option::is_none")]
@ -825,6 +846,7 @@ impl MapTest {
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct MixedPropertiesAndAdditionalPropertiesClass { pub struct MixedPropertiesAndAdditionalPropertiesClass {
#[serde(rename = "uuid")] #[serde(rename = "uuid")]
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if="Option::is_none")]
@ -861,6 +883,7 @@ impl MixedPropertiesAndAdditionalPropertiesClass {
/// Model for testing model name starting with number /// Model for testing model name starting with number
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
#[serde(rename = "Name")] #[serde(rename = "Name")]
pub struct Model200Response { pub struct Model200Response {
#[serde(rename = "name")] #[serde(rename = "name")]
@ -893,6 +916,7 @@ impl Model200Response {
/// Model for testing reserved words /// Model for testing reserved words
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
#[serde(rename = "Return")] #[serde(rename = "Return")]
pub struct ModelReturn { pub struct ModelReturn {
#[serde(rename = "return")] #[serde(rename = "return")]
@ -920,6 +944,7 @@ impl ModelReturn {
/// Model for testing model name same as property name /// Model for testing model name same as property name
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
#[serde(rename = "Name")] #[serde(rename = "Name")]
pub struct Name { pub struct Name {
#[serde(rename = "name")] #[serde(rename = "name")]
@ -960,6 +985,7 @@ impl Name {
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct NumberOnly { pub struct NumberOnly {
#[serde(rename = "JustNumber")] #[serde(rename = "JustNumber")]
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if="Option::is_none")]
@ -985,6 +1011,7 @@ impl NumberOnly {
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
#[serde(rename = "Order")] #[serde(rename = "Order")]
pub struct Order { pub struct Order {
#[serde(rename = "id")] #[serde(rename = "id")]
@ -1038,6 +1065,7 @@ impl Order {
} }
#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct OuterBoolean(bool); pub struct OuterBoolean(bool);
@ -1078,6 +1106,7 @@ impl OuterBoolean {
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct OuterComposite { pub struct OuterComposite {
#[serde(rename = "my_number")] #[serde(rename = "my_number")]
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if="Option::is_none")]
@ -1117,7 +1146,8 @@ impl OuterComposite {
/// which helps with FFI. /// which helps with FFI.
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Serialize, Deserialize, Eq, Ord)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGenericEnum))]
pub enum OuterEnum { pub enum OuterEnum {
#[serde(rename = "placed")] #[serde(rename = "placed")]
PLACED, PLACED,
@ -1159,6 +1189,7 @@ impl OuterEnum {
} }
#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct OuterNumber(f64); pub struct OuterNumber(f64);
@ -1199,6 +1230,7 @@ impl OuterNumber {
} }
#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct OuterString(String); pub struct OuterString(String);
@ -1245,6 +1277,7 @@ impl OuterString {
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
#[serde(rename = "Pet")] #[serde(rename = "Pet")]
pub struct Pet { pub struct Pet {
#[serde(rename = "id")] #[serde(rename = "id")]
@ -1296,6 +1329,7 @@ impl Pet {
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct ReadOnlyFirst { pub struct ReadOnlyFirst {
#[serde(rename = "bar")] #[serde(rename = "bar")]
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if="Option::is_none")]
@ -1326,6 +1360,7 @@ impl ReadOnlyFirst {
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
#[serde(rename = "$special[model.name]")] #[serde(rename = "$special[model.name]")]
pub struct SpecialModelName { pub struct SpecialModelName {
#[serde(rename = "$special[property.name]")] #[serde(rename = "$special[property.name]")]
@ -1352,6 +1387,7 @@ impl SpecialModelName {
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
#[serde(rename = "Tag")] #[serde(rename = "Tag")]
pub struct Tag { pub struct Tag {
#[serde(rename = "id")] #[serde(rename = "id")]
@ -1383,6 +1419,7 @@ impl Tag {
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
#[serde(rename = "User")] #[serde(rename = "User")]
pub struct User { pub struct User {
#[serde(rename = "id")] #[serde(rename = "id")]

View File

@ -7,42 +7,59 @@ license = "Unlicense"
[features] [features]
default = ["client", "server"] default = ["client", "server"]
client = ["serde_json", "serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "url", "uuid"] client = ["serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "url"]
server = ["serde_json", "serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "tokio-proto", "tokio-tls", "regex", "percent-encoding", "url", "uuid"] server = ["serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio-core", "tokio-proto", "tokio-tls", "regex", "percent-encoding", "url"]
conversion = ["frunk", "frunk_derives", "frunk_core", "frunk-enum-core", "frunk-enum-derive"]
[dependencies] [dependencies]
# Required by example server. # Common
#
chrono = { version = "0.4", features = ["serde"] } chrono = { version = "0.4", features = ["serde"] }
futures = "0.1" futures = "0.1"
hyper = {version = "0.11", optional = true}
hyper-tls = {version = "0.1.2", optional = true}
swagger = "2" swagger = "2"
# Not required by example server.
#
lazy_static = "0.2" lazy_static = "0.2"
log = "0.3.0" log = "0.3.0"
mime = "0.2.6" mime = "0.2.6"
multipart = {version = "0.13.3"} multipart = "0.13.3"
native-tls = {version = "0.1.4", optional = true}
openssl = {version = "0.9.14", optional = true}
percent-encoding = {version = "1.0.0", optional = true}
regex = {version = "0.2", optional = true}
serde = "1.0" serde = "1.0"
serde_derive = "1.0" serde_derive = "1.0"
serde_json = "1.0"
# Crates included if required by the API definition
# Common between server and client features
hyper = {version = "0.11", optional = true}
hyper-tls = {version = "0.1.2", optional = true}
native-tls = {version = "0.1.4", optional = true}
openssl = {version = "0.9.14", optional = true}
serde_ignored = {version = "0.0.4", optional = true} serde_ignored = {version = "0.0.4", optional = true}
serde_json = {version = "1.0", optional = true}
serde_urlencoded = {version = "0.5.1", optional = true}
tokio-core = {version = "0.1.6", optional = true} tokio-core = {version = "0.1.6", optional = true}
url = {version = "1.5", optional = true}
# Client-specific
# Server-specific
percent-encoding = {version = "1.0.0", optional = true}
regex = {version = "0.2", optional = true}
tokio-proto = {version = "0.1.1", optional = true} tokio-proto = {version = "0.1.1", optional = true}
tokio-tls = {version = "0.1.3", optional = true, features = ["tokio-proto"]} tokio-tls = {version = "0.1.3", optional = true, features = ["tokio-proto"]}
url = {version = "1.5", optional = true}
uuid = {version = "0.5", optional = true, features = ["serde", "v4"]}
# ToDo: this should be updated to point at the official crate once
# https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream
# Other optional crates
frunk = { version = "0.3.0", optional = true }
frunk_derives = { version = "0.3.0", optional = true }
frunk_core = { version = "0.3.0", optional = true }
frunk-enum-derive = { version = "0.2.0", optional = true }
frunk-enum-core = { version = "0.2.0", optional = true }
[dev-dependencies] [dev-dependencies]
clap = "2.25" clap = "2.25"
error-chain = "0.12" error-chain = "0.12"
uuid = {version = "0.5", features = ["serde", "v4"]}
[[example]]
name = "client"
required-features = ["client"]
[[example]]
name = "server"
required-features = ["server"]

View File

@ -3,10 +3,11 @@
This spec is for testing rust-server-specific things This spec is for testing rust-server-specific things
## Overview ## Overview
This client/server was generated by the [openapi-generator] This client/server was generated by the [openapi-generator]
(https://openapi-generator.tech) project. (https://openapi-generator.tech) project. By using the
By using the [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote server, you can easily generate a server stub. [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote
- server, you can easily generate a server stub.
To see how to make this your own, look here: To see how to make this your own, look here:
@ -14,6 +15,9 @@ To see how to make this your own, look here:
- API version: 2.3.4 - API version: 2.3.4
This autogenerated project defines an API crate `rust-server-test` which contains: This autogenerated project defines an API crate `rust-server-test` which contains:
* An `Api` trait defining the API in Rust. * An `Api` trait defining the API in Rust.
* Data types representing the underlying data model. * Data types representing the underlying data model.
@ -21,15 +25,17 @@ This autogenerated project defines an API crate `rust-server-test` which contain
* A router which accepts HTTP requests and invokes the appropriate `Api` method for each operation. * A router which accepts HTTP requests and invokes the appropriate `Api` method for each operation.
It also contains an example server and client which make use of `rust-server-test`: It also contains an example server and client which make use of `rust-server-test`:
* The example server starts up a web server using the `rust-server-test` router,
and supplies a trivial implementation of `Api` which returns failure for every operation. * The example server starts up a web server using the `rust-server-test`
* The example client provides a CLI which lets you invoke any single operation on the router, and supplies a trivial implementation of `Api` which returns failure
`rust-server-test` client by passing appropriate arguments on the command line. for every operation.
* The example client provides a CLI which lets you invoke
any single operation on the `rust-server-test` client by passing appropriate
arguments on the command line.
You can use the example server and client as a basis for your own code. You can use the example server and client as a basis for your own code.
See below for [more detail on implementing a server](#writing-a-server). See below for [more detail on implementing a server](#writing-a-server).
## Examples ## Examples
Run examples with: Run examples with:
@ -44,14 +50,14 @@ To pass in arguments to the examples, put them after `--`, for example:
cargo run --example client -- --help cargo run --example client -- --help
``` ```
### Running the server ### Running the example server
To run the server, follow these simple steps: To run the server, follow these simple steps:
``` ```
cargo run --example server cargo run --example server
``` ```
### Running a client ### Running the example client
To run a client, follow one of the following simple steps: To run a client, follow one of the following simple steps:
``` ```
@ -69,43 +75,23 @@ The examples can be run in HTTPS mode by passing in the flag `--https`, for exam
cargo run --example server -- --https cargo run --example server -- --https
``` ```
This will use the keys/certificates from the examples directory. Note that the server chain is signed with This will use the keys/certificates from the examples directory. Note that the
`CN=localhost`. server chain is signed with `CN=localhost`.
## Using the generated library
## Writing a server The generated library has a few optional features that can be activated through Cargo.
The server example is designed to form the basis for implementing your own server. Simply follow these steps. * `server`
* This defaults to enabled and creates the basic skeleton of a server implementation based on hyper
* To create the server stack you'll need to provide an implementation of the API trait to provide the server function.
* `client`
* This defaults to enabled and creates the basic skeleton of a client implementation based on hyper
* The constructed client implements the API trait by making remote API call.
* `conversions`
* This defaults to disabled and creates extra derives on models to allow "transmogrification" between objects of structurally similar types.
* Set up a new Rust project, e.g., with `cargo init --bin`. See https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section for how to use features in your `Cargo.toml`.
* Insert `rust-server-test` into the `members` array under [workspace] in the root `Cargo.toml`, e.g., `members = [ "rust-server-test" ]`.
* Add `rust-server-test = {version = "2.3.4", path = "rust-server-test"}` under `[dependencies]` in the root `Cargo.toml`.
* Copy the `[dependencies]` and `[dev-dependencies]` from `rust-server-test/Cargo.toml` into the root `Cargo.toml`'s `[dependencies]` section.
* Copy all of the `[dev-dependencies]`, but only the `[dependencies]` that are required by the example server. These should be clearly indicated by comments.
* Remove `"optional = true"` from each of these lines if present.
Each autogenerated API will contain an implementation stub and main entry point, which should be copied into your project the first time:
```
cp rust-server-test/examples/server.rs src/main.rs
cp rust-server-test/examples/server_lib/mod.rs src/lib.rs
cp rust-server-test/examples/server_lib/server.rs src/server.rs
```
Now
* From `src/main.rs`, remove the `mod server_lib;` line, and uncomment and fill in the `extern crate` line with the name of this server crate.
* Move the block of imports "required by the service library" from `src/main.rs` to `src/lib.rs` and uncomment.
* Change the `let server = server::Server {};` line to `let server = SERVICE_NAME::server().unwrap();` where `SERVICE_NAME` is the name of the server crate.
* Run `cargo build` to check it builds.
* Run `cargo fmt` to reformat the code.
* Commit the result before making any further changes (lest format changes get confused with your own updates).
Now replace the implementations in `src/server.rs` with your own code as required.
## Updating your server to track API changes
Later, if the API changes, you can copy new sections from the autogenerated API stub into your implementation.
Alternatively, implement the now-missing methods based on the compiler's error messages.
## Documentation for API Endpoints ## Documentation for API Endpoints

View File

@ -7,9 +7,9 @@ extern crate futures;
#[macro_use] #[macro_use]
extern crate swagger; extern crate swagger;
#[allow(unused_extern_crates)] #[allow(unused_extern_crates)]
extern crate uuid;
extern crate clap; extern crate clap;
extern crate tokio_core; extern crate tokio_core;
extern crate uuid;
use swagger::{ContextBuilder, EmptyContext, XSpanIdString, Has, Push, AuthData}; use swagger::{ContextBuilder, EmptyContext, XSpanIdString, Has, Push, AuthData};

View File

@ -21,7 +21,6 @@ extern crate chrono;
#[macro_use] #[macro_use]
extern crate error_chain; extern crate error_chain;
use openssl::x509::X509_FILETYPE_PEM; use openssl::x509::X509_FILETYPE_PEM;
use openssl::ssl::{SslAcceptorBuilder, SslMethod}; use openssl::ssl::{SslAcceptorBuilder, SslMethod};
use openssl::error::ErrorStack; use openssl::error::ErrorStack;

View File

@ -6,7 +6,6 @@ use futures::{self, Future};
use chrono; use chrono;
use std::collections::HashMap; use std::collections::HashMap;
use std::marker::PhantomData; use std::marker::PhantomData;
use swagger; use swagger;
use swagger::{Has, XSpanIdString}; use swagger::{Has, XSpanIdString};

View File

@ -1,40 +1,50 @@
#![allow(missing_docs, trivial_casts, unused_variables, unused_mut, unused_imports, unused_extern_crates, non_camel_case_types)] #![allow(missing_docs, trivial_casts, unused_variables, unused_mut, unused_imports, unused_extern_crates, non_camel_case_types)]
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate futures;
extern crate chrono;
#[macro_use] #[macro_use]
extern crate lazy_static; extern crate lazy_static;
#[macro_use] #[macro_use]
extern crate log; extern crate log;
extern crate mime; #[macro_use]
extern crate serde_derive;
// Logically this should be in the client and server modules, but rust doesn't allow `macro_use` from a module.
#[cfg(any(feature = "client", feature = "server"))] #[cfg(any(feature = "client", feature = "server"))]
#[macro_use] #[macro_use]
extern crate hyper; extern crate hyper;
#[cfg(any(feature = "client", feature = "server"))]
extern crate swagger;
#[macro_use] #[macro_use]
extern crate url; extern crate url;
// Crates for conversion support
#[cfg(feature = "conversion")]
#[macro_use]
extern crate frunk_derives;
#[cfg(feature = "conversion")]
#[macro_use]
extern crate frunk_enum_derive;
#[cfg(feature = "conversion")]
extern crate frunk_core;
extern crate mime;
extern crate serde;
extern crate serde_json;
extern crate futures;
extern crate chrono;
extern crate swagger;
use futures::Stream; use futures::Stream;
use std::io::Error; use std::io::Error;
#[allow(unused_imports)] #[allow(unused_imports)]
use std::collections::HashMap; use std::collections::HashMap;
pub use futures::Future;
#[cfg(any(feature = "client", feature = "server"))] #[cfg(any(feature = "client", feature = "server"))]
mod mimetypes; mod mimetypes;
#[deprecated(note = "Import swagger-rs directly")]
pub use swagger::{ApiError, ContextWrapper}; pub use swagger::{ApiError, ContextWrapper};
#[deprecated(note = "Import futures directly")]
pub use futures::Future;
pub const BASE_PATH: &'static str = ""; pub const BASE_PATH: &'static str = "";
pub const API_VERSION: &'static str = "2.3.4"; pub const API_VERSION: &'static str = "2.3.4";

View File

@ -1,6 +1,5 @@
#![allow(unused_imports, unused_qualifications, unused_extern_crates)] #![allow(unused_imports, unused_qualifications, unused_extern_crates)]
extern crate chrono; extern crate chrono;
extern crate uuid;
use serde::ser::Serializer; use serde::ser::Serializer;
@ -10,8 +9,8 @@ use swagger;
use std::string::ParseError; use std::string::ParseError;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct ANullableContainer { pub struct ANullableContainer {
#[serde(rename = "NullableThing")] #[serde(rename = "NullableThing")]
#[serde(deserialize_with = "swagger::nullable_format::deserialize_optional_nullable")] #[serde(deserialize_with = "swagger::nullable_format::deserialize_optional_nullable")]
@ -36,6 +35,7 @@ impl ANullableContainer {
/// An additionalPropertiesObject /// An additionalPropertiesObject
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct AdditionalPropertiesObject { pub struct AdditionalPropertiesObject {
} }
@ -48,6 +48,7 @@ impl AdditionalPropertiesObject {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct InlineObject { pub struct InlineObject {
#[serde(rename = "id")] #[serde(rename = "id")]
pub id: String, pub id: String,
@ -70,6 +71,7 @@ impl InlineObject {
/// An object of objects /// An object of objects
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct ObjectOfObjects { pub struct ObjectOfObjects {
#[serde(rename = "inner")] #[serde(rename = "inner")]
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if="Option::is_none")]
@ -87,6 +89,7 @@ impl ObjectOfObjects {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
pub struct ObjectOfObjectsInner { pub struct ObjectOfObjectsInner {
#[serde(rename = "required_thing")] #[serde(rename = "required_thing")]
pub required_thing: String, pub required_thing: String,

View File

@ -8,7 +8,6 @@ extern crate mime;
extern crate chrono; extern crate chrono;
extern crate percent_encoding; extern crate percent_encoding;
extern crate url; extern crate url;
extern crate uuid;
use std::sync::Arc; use std::sync::Arc;
use std::marker::PhantomData; use std::marker::PhantomData;