Skip to content

Commit

Permalink
support v3.1 spec
Browse files Browse the repository at this point in the history
  • Loading branch information
SVilgelm committed Mar 18, 2024
1 parent 2ff5ccf commit 0cdb6fb
Show file tree
Hide file tree
Showing 42 changed files with 10,231 additions and 34 deletions.
10 changes: 6 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "roas"
version = "0.2.2"
version = "0.3.0"
edition = "2021"
authors = ["Sergey Vilgelm <[email protected]>"]
description = "Rust OpenAPI Specification"
Expand All @@ -16,13 +16,15 @@ include = ["src", "Cargo.toml", "README.md", "LICENSE-APACHE", "LICENSE-MIT", "d
dependencies-license-file = "dependencies-license.json"

[features]
default = ["v3_0"]
default = ["v3_1"]
v2 = []
v3_0 = []
v3_1 = []

[dependencies]
enumset = { version = "1.1.3" }
monostate = "0.1.11"
regex = { version = "1.10.3" }
serde = { version = "1.0.197", features = ["derive"] }
serde_json = { version = "1.0.114" }
regex = { version = "1.10.3" }
enumset = { version = "1.1.3" }
thiserror = { version = "1.0.58" }
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,21 @@ Parsing and generating OpenAPI Specification:

* [x] OpenAPI Specification v2.0
* [x] OpenAPI Specification v3.0.X
* [ ] OpenAPI Specification v3.0.0
* [x] OpenAPI Specification v3.1.X

## Usage

Add this to your `Cargo.toml`:

```toml
[dependencies]
roas = { version = "0.2", features = ["v3_0"] }
roas = "0.3"
```

## Examples

```rust
use roas::v3_0::spec::Spec;
use roas::v3_1::spec::Spec;
use roas::validation::{Options, Validate};

...
Expand Down
17 changes: 17 additions & 0 deletions src/common/bool_or.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::common::helpers::{Context, ValidateWithContext};
use crate::common::reference::{RefOr, ResolveReference};
use serde::{Deserialize, Serialize};

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
Expand All @@ -7,6 +9,21 @@ pub enum BoolOr<T> {
Item(T),
}

impl<D> BoolOr<RefOr<Box<D>>> {
pub fn validate_with_context_boxed<T>(&self, ctx: &mut Context<T>, path: String)
where
T: ResolveReference<D>,
D: ValidateWithContext<T>,
{
match self {
BoolOr::Bool(_) => {}

Check warning on line 19 in src/common/bool_or.rs

View check run for this annotation

Codecov / codecov/patch

src/common/bool_or.rs#L19

Added line #L19 was not covered by tests
BoolOr::Item(d) => {
d.validate_with_context_boxed(ctx, path);
}
}
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
10 changes: 10 additions & 0 deletions src/common/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,13 @@ pub fn validate_optional_string_matches<T>(
validate_string_matches(s, pattern, ctx, path);
}
}

pub fn validate_pattern<T>(pattern: &str, ctx: &mut Context<T>, path: String) {
match Regex::new(pattern) {
Ok(_) => {}
Err(e) => ctx.error(
path,
format_args!("pattern `{}` is invalid: {}", pattern, e),
),

Check warning on line 145 in src/common/helpers.rs

View check run for this annotation

Codecov / codecov/patch

src/common/helpers.rs#L139-L145

Added lines #L139 - L145 were not covered by tests
}
}

Check warning on line 147 in src/common/helpers.rs

View check run for this annotation

Codecov / codecov/patch

src/common/helpers.rs#L147

Added line #L147 was not covered by tests
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@ pub mod v2;

#[cfg(feature = "v3_0")]
pub mod v3_0;

#[cfg(feature = "v3_1")]
pub mod v3_1;
59 changes: 53 additions & 6 deletions src/v2/schema.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Schema Object

use monostate::MustBe;
use std::collections::BTreeMap;
use std::fmt::{Display, Formatter};

Expand All @@ -14,7 +15,7 @@ use crate::v2::spec::Spec;
use crate::v2::xml::XML;

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[serde(tag = "type")]
#[serde(untagged)]
pub enum Schema {
#[serde(rename = "string")]
String(StringSchema),
Expand All @@ -31,11 +32,11 @@ pub enum Schema {
#[serde(rename = "array")]
Array(ArraySchema),

#[serde(rename = "object")]
Object(ObjectSchema),

#[serde(rename = "bull")]
#[serde(rename = "null")]
Null(NullSchema),

#[serde(rename = "object")]
Object(ObjectSchema), // must be last
}

impl Default for Schema {
Expand All @@ -60,6 +61,9 @@ impl Display for Schema {

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct StringSchema {
#[serde(rename = "type")]
_type: MustBe!("string"),

/// A title to explain the purpose of the schema.
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
Expand Down Expand Up @@ -134,6 +138,9 @@ pub struct StringSchema {

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct IntegerSchema {
#[serde(rename = "type")]
_type: MustBe!("integer"),

/// A title to explain the purpose of the schema.
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
Expand Down Expand Up @@ -217,6 +224,9 @@ pub struct IntegerSchema {

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct NumberSchema {
#[serde(rename = "type")]
_type: MustBe!("number"),

/// A title to explain the purpose of the schema.
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
Expand Down Expand Up @@ -300,6 +310,9 @@ pub struct NumberSchema {

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct BooleanSchema {
#[serde(rename = "type")]
_type: MustBe!("boolean"),

/// A title to explain the purpose of the schema.
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
Expand Down Expand Up @@ -351,6 +364,9 @@ pub struct BooleanSchema {

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct ArraySchema {
#[serde(rename = "type")]
_type: MustBe!("array"),

/// A title to explain the purpose of the schema.
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
Expand Down Expand Up @@ -417,8 +433,12 @@ pub struct ArraySchema {
pub extensions: Option<BTreeMap<String, serde_json::Value>>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct ObjectSchema {
#[serde(rename = "type")]
#[serde(default)]
_type: String,

/// A title to explain the purpose of the schema.
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
Expand Down Expand Up @@ -506,8 +526,34 @@ pub struct ObjectSchema {
pub extensions: Option<BTreeMap<String, serde_json::Value>>,
}

impl Default for ObjectSchema {
fn default() -> Self {
ObjectSchema {
_type: "object".to_owned(),
title: None,
description: None,
properties: None,
default: None,
max_properties: None,
min_properties: None,
additional_properties: None,
required: None,
discriminator: None,
read_only: None,
xml: None,
external_docs: None,
example: None,
all_of: None,
extensions: None,
}
}
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct NullSchema {
#[serde(rename = "null")]
_type: MustBe!("string"),

/// A title to explain the purpose of the schema.
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
Expand Down Expand Up @@ -797,6 +843,7 @@ mod tests {
},
{
"title": "foo",
"type": "object",
},
],
}),
Expand Down
58 changes: 51 additions & 7 deletions src/v3_0/schema.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Schema Object

use monostate::MustBe;
use std::collections::BTreeMap;
use std::fmt::{Display, Formatter};

Expand All @@ -17,11 +18,11 @@ use crate::v3_0::xml::XML;
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(untagged)]
pub enum Schema {
Single(SingleSchema),
AllOf(AllOfSchema),
AnyOf(AnyOfSchema),
OneOf(OneOfSchema),
Not(NotSchema),
Single(SingleSchema), // must be last
}

impl Default for Schema {
Expand Down Expand Up @@ -112,7 +113,7 @@ pub struct NotSchema {
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[serde(tag = "type")]
#[serde(untagged)]
pub enum SingleSchema {
#[serde(rename = "string")]
String(StringSchema),
Expand All @@ -129,11 +130,11 @@ pub enum SingleSchema {
#[serde(rename = "array")]
Array(ArraySchema),

#[serde(rename = "null")]
Null(NullSchema),

#[serde(rename = "object")]
Object(ObjectSchema),

#[serde(rename = "bull")]
Null(NullSchema),
}

impl Default for SingleSchema {
Expand All @@ -158,6 +159,9 @@ impl Display for SingleSchema {

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct StringSchema {
#[serde(rename = "type")]
_type: MustBe!("string"),

/// A title to explain the purpose of the schema.
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
Expand Down Expand Up @@ -232,6 +236,9 @@ pub struct StringSchema {

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct IntegerSchema {
#[serde(rename = "type")]
_type: MustBe!("integer"),

/// A title to explain the purpose of the schema.
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
Expand Down Expand Up @@ -315,6 +322,9 @@ pub struct IntegerSchema {

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct NumberSchema {
#[serde(rename = "type")]
_type: MustBe!("number"),

/// A title to explain the purpose of the schema.
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
Expand Down Expand Up @@ -398,6 +408,9 @@ pub struct NumberSchema {

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct BooleanSchema {
#[serde(rename = "type")]
_type: MustBe!("boolean"),

/// A title to explain the purpose of the schema.
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
Expand Down Expand Up @@ -449,6 +462,9 @@ pub struct BooleanSchema {

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct ArraySchema {
#[serde(rename = "type")]
_type: MustBe!("array"),

/// A title to explain the purpose of the schema.
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
Expand Down Expand Up @@ -515,8 +531,12 @@ pub struct ArraySchema {
pub extensions: Option<BTreeMap<String, serde_json::Value>>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct ObjectSchema {
#[serde(rename = "type")]
#[serde(default)]
_type: String,

/// A title to explain the purpose of the schema.
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
Expand All @@ -531,7 +551,7 @@ pub struct ObjectSchema {

/// Declares the values of the header that the server will use if none is provided.
#[serde(skip_serializing_if = "Option::is_none")]
pub default: Option<Vec<serde_json::Value>>,
pub default: Option<BTreeMap<String, serde_json::Value>>,

/// Declares the maximum number of items that are allowed in the array.
#[serde(rename = "maxProperties")]
Expand Down Expand Up @@ -589,8 +609,32 @@ pub struct ObjectSchema {
pub extensions: Option<BTreeMap<String, serde_json::Value>>,
}

impl Default for ObjectSchema {
fn default() -> Self {
ObjectSchema {
_type: "object".to_owned(),
title: None,
description: None,
properties: None,
default: None,
max_properties: None,
min_properties: None,
additional_properties: None,
required: None,
read_only: None,
xml: None,
external_docs: None,
example: None,
extensions: None,
}
}
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct NullSchema {
#[serde(rename = "type")]
_type: MustBe!("null"),

/// A title to explain the purpose of the schema.
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
Expand Down
Loading

0 comments on commit 0cdb6fb

Please sign in to comment.