Skip to content

Commit

Permalink
chore: remove I/O functions to account for YAML optionality
Browse files Browse the repository at this point in the history
  • Loading branch information
robjtede committed Jan 30, 2025
1 parent 37cf036 commit 454acf9
Show file tree
Hide file tree
Showing 18 changed files with 145 additions and 171 deletions.
10 changes: 10 additions & 0 deletions crates/oas3/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

## Unreleased

- Add new crate feature `yaml-spec` (on-by-default).
- Add top-level `from_json()` function.
- Add top-level `from_yaml()` function, guarded by the `yaml-spec` crate feature.
- The top-level `to_json()` function now returns `serde_json` errors directly.
- The top-level `to_yaml()` function now returns `serde_yaml` errors directly.
- The top-level `to_yaml()` function is now guarded by the `yaml-spec` crate feature.
- Remove top-level `from_reader()` function.
- Remove top-level `from_path()` function.
- Remove top-level `Error` type.

## 0.14.0

- Implement `Default` for `spec::{Components, Contact, Example, Flows}`.
Expand Down
10 changes: 4 additions & 6 deletions crates/oas3/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ edition = { workspace = true }
rust-version = { workspace = true }

[features]
default = ["validation", "yaml_spec"]
validation = []
yaml_spec = ["dep:serde_yaml"]
default = []
yaml-spec = ["dep:serde_yaml"]

[dependencies]
derive_more = { workspace = true, features = ["display", "error", "from"] }
Expand All @@ -33,9 +32,8 @@ indoc = { workspace = true }
pretty_assertions = { workspace = true }

[[example]]
name = "printers"
path = "examples/printer.rs"
required-features = ["yaml_spec"]
name = "printer"
required-features = ["yaml-spec"]

[lints]
workspace = true
4 changes: 3 additions & 1 deletion crates/oas3/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ specs in the older format.
## Example

```rust
match oas3::from_path("path/to/openapi.yml") {
let yaml = std::fs::read_to_string("path/to/openapi.yml").unwrap();

match oas3::from_yaml(yaml) {
Ok(spec) => println!("spec: {:?}", spec),
Err(err) => println!("error: {}", err)
}
Expand Down
13 changes: 8 additions & 5 deletions crates/oas3/examples/printer.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
//! Demonstrates reading an OpenAPI spec file and printing back to stdout.
use std::env;
use std::{env, fs};

fn main() -> eyre::Result<()> {
if let Some(path) = env::args().nth(1) {
let spec = oas3::from_path(path)?;
println!("{}", oas3::to_yaml(&spec).unwrap());
}
let Some(path) = env::args().nth(1) else {
return Ok(());
};

let yaml = fs::read_to_string(path)?;
let spec = oas3::from_yaml(yaml)?;
println!("{}", oas3::to_yaml(&spec).unwrap());

Ok(())
}
28 changes: 0 additions & 28 deletions crates/oas3/src/error.rs

This file was deleted.

80 changes: 32 additions & 48 deletions crates/oas3/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
//! # Example
//!
//! ```no_run
//! match oas3::from_path("path/to/openapi.yml") {
//! let yaml = std::fs::read_to_string("path/to/openapi.yml").unwrap();
//!
//! match oas3::from_yaml(yaml) {
//! Ok(spec) => println!("spec: {:?}", spec),
//! Err(err) => println!("error: {}", err)
//! }
Expand All @@ -17,12 +19,9 @@
#![warn(missing_docs)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]

use std::{fs::File, io::Read, path::Path};

mod error;
pub mod spec;

pub use self::{error::Error, spec::Spec};
pub use self::spec::Spec;

/// Version 3.1.0 of the OpenAPI specification.
///
Expand All @@ -32,63 +31,48 @@ pub use self::{error::Error, spec::Spec};
pub type OpenApiV3Spec = spec::Spec;

/// Try deserializing an OpenAPI spec (YAML or JSON) from a file, giving the path.
///
/// If the `yaml` feature flag is disabled only `JSON` specs are supported
pub fn from_path<P>(path: P) -> Result<OpenApiV3Spec, Error>
where
P: AsRef<Path>,
{
from_reader(File::open(path)?)
#[cfg(all(test, feature = "yaml-spec"))]
pub(crate) fn from_path(
path: impl AsRef<std::path::Path>,
) -> std::io::Result<Result<OpenApiV3Spec, serde_yaml::Error>> {
let file = std::fs::File::open(path.as_ref())?;
Ok(from_reader(file))
}

/// Try deserializing an OpenAPI spec (YAML or JSON) from a [`Read`] type.
///
/// If the `yaml` feature flag is disabled only `JSON` specs are supported
pub fn from_reader<R>(read: R) -> Result<OpenApiV3Spec, Error>
where
R: Read,
{
#[cfg(feature = "yaml_spec")]
{
Ok(serde_yaml::from_reader::<R, OpenApiV3Spec>(read)?)
}
#[cfg(not(feature = "yaml_spec"))]
{
Ok(serde_json::from_reader::<R, OpenApiV3Spec>(read)?)
}
#[cfg(all(test, feature = "yaml-spec"))]
pub(crate) fn from_reader(read: impl std::io::Read) -> Result<OpenApiV3Spec, serde_yaml::Error> {
serde_yaml::from_reader::<_, OpenApiV3Spec>(read)
}

/// Try deserializing an OpenAPI spec (YAML or JSON) from string.
///
/// If the `yaml` feature flag is disabled only `JSON` specs are supported
pub fn from_str(val: impl AsRef<str>) -> Result<OpenApiV3Spec, Error> {
#[cfg(feature = "yaml_spec")]
{
Ok(serde_yaml::from_str::<OpenApiV3Spec>(val.as_ref())?)
}
#[cfg(not(feature = "yaml_spec"))]
{
Ok(serde_json::from_str::<OpenApiV3Spec>(val.as_ref())?)
}
/// Deserializes an OpenAPI spec (YAML-format) from a string.
#[cfg(feature = "yaml-spec")]
pub fn from_yaml(yaml: impl AsRef<str>) -> Result<OpenApiV3Spec, serde_yaml::Error> {
serde_yaml::from_str(yaml.as_ref())
}

/// Deserializes an OpenAPI spec (JSON-format) from a string.
pub fn from_json(json: impl AsRef<str>) -> Result<OpenApiV3Spec, serde_json::Error> {
serde_json::from_str(json.as_ref())
}

/// Try serializing to a YAML string.
#[cfg(feature = "yaml_spec")]
pub fn to_yaml(spec: &OpenApiV3Spec) -> Result<String, Error> {
Ok(serde_yaml::to_string(spec)?)
/// Serializes OpenAPI spec to a YAML string.
#[cfg(feature = "yaml-spec")]
pub fn to_yaml(spec: &OpenApiV3Spec) -> Result<String, serde_yaml::Error> {
serde_yaml::to_string(spec)
}

/// Try serializing to a JSON string.
pub fn to_json(spec: &OpenApiV3Spec) -> Result<String, Error> {
Ok(serde_json::to_string_pretty(spec)?)
/// Serializes OpenAPI spec to a JSON string.
pub fn to_json(spec: &OpenApiV3Spec) -> Result<String, serde_json::Error> {
serde_json::to_string_pretty(spec)
}

#[cfg(all(test, feature = "yaml_spec"))]
#[cfg(all(test, feature = "yaml-spec"))]
mod tests {
use std::{
fs::{self, read_to_string, File},
io::Write,
path,
path::{self, Path},
};

use pretty_assertions::assert_eq;
Expand Down Expand Up @@ -143,7 +127,7 @@ mod tests {
// File -> `Spec` -> `serde_json::Value` -> `String`

// Parse the input file
let parsed_spec = from_path(input_file).unwrap();
let parsed_spec = from_path(input_file).unwrap().unwrap();
// Convert to serde_json::Value
let parsed_spec_json = serde_json::to_value(parsed_spec).unwrap();
// Convert to a JSON string
Expand Down
2 changes: 1 addition & 1 deletion crates/oas3/src/spec/discriminator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub struct Discriminator {
pub mapping: Option<BTreeMap<String, String>>,
}

#[cfg(all(test, feature = "yaml_spec"))]
#[cfg(all(test, feature = "yaml-spec"))]
mod tests {
use super::*;

Expand Down
7 changes: 1 addition & 6 deletions crates/oas3/src/spec/media_type_examples.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,8 @@ impl MediaTypeExamples {
}
}

#[cfg(test)]
#[cfg(all(test, feature = "yaml-spec"))]
mod tests {
#[cfg(feature = "yaml_spec")]
use serde_json::json;

use super::*;
Expand All @@ -99,7 +98,6 @@ mod tests {
}

#[test]
#[cfg(feature = "yaml_spec")]
fn deserialize() {
assert_eq!(
serde_yaml::from_str::<MediaTypeExamples>(indoc::indoc! {"
Expand All @@ -121,7 +119,6 @@ mod tests {
}

#[test]
#[cfg(feature = "yaml_spec")]
fn serialize() {
let mt_examples = MediaTypeExamples::default();
assert_eq!(
Expand All @@ -143,7 +140,6 @@ mod tests {
}

#[test]
#[cfg(feature = "yaml_spec")]
fn single_example() {
let spec = serde_yaml::from_str::<Spec>(indoc::indoc! {"
openapi: 3.1.0
Expand Down Expand Up @@ -171,7 +167,6 @@ paths: {}
}

#[test]
#[cfg(feature = "yaml_spec")]
fn resolve_references() {
let spec = serde_yaml::from_str::<Spec>(indoc::indoc! {"
openapi: 3.1.0
Expand Down
43 changes: 0 additions & 43 deletions crates/oas3/src/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,46 +227,3 @@ impl Spec {
self.servers.first()
}
}

#[cfg(all(test, feature = "yaml_spec"))]
mod tests {
use pretty_assertions::assert_eq;

use super::*;

#[test]
fn spec_extensions_deserialize() {
let spec = indoc::indoc! {"
openapi: '3.1.0'
info:
title: test
version: v1
components: {}
x-bar: true
qux: true
"};

let spec = serde_yaml::from_str::<Spec>(spec).unwrap();
assert!(spec.components.is_some());
assert!(!spec.extensions.contains_key("x-bar"));
assert!(!spec.extensions.contains_key("qux"));
assert_eq!(spec.extensions.get("bar").unwrap(), true);
}

#[test]
fn spec_extensions_serialize() {
let spec = indoc::indoc! {"
openapi: 3.1.0
info:
title: test
version: v1
components: {}
x-bar: true
"};

let parsed_spec = serde_yaml::from_str::<Spec>(spec).unwrap();
let round_trip_spec = serde_yaml::to_string(&parsed_spec).unwrap();

assert_eq!(spec, round_trip_spec);
}
}
2 changes: 1 addition & 1 deletion crates/oas3/src/spec/parameter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ impl FromRef for Parameter {
}
}

#[cfg(all(test, feature = "yaml_spec"))]
#[cfg(all(test, feature = "yaml-spec"))]
mod tests {
use indoc::indoc;

Expand Down
2 changes: 1 addition & 1 deletion crates/oas3/src/spec/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -593,7 +593,7 @@ where
T::deserialize(de).map(Some)
}

#[cfg(all(test, feature = "yaml_spec"))]
#[cfg(all(test, feature = "yaml-spec"))]
mod tests {
use super::*;

Expand Down
Loading

0 comments on commit 454acf9

Please sign in to comment.