Sourcemeta Core 0.0.0
Loading...
Searching...
No Matches
OpenAPI

A growing implementation of the OpenAPI Specification. More...

Classes

struct  sourcemeta::core::OpenAPIContact
struct  sourcemeta::core::OpenAPILicense
struct  sourcemeta::core::OpenAPIInfo
class  sourcemeta::core::OpenAPIFrame
struct  sourcemeta::core::OpenAPIBundleOptions
class  sourcemeta::core::OpenAPIError
class  sourcemeta::core::OpenAPIResolutionError
class  sourcemeta::core::OpenAPIReferenceError
class  sourcemeta::core::OpenAPIFrameLimitError
class  sourcemeta::core::OpenAPIBundleLimitError

Typedefs

using sourcemeta::core::OpenAPIResolverResult = OwnedOrReference<JSON>
using sourcemeta::core::OpenAPIResolver = std::function<OpenAPIResolverResult(std::string_view)>

Enumerations

enum class  sourcemeta::core::OpenAPIVersion : std::uint8_t { OpenAPIVersion::OPENAPI_3_1 , OpenAPIVersion::OPENAPI_3_2 }

Functions

SOURCEMETA_CORE_OPENAPI_EXPORT auto sourcemeta::core::openapi_version (const JSON &document) -> std::optional< OpenAPIVersion >
SOURCEMETA_CORE_OPENAPI_EXPORT auto sourcemeta::core::openapi_version_name (const OpenAPIVersion version) noexcept -> JSON::StringView
SOURCEMETA_CORE_OPENAPI_EXPORT auto sourcemeta::core::openapi_kind_name (const OpenAPIFrame::ObjectKind kind) noexcept -> JSON::StringView
SOURCEMETA_CORE_OPENAPI_EXPORT auto sourcemeta::core::openapi_operation_kind_name (const OpenAPIFrame::OperationKind kind) noexcept -> JSON::StringView
SOURCEMETA_CORE_OPENAPI_EXPORT auto sourcemeta::core::openapi_format (JSON &document, const OpenAPIFrame &frame) -> void
SOURCEMETA_CORE_OPENAPI_EXPORT auto sourcemeta::core::openapi_bundle (JSON &document, const SchemaWalker &walker, const SchemaResolver &schema_resolver, const OpenAPIResolver &resolver, const OpenAPIBundleOptions &options={}) -> void
SOURCEMETA_CORE_OPENAPI_EXPORT auto sourcemeta::core::openapi_bundle (const JSON &document, const SchemaWalker &walker, const SchemaResolver &schema_resolver, const OpenAPIResolver &resolver, const OpenAPIBundleOptions &options={}) -> JSON

Detailed Description

A growing implementation of the OpenAPI Specification.

This module reports where an OpenAPI Description declares its JSON Schemas and leaves what is inside them to a JSON Schema implementation.

This functionality is included as follows:

#include <sourcemeta/core/openapi.h>

Class Documentation

◆ sourcemeta::core::OpenAPIContact

struct sourcemeta::core::OpenAPIContact

The contact information that an OpenAPI Description declares for the API. Every value borrows from the document it was read from, so that document must outlive this

Public Attributes

std::optional< JSON::StringView > name {std::nullopt}
 The identifying name of the contact person or organisation.
std::optional< JSON::StringView > url {std::nullopt}
 Where to find the contact information, as a URI reference.
std::optional< JSON::StringView > email {std::nullopt}
 The email address of the contact person or organisation.

◆ sourcemeta::core::OpenAPILicense

struct sourcemeta::core::OpenAPILicense

The license information that an OpenAPI Description declares for the API. Every value borrows from the document it was read from, so that document must outlive this

Public Attributes

JSON::StringView name {}
 The license name used for the API.
std::optional< JSON::StringView > identifier {std::nullopt}
std::optional< JSON::StringView > url {std::nullopt}
 Where to find the license used for the API, as a URI reference.

Member Data Documentation

◆ identifier

std::optional<JSON::StringView> sourcemeta::core::OpenAPILicense::identifier {std::nullopt}

The SPDX license expression for the API, recorded as it was written, as the specification states no requirement on its syntax

◆ sourcemeta::core::OpenAPIInfo

struct sourcemeta::core::OpenAPIInfo

The metadata that an OpenAPI Description declares about the API it describes. Every value borrows from the document it was read from, so that document must outlive this

Public Attributes

JSON::StringView title {}
 The title of the API.
JSON::StringView version {}
std::optional< JSON::StringView > summary {std::nullopt}
 A short summary of the API.
std::optional< JSON::StringView > description {std::nullopt}
 A description of the API, which may be written in CommonMark.
std::optional< JSON::StringView > terms_of_service {std::nullopt}
 Where to find the terms of service for the API, as a URI reference.
std::optional< OpenAPIContact > contact {std::nullopt}
 The contact information for the API.
std::optional< OpenAPILicense > license {std::nullopt}
 The license information for the API.

Member Data Documentation

◆ version

JSON::StringView sourcemeta::core::OpenAPIInfo::version {}

The version of the document, which is unrelated to the version of the OpenAPI Specification that it declares

◆ sourcemeta::core::OpenAPIFrame

class sourcemeta::core::OpenAPIFrame

A static analysis pass over an OpenAPI Description that computes the locations it exposes, the references between them, the operations it describes, and where its JSON Schemas begin. It does not look inside those schemas. For example:

#include <sourcemeta/core/json.h>
#include <sourcemeta/core/openapi.h>
#include <iostream>
const auto document{sourcemeta::core::parse_json(R"({
"openapi": "3.1.1",
"info": { "title": "Example", "version": "1.0.0" },
"paths": {}
})")};
sourcemeta::core::prettify(frame.to_json(), std::cout);
std::cout << std::endl;
SOURCEMETA_CORE_JSON_EXPORT auto parse_json(std::basic_istream< JSON::Char, JSON::CharTraits > &stream) -> JSON
SOURCEMETA_CORE_JSON_EXPORT auto prettify(const JSON &document, std::basic_ostream< JSON::Char, JSON::CharTraits > &stream, const std::size_t spaces=2) -> void
SOURCEMETA_CORE_JSONSCHEMA_EXPORT auto schema_resolver(const std::string_view identifier) -> SchemaResolverResult
SOURCEMETA_CORE_JSONSCHEMA_EXPORT auto schema_walker(const std::string_view keyword, const SchemaVocabularies &vocabularies) -> const SchemaWalkerResult &
auto to_json(const std::optional< PointerPositionTracker > &tracker=std::nullopt) const -> JSON
Definition openapi.h:167

A frame is analysed once, on construction, and what it reports never changes afterwards. Reading one is not thread safe even so, as it answers out of caches it fills as it goes. A frame cannot be copied or moved, so it is built where it is read.

Public Types

enum class  ObjectKind : std::uint8_t {
  Document , PathItem , Parameter , RequestBody ,
  Response , Example , Header , Link ,
  Callbacks , SecurityScheme , MediaType , Info ,
  Contact , License , Server , ServerVariable ,
  Components , Paths , Operation , ExternalDocumentation ,
  Encoding , Responses , Tag , Reference ,
  Schema , OAuthFlows , OAuthFlow , SecurityRequirement
}
enum class  OperationKind : std::uint8_t { Path , Webhook , Callback }
using Locations = std::map<JSON::String, Location, std::less<>>
using References = std::map<JSON::String, Reference, std::less<>>

Public Member Functions

 OpenAPIFrame (const JSON &document, const SchemaWalker &walker, const SchemaResolver &resolver, std::string_view default_base="", std::uint64_t max_locations=std::numeric_limits< std::uint64_t >::max())
 OpenAPIFrame (const OpenAPIFrame &)=delete
 OpenAPIFrame (OpenAPIFrame &&)=delete
auto version () const noexcept -> OpenAPIVersion
auto info () const noexcept -> const OpenAPIInfo &
auto base () const noexcept -> JSON::StringView
auto standalone () const noexcept -> bool
auto schemas () const noexcept -> const SchemaFrame &
auto locations () const noexcept -> const Locations &
 Every Object the description holds, keyed by the URI addressing each one.
auto references () const noexcept -> const References &
auto security_references () const noexcept -> const References &
auto operations () const noexcept -> const std::vector< Operation > &
 Every operation the described API exposes.
auto discriminators () const noexcept -> const std::vector< Discriminator > &
template<std::invocable< const JSON::String &, const Location & > F>
auto for_each_object (const F &callback) const -> void
template<std::predicate< const JSON::String &, const Location & > F>
auto any_object (const F &predicate) const -> bool
template<std::invocable< const JSON::String &, const Reference & > F>
auto for_each_reference (const F &callback) const -> void
template<std::invocable< const JSON::String &, const Reference & > F>
auto for_each_security_reference (const F &callback) const -> void
template<std::invocable< const Operation & > F>
auto for_each_operation (const F &callback) const -> void
template<std::invocable< const Discriminator & > F>
auto for_each_discriminator (const F &callback) const -> void
auto traverse (const JSON::StringView uri) const -> const Location *
auto uri (const Pointer &pointer) const -> JSON::String
auto object_count () const noexcept -> std::size_t
 How many Objects the description holds.
auto reference_count () const noexcept -> std::size_t
auto to_json (const std::optional< PointerPositionTracker > &tracker=std::nullopt) const -> JSON

Member Typedef Documentation

◆ Locations

The Objects a frame holds, keyed by the URI addressing each one. Comparison is transparent so that a lookup may take a view of a URI without building a string of it

◆ References

The references a frame holds, keyed by the URI of the Object that makes each one

Member Enumeration Documentation

◆ ObjectKind

enum class sourcemeta::core::OpenAPIFrame::ObjectKind : std::uint8_t
strong

What kind of Object an OpenAPI Description holds at a given position. For a position a reference names, this is what it expects to find at the far end of itself, which is fixed by where the reference sits rather than by anything the target says about itself. OpenAPI Specification 3.1.1, Section 4.3.1 calls this "the expected type of the reference", and it is what the place a reference lands on is held to

Enumerator
Document 

A whole OpenAPI Description, which is what the root of the document framed is recorded as

PathItem 

A Path Item Object, which describes the operations available on one path.

Parameter 

A Parameter Object, which describes one parameter of an operation.

RequestBody 

A Request Body Object, which describes the body an operation takes.

Response 

A Response Object, which describes one response of an operation.

Example 

An Example Object, which pairs an example value with its metadata.

Header 

A Header Object, which describes one header of a response or an encoding.

Link 

A Link Object, which names a design time relationship to an operation.

Callbacks 

A Callback Object, which maps runtime expressions to out of band requests

SecurityScheme 

A Security Scheme Object, which describes one way of authenticating.

MediaType 

A Media Type Object, which describes one representation of a body.

Info 

An Info Object, which carries the metadata about the API.

Contact 

A Contact Object, which names who to reach about the API.

License 

A License Object, which names the license the API is offered under.

Server 

A Server Object, which names a host the API is served from.

ServerVariable 

A Server Variable Object, which describes one substitution a server URL template takes

Components 

A Components Object, which holds the Objects a description reuses.

Paths 

A Paths Object, which maps path templates to what describes them.

Operation 

An Operation Object, which describes one operation on a path.

ExternalDocumentation 

An External Documentation Object, which points at documentation held elsewhere

Encoding 

An Encoding Object, which describes how one property of a body is serialised

Responses 

A Responses Object, which maps status codes to what describes them.

Tag 

A Tag Object, which adds metadata to a tag that the operations name.

Reference 

A Reference Object, which stands in for another Object.

Schema 

A Schema Object, whose contents are JSON Schema's to make sense of rather than this specification's

OAuthFlows 

An OAuth Flows Object, which holds the flows an OAuth scheme supports.

OAuthFlow 

An OAuth Flow Object, which describes one flow a scheme supports.

SecurityRequirement 

A Security Requirement Object, which names the schemes that apply.

◆ OperationKind

enum class sourcemeta::core::OpenAPIFrame::OperationKind : std::uint8_t
strong

How an Operation Object is reached from the entry document. OpenAPI Specification 3.1.1, Section 4.3.3: "only the entry document's Paths Object contributes URLs to the described API", so what an operation is reached through is a property of the route to it rather than of where it is defined

Enumerator
Path 

Reached through the Paths Object of the entry document.

Webhook 

Reached through the webhooks that the entry document declares.

Callback 

Reached through a Callback Object that an operation declares.

Constructor & Destructor Documentation

◆ OpenAPIFrame()

sourcemeta::core::OpenAPIFrame::OpenAPIFrame ( const JSON & document,
const SchemaWalker & walker,
const SchemaResolver & resolver,
std::string_view default_base = "",
std::uint64_t max_locations = std::numeric_limits< std::uint64_t >::max() )

Frame an OpenAPI Description from a given document. That document must outlive the frame, as the metadata it reports borrows from it. The given base need not, as the frame canonicalises it into a string of its own

The base is the retrieval URI of the document. OpenAPI 3.1 offers a document no way of declaring an identity of its own, so under that revision this is the only way to give the description one. From 3.2 onwards a document may declare $self, which takes precedence once it is absolute, resolving against this when relative and standing aside when neither gives it a scheme

Only the given document is read. A reference that leaves it is recorded and left there, and a frame holding one of those does not stand alone

The walker and the resolver are what reading inside a Schema Object takes, as a Schema Object is JSON Schema's to make sense of rather than this specification's. Neither is defaulted, as which dialects a description may be written against is the caller's to state: pass sourcemeta::core::schema_walker and sourcemeta::core::schema_resolver for the dialects that are published, and a resolver of your own for one that is not. The frame keeps the resolver and asks it again when exporting, so whatever it reaches for has to be there for as long as the frame is

The places the description holds and the places its Schema Objects hold are places of the one description, so they spend from the one allowance. Bound it to throw sourcemeta::core::OpenAPIFrameLimitError rather than register past it, which reports the allowance the caller set rather than whatever was left of it

The base must carry a scheme. One that does not is refused before the document is read, which is why such a refusal names no place within it

A document that does not conform to the specification is rejected here rather than reported back, by throwing sourcemeta::core::OpenAPIError. What sits inside a Schema Object is held to JSON Schema instead, so one naming a dialect nothing resolves throws sourcemeta::core::SchemaResolutionError, one declaring an identifier or a reference that is no URI throws sourcemeta::core::SchemaKeywordError, and two colliding on an identifier or on an anchor throw sourcemeta::core::SchemaFrameError and sourcemeta::core::SchemaAnchorCollisionError respectively. One whose dialect or base dialect cannot be settled at all throws sourcemeta::core::SchemaUnknownDialectError or sourcemeta::core::SchemaUnknownBaseDialectError

Member Function Documentation

◆ any_object()

template<std::predicate< const JSON::String &, const Location & > F>
auto sourcemeta::core::OpenAPIFrame::any_object ( const F & predicate) const -> bool
inlinenodiscard

Check whether any Object the description holds satisfies the predicate. For example:

#include <sourcemeta/core/json.h>
#include <sourcemeta/core/openapi.h>
#include <cassert>
const auto document{sourcemeta::core::parse_json(R"({
"openapi": "3.1.1",
"info": { "title": "Example", "version": "1.0.0" },
"paths": {}
})")};
assert(frame.any_object([](const auto &, const auto &location) {
return location.type ==
sourcemeta::core::OpenAPIFrame::ObjectKind::Paths;
}));
auto any_object(const F &predicate) const -> bool
Definition openapi.h:638

◆ base()

auto sourcemeta::core::OpenAPIFrame::base ( ) const -> JSON::StringView
nodiscardnoexcept

Get the base URI that relative references in the entry document resolve against, canonicalised, or the empty URI reference when nothing established one, which leaves those references relative. It is the $self the entry document declares, and the retrieval URI the caller supplied when it declares none or when what it declares cannot be made absolute, in either case stripped of any fragment. For example:

#include <sourcemeta/core/json.h>
#include <sourcemeta/core/openapi.h>
#include <cassert>
const auto document{sourcemeta::core::parse_json(R"({
"openapi": "3.1.1",
"info": { "title": "Example", "version": "1.0.0" },
"paths": {}
})")};
"https://example.com/openapi.json"};
assert(frame.base() == "https://example.com/openapi.json");
auto base() const noexcept -> JSON::StringView

◆ discriminators()

auto sourcemeta::core::OpenAPIFrame::discriminators ( ) const -> const std::vector< Discriminator > &
nodiscardnoexcept

Every URI a Discriminator Object names, which is a reference the schemas hold rather than one the shell around them does

◆ for_each_discriminator()

template<std::invocable< const Discriminator & > F>
auto sourcemeta::core::OpenAPIFrame::for_each_discriminator ( const F & callback) const -> void
inline

Iterate over every URI a Discriminator Object names. For example:

#include <sourcemeta/core/json.h>
#include <sourcemeta/core/openapi.h>
#include <iostream>
const auto document{sourcemeta::core::parse_json(R"({
"openapi": "3.1.1",
"info": { "title": "Example", "version": "1.0.0" },
"paths": {}
})")};
frame.for_each_discriminator([](const auto &discriminator) {
std::cout << discriminator.destination << "\n";
});
auto for_each_discriminator(const F &callback) const -> void
Definition openapi.h:759

◆ for_each_object()

template<std::invocable< const JSON::String &, const Location & > F>
auto sourcemeta::core::OpenAPIFrame::for_each_object ( const F & callback) const -> void
inline

Iterate over every Object the description holds, along with the URI the frame keys it by. For example:

#include <sourcemeta/core/json.h>
#include <sourcemeta/core/openapi.h>
#include <iostream>
const auto document{sourcemeta::core::parse_json(R"({
"openapi": "3.1.1",
"info": { "title": "Example", "version": "1.0.0" },
"paths": {}
})")};
frame.for_each_object([](const auto &uri, const auto &location) {
if (location.type ==
std::cout << "a schema at " << uri << "\n";
}
});
auto for_each_object(const F &callback) const -> void
Definition openapi.h:608
auto uri(const Pointer &pointer) const -> JSON::String

◆ for_each_operation()

template<std::invocable< const Operation & > F>
auto sourcemeta::core::OpenAPIFrame::for_each_operation ( const F & callback) const -> void
inline

Iterate over every operation the described API exposes. For example:

#include <sourcemeta/core/json.h>
#include <sourcemeta/core/openapi.h>
#include <iostream>
const auto document{sourcemeta::core::parse_json(R"({
"openapi": "3.1.1",
"info": { "title": "Example", "version": "1.0.0" },
"paths": { "/users": { "get": { "responses": {
"200": { "description": "Some users" } } } } }
})")};
frame.for_each_operation([](const auto &operation) {
std::cout << operation.method << " " << operation.path << "\n";
});
auto for_each_operation(const F &callback) const -> void
Definition openapi.h:731

◆ for_each_reference()

template<std::invocable< const JSON::String &, const Reference & > F>
auto sourcemeta::core::OpenAPIFrame::for_each_reference ( const F & callback) const -> void
inline

Iterate over every reference the description makes, along with the URI of the Object that makes it. For example:

#include <sourcemeta/core/json.h>
#include <sourcemeta/core/openapi.h>
#include <iostream>
const auto document{sourcemeta::core::parse_json(R"({
"openapi": "3.1.1",
"info": { "title": "Example", "version": "1.0.0" },
"paths": { "/users": { "$ref": "#/components/pathItems/Users" } },
"components": { "pathItems": { "Users": {} } }
})")};
frame.for_each_reference([](const auto &origin, const auto &reference) {
std::cout << origin << " -> " << reference.destination << "\n";
});
auto for_each_reference(const F &callback) const -> void
Definition openapi.h:672

◆ for_each_security_reference()

template<std::invocable< const JSON::String &, const Reference & > F>
auto sourcemeta::core::OpenAPIFrame::for_each_security_reference ( const F & callback) const -> void
inline

Iterate over every scheme a Security Requirement Object names by the URI of one, along with the URI of the Object that names it. For example:

#include <sourcemeta/core/json.h>
#include <sourcemeta/core/openapi.h>
#include <iostream>
const auto document{sourcemeta::core::parse_json(R"({
"openapi": "3.1.1",
"info": { "title": "Example", "version": "1.0.0" },
"paths": {}
})")};
[](const auto &origin, const auto &reference) {
std::cout << origin << " -> " << reference.destination << "\n";
});
auto for_each_security_reference(const F &callback) const -> void
Definition openapi.h:702

◆ info()

auto sourcemeta::core::OpenAPIFrame::info ( ) const -> const OpenAPIInfo &
nodiscardnoexcept

Get the metadata that the entry document declares about the API. For example:

#include <sourcemeta/core/json.h>
#include <sourcemeta/core/openapi.h>
#include <cassert>
const auto document{sourcemeta::core::parse_json(R"({
"openapi": "3.1.1",
"info": { "title": "Example", "version": "1.0.0" },
"paths": {}
})")};
assert(frame.info().title == "Example");
assert(frame.info().version == "1.0.0");
assert(!frame.info().license.has_value());
auto info() const noexcept -> const OpenAPIInfo &

◆ reference_count()

auto sourcemeta::core::OpenAPIFrame::reference_count ( ) const -> std::size_t
nodiscardnoexcept

How many references the description makes, not counting what a Security Requirement Object names by the URI of a scheme

◆ references()

auto sourcemeta::core::OpenAPIFrame::references ( ) const -> const References &
nodiscardnoexcept

Every reference the description makes, keyed by the URI of the Object that makes it rather than by its $ref member, so that where a reference comes from is a location like any other

◆ schemas()

auto sourcemeta::core::OpenAPIFrame::schemas ( ) const -> const SchemaFrame &
nodiscardnoexcept

Get the frame of every Schema Object the description holds, which a schema location names its part of by key. For example:

#include <sourcemeta/core/json.h>
#include <sourcemeta/core/openapi.h>
#include <cassert>
const auto document{sourcemeta::core::parse_json(R"({
"openapi": "3.1.1",
"info": { "title": "Example", "version": "1.0.0" },
"components": { "schemas": { "Pet": { "type": "object" } } }
})")};
"https://example.com/openapi.json"};
assert(frame.schemas()
"https://example.com/openapi.json"
"#/components/schemas/Pet")
.has_value());
@ Static
A reference that resolves at framing time.
Definition jsonschema_types.h:47
auto schemas() const noexcept -> const SchemaFrame &

◆ security_references()

auto sourcemeta::core::OpenAPIFrame::security_references ( ) const -> const References &
nodiscardnoexcept

Every scheme a Security Requirement Object names by the URI of one, which OpenAPI Specification 3.2.1 admits alongside the name of a component. These are kept apart from the references above because a single such Object may name several, while every other way of naming an Object is written down where the Object that makes it sits

◆ standalone()

auto sourcemeta::core::OpenAPIFrame::standalone ( ) const -> bool
nodiscardnoexcept

Check whether everything this description references is inside what was framed, which counts what its Schema Objects reference as much as what the shell around them does. The dialect a Schema Object names is not one of those, as a schema is under no obligation to carry the meta-schema it is written against. For example:

#include <sourcemeta/core/json.h>
#include <sourcemeta/core/openapi.h>
#include <cassert>
const auto document{sourcemeta::core::parse_json(R"({
"openapi": "3.1.1",
"info": { "title": "Example", "version": "1.0.0" },
"paths": {}
})")};
assert(frame.standalone());
auto standalone() const noexcept -> bool

◆ to_json()

auto sourcemeta::core::OpenAPIFrame::to_json ( const std::optional< PointerPositionTracker > & tracker = std::nullopt) const -> JSON
nodiscard

Export the frame as JSON. This is the complete state of the frame. It asks the resolver the frame kept, so a meta-schema that has gone out of reach since throws sourcemeta::core::SchemaResolutionError here rather than at construction.

Pass the tracker that read the document to report where every place the export names by a pointer sits within it, which counts the places its Schema Objects hold as much as the Objects around them. A place the tracker holds nothing for reports a null position, and where no tracker is given no position is reported at all. For example:

#include <sourcemeta/core/json.h>
#include <sourcemeta/core/openapi.h>
#include <cassert>
const auto document{sourcemeta::core::parse_json(R"({
"openapi": "3.1.1",
"info": { "title": "Example", "version": "1.0.0" },
"paths": {}
})")};
assert(frame.to_json().at("version").to_string() == "3.1");

◆ traverse()

auto sourcemeta::core::OpenAPIFrame::traverse ( const JSON::StringView uri) const -> const Location *
nodiscard

The Object a URI names, or nothing when the frame holds none. This is what turns the destination of a reference into the Object it lands on, as every destination is one of the URIs this frame addresses its Objects by. For example:

#include <sourcemeta/core/json.h>
#include <sourcemeta/core/openapi.h>
#include <cassert>
const auto document{sourcemeta::core::parse_json(R"({
"openapi": "3.1.1",
"info": { "title": "Example", "version": "1.0.0" },
"paths": {}
})")};
"https://example.com/openapi.json"};
assert(frame.traverse("https://example.com/openapi.json#/info")->type ==
@ Info
An Info Object, which carries the metadata about the API.
Definition openapi.h:205
auto traverse(const JSON::StringView uri) const -> const Location *

◆ uri()

auto sourcemeta::core::OpenAPIFrame::uri ( const Pointer & pointer) const -> JSON::String
nodiscard

The URI this frame addresses the given position by, which is the inverse of traversal. For example:

#include <sourcemeta/core/json.h>
#include <sourcemeta/core/openapi.h>
#include <cassert>
const auto document{sourcemeta::core::parse_json(R"({
"openapi": "3.1.1",
"info": { "title": "Example", "version": "1.0.0" },
"paths": {}
})")};
"https://example.com/openapi.json"};
assert(frame.uri(sourcemeta::core::Pointer{"info"}) ==
"https://example.com/openapi.json#/info");
GenericPointer< JSON::String, PropertyHashJSON< JSON::String > > Pointer
Definition jsonpointer.h:39

◆ version()

auto sourcemeta::core::OpenAPIFrame::version ( ) const -> OpenAPIVersion
nodiscardnoexcept

Get the version of the OpenAPI Specification that the entry document declares. The patch component of that declaration carries no meaning, so every 3.1.x release reports the same version. For example:

#include <sourcemeta/core/json.h>
#include <sourcemeta/core/openapi.h>
#include <cassert>
const auto document{sourcemeta::core::parse_json(R"({
"openapi": "3.1.1",
"info": { "title": "Example", "version": "1.0.0" },
"paths": {}
})")};
assert(frame.version() ==
auto version() const noexcept -> OpenAPIVersion
@ OPENAPI_3_1
The OpenAPI Specification 3.1 revision.
Definition openapi.h:45

◆ sourcemeta::core::OpenAPIBundleOptions

struct sourcemeta::core::OpenAPIBundleOptions

Everything bundling takes beyond the document and how to reach the rest

Public Types

using Callback
using Namer = std::function<JSON::String(JSON::StringView, JSON::StringView)>

Public Attributes

std::string_view default_base {}
std::uint64_t max_locations {std::numeric_limits<std::uint64_t>::max()}
Callback callback {}
 A callback to report each place that bundling embedded.
Namer namer {}
 A callback to name each place that bundling embeds.

Member Typedef Documentation

◆ Callback

Initial value:
std::function<void(JSON::StringView, const sourcemeta::core::Pointer &)>
std::basic_string_view< Char, CharTraits > StringView
The string view type used by the JSON document.
Definition json_value.h:54

A callback to report what bundling embedded, as the URI of the place it came from and a pointer from the root of the document it landed at. Bundling renames what it embeds to hold up as a component name, so this is the only way to know which place became which component

◆ Namer

A callback to name what bundling embeds, given the URI of the place it came from and the Components Object member it goes under. Whatever it hands back is held to the keys that the specification admits and to being one the description does not already give a meaning to, so it is what bundling starts from rather than the last word

Member Data Documentation

◆ default_base

std::string_view sourcemeta::core::OpenAPIBundleOptions::default_base {}

The URI the document was retrieved from, which every relative reference it makes resolves against. A document that names itself takes that name as its base instead, leaving this as the one a relative such name resolves against

◆ max_locations

std::uint64_t sourcemeta::core::OpenAPIBundleOptions::max_locations {std::numeric_limits<std::uint64_t>::max()}

The maximum number of locations that analysis may register. How many documents bundling ends up reading follows from what the resolvers hand back rather than from the document the caller passed in, and every walk and every frame that bundling constructs spends from this one allowance, throwing sourcemeta::core::OpenAPIBundleLimitError once it runs out.

Bundling settles by reading what it has produced so far over and over until a pass brings nothing new in, so this bounds the reading rather than the result. One place counts once per pass that goes by it and once more for each document brought in alongside it, which puts the allowance a whole description needs well above the number of places it holds. Note too that a document is read in full before anything charges for it, so this bounds how many oversized documents are read rather than whether one is

◆ sourcemeta::core::OpenAPIError

class sourcemeta::core::OpenAPIError

An error that represents an OpenAPI Description that does not conform to the specification. For example:

#include <sourcemeta/core/jsonpointer.h>
#include <sourcemeta/core/openapi.h>
#include <cassert>
sourcemeta::core::Pointer{"info"}, "The Info Object is required"};
assert(error.location() == sourcemeta::core::Pointer{"info"});
auto location() const noexcept -> const Pointer &
Definition openapi_error.h:67
Definition openapi_error.h:40
Inheritance diagram for sourcemeta::core::OpenAPIError:

Public Member Functions

 OpenAPIError (Pointer location, const char *message)
 Construct an error from where the problem is and a message.
 OpenAPIError (Pointer location, std::string message)=delete
 OpenAPIError (Pointer location, std::string &&message)=delete
 OpenAPIError (Pointer location, std::string_view message)=delete
 OpenAPIError (JSON::String base, Pointer location, const char *message)
 OpenAPIError (JSON::String base, Pointer location, std::string message)=delete
 OpenAPIError (JSON::String base, Pointer location, std::string &&message)=delete
 OpenAPIError (JSON::String base, Pointer location, std::string_view message)=delete
auto location () const noexcept -> const Pointer &
auto base () const noexcept -> JSON::StringView

Constructor & Destructor Documentation

◆ OpenAPIError()

sourcemeta::core::OpenAPIError::OpenAPIError ( JSON::String base,
Pointer location,
const char * message )
inline

Construct an error that names the document the problem is in, which is what a caller that framed more than one of them tells them apart by

Member Function Documentation

◆ base()

auto sourcemeta::core::OpenAPIError::base ( ) const -> JSON::StringView
inlinenodiscardnoexcept

Get the base URI of the document that holds the problem, or the empty URI reference when the caller established none

◆ location()

auto sourcemeta::core::OpenAPIError::location ( ) const -> const Pointer &
inlinenodiscardnoexcept

Get where the problem is, as a pointer from the root of the document that holds it

◆ sourcemeta::core::OpenAPIResolutionError

class sourcemeta::core::OpenAPIResolutionError

An error that represents a document of an OpenAPI Description that nothing could produce. For example:

#include <sourcemeta/core/jsonpointer.h>
#include <sourcemeta/core/openapi.h>
#include <cassert>
"https://example.com/openapi.json", sourcemeta::core::Pointer{"$ref"},
"https://example.com/shared.json", "Could not resolve"};
assert(error.identifier() == "https://example.com/shared.json");
auto identifier() const noexcept -> JSON::StringView
The URI that nothing could produce a document for.
Definition openapi_error.h:120
Definition openapi_error.h:98
Inheritance diagram for sourcemeta::core::OpenAPIResolutionError:

Public Member Functions

 OpenAPIResolutionError (JSON::String base, Pointer location, JSON::String identifier, const char *message)
 OpenAPIResolutionError (JSON::String base, Pointer location, JSON::String identifier, std::string message)=delete
 OpenAPIResolutionError (JSON::String base, Pointer location, JSON::String identifier, std::string &&message)=delete
 OpenAPIResolutionError (JSON::String base, Pointer location, JSON::String identifier, std::string_view message)=delete
auto identifier () const noexcept -> JSON::StringView
 The URI that nothing could produce a document for.
auto location () const noexcept -> const Pointer &
auto base () const noexcept -> JSON::StringView
 Get the base URI of the document that makes the reference.

Constructor & Destructor Documentation

◆ OpenAPIResolutionError()

sourcemeta::core::OpenAPIResolutionError::OpenAPIResolutionError ( JSON::String base,
Pointer location,
JSON::String identifier,
const char * message )
inline

Create a resolution error from the document the reference was made in, where in it the reference sits, what it names, and a message

Member Function Documentation

◆ location()

auto sourcemeta::core::OpenAPIResolutionError::location ( ) const -> const Pointer &
inlinenodiscardnoexcept

Get where the reference is, as a pointer from the root of the document that makes it

◆ sourcemeta::core::OpenAPIReferenceError

class sourcemeta::core::OpenAPIReferenceError

An error that represents a reference of an OpenAPI Description that names something it may not. For example:

#include <sourcemeta/core/jsonpointer.h>
#include <sourcemeta/core/openapi.h>
#include <cassert>
"https://example.com/openapi.json", sourcemeta::core::Pointer{"$ref"},
"https://example.com/shared.json#/info", "Wrong kind"};
assert(error.identifier() == "https://example.com/shared.json#/info");
auto identifier() const noexcept -> JSON::StringView
The URI that the reference names, resolved and canonicalised.
Definition openapi_error.h:179
Definition openapi_error.h:157
Inheritance diagram for sourcemeta::core::OpenAPIReferenceError:

Public Member Functions

 OpenAPIReferenceError (JSON::String base, Pointer location, JSON::String identifier, const char *message)
 OpenAPIReferenceError (JSON::String base, Pointer location, JSON::String identifier, std::string message)=delete
 OpenAPIReferenceError (JSON::String base, Pointer location, JSON::String identifier, std::string &&message)=delete
 OpenAPIReferenceError (JSON::String base, Pointer location, JSON::String identifier, std::string_view message)=delete
auto identifier () const noexcept -> JSON::StringView
 The URI that the reference names, resolved and canonicalised.
auto location () const noexcept -> const Pointer &
auto base () const noexcept -> JSON::StringView
 Get the base URI of the document that makes the reference.

Constructor & Destructor Documentation

◆ OpenAPIReferenceError()

sourcemeta::core::OpenAPIReferenceError::OpenAPIReferenceError ( JSON::String base,
Pointer location,
JSON::String identifier,
const char * message )
inline

Create a reference error from the document the reference was made in, where in it the reference sits, what it names, and a message

Member Function Documentation

◆ location()

auto sourcemeta::core::OpenAPIReferenceError::location ( ) const -> const Pointer &
inlinenodiscardnoexcept

Get where the reference is, as a pointer from the root of the document that makes it

◆ sourcemeta::core::OpenAPIFrameLimitError

class sourcemeta::core::OpenAPIFrameLimitError

An error that represents framing that ran past what the caller allowed it to register. For example:

#include <sourcemeta/core/openapi.h>
#include <cassert>
assert(error.limit() == 100);
auto limit() const noexcept -> std::uint64_t
The maximum number of locations that framing was allowed to register.
Definition openapi_error.h:224
Definition openapi_error.h:213
Inheritance diagram for sourcemeta::core::OpenAPIFrameLimitError:

Public Member Functions

 OpenAPIFrameLimitError (const std::uint64_t limit)
 Create a framing limit error.
auto limit () const noexcept -> std::uint64_t
 The maximum number of locations that framing was allowed to register.

◆ sourcemeta::core::OpenAPIBundleLimitError

class sourcemeta::core::OpenAPIBundleLimitError

An error that represents bundling that ran past what the caller allowed it to analyse. For example:

#include <sourcemeta/core/openapi.h>
#include <cassert>
assert(error.limit() == 100);
auto limit() const noexcept -> std::uint64_t
The maximum number of locations that bundling was allowed to register.
Definition openapi_error.h:255
Definition openapi_error.h:244
Inheritance diagram for sourcemeta::core::OpenAPIBundleLimitError:

Public Member Functions

 OpenAPIBundleLimitError (const std::uint64_t limit)
 Create a bundling limit error.
auto limit () const noexcept -> std::uint64_t
 The maximum number of locations that bundling was allowed to register.

Typedef Documentation

◆ OpenAPIResolver

using sourcemeta::core::OpenAPIResolver = std::function<OpenAPIResolverResult(std::string_view)>

How bundling reaches the other documents that an OpenAPI Description is split across. Every document handed back must itself be an OpenAPI Description, and a URI that names nothing is reported by handing back no value. For example:

#include <sourcemeta/core/json.h>
#include <sourcemeta/core/openapi.h>
#include <string_view>
static auto resolver(const std::string_view identifier)
if (identifier == "https://example.com/shared.json") {
"openapi": "3.1.1",
"info": { "title": "Shared", "version": "1.0.0" },
"components": {}
})JSON");
}
return std::nullopt;
}
OwnedOrReference< JSON > OpenAPIResolverResult
Definition openapi.h:904

◆ OpenAPIResolverResult

What a sourcemeta::core::OpenAPIResolver hands back: either a document it owns, or a reference to one that outlives the call

Enumeration Type Documentation

◆ OpenAPIVersion

enum class sourcemeta::core::OpenAPIVersion : std::uint8_t
strong

The OpenAPI Description versions that this module recognises

Enumerator
OPENAPI_3_1 

The OpenAPI Specification 3.1 revision.

OPENAPI_3_2 

The OpenAPI Specification 3.2 revision.

Function Documentation

◆ openapi_bundle() [1/2]

SOURCEMETA_CORE_OPENAPI_EXPORT auto sourcemeta::core::openapi_bundle ( const JSON & document,
const SchemaWalker & walker,
const SchemaResolver & schema_resolver,
const OpenAPIResolver & resolver,
const OpenAPIBundleOptions & options = {} ) -> JSON

Bundle an OpenAPI Description by embedding everything it references from another document into its own Components Object. No document the description spans may declare a revision of the OpenAPI Specification other than the one the entry document declares, which is a choice this makes rather than one the specification asks for. This overload returns a new document, without mutating the input. For example:

#include <sourcemeta/core/json.h>
#include <sourcemeta/core/openapi.h>
#include <cassert>
#include <string_view>
static auto resolver(const std::string_view identifier)
assert(identifier == "https://example.com/shared.json");
"openapi": "3.1.1",
"info": { "title": "Shared", "version": "1.0.0" },
"components": {
"responses": { "NotFound": { "description": "Not found" } }
}
})JSON");
}
const auto document{sourcemeta::core::parse_json(R"JSON({
"openapi": "3.1.1",
"info": { "title": "Example", "version": "1.0.0" },
"paths": {
"/pets": {
"get": {
"responses": {
"404": { "$ref": "shared.json#/components/responses/NotFound" }
}
}
}
}
})JSON")};
{.default_base = "https://example.com/openapi.json"})};
assert(result.at("components").at("responses").defines("NotFound"));
SOURCEMETA_CORE_OPENAPI_EXPORT auto openapi_bundle(JSON &document, const SchemaWalker &walker, const SchemaResolver &schema_resolver, const OpenAPIResolver &resolver, const OpenAPIBundleOptions &options={}) -> void

◆ openapi_bundle() [2/2]

SOURCEMETA_CORE_OPENAPI_EXPORT auto sourcemeta::core::openapi_bundle ( JSON & document,
const SchemaWalker & walker,
const SchemaResolver & schema_resolver,
const OpenAPIResolver & resolver,
const OpenAPIBundleOptions & options = {} ) -> void

Bundle an OpenAPI Description by embedding everything it references from another document into its own Components Object. The walker and the resolver are what reading inside a Schema Object takes, and the OpenAPI resolver is how the rest of the description is reached. No document the description spans may declare a revision of the OpenAPI Specification other than the one the entry document declares. The specification does not ask for that. It is a choice this makes, as what this produces is one document that declares one revision, and there is none to pick that can express both what one revision holds and what another does. This overload mutates the input document. For example:

#include <sourcemeta/core/json.h>
#include <sourcemeta/core/openapi.h>
#include <cassert>
#include <string_view>
static auto resolver(const std::string_view identifier)
assert(identifier == "https://example.com/shared.json");
"openapi": "3.1.1",
"info": { "title": "Shared", "version": "1.0.0" },
"components": {
"responses": { "NotFound": { "description": "Not found" } }
}
})JSON");
}
auto document{sourcemeta::core::parse_json(R"JSON({
"openapi": "3.1.1",
"info": { "title": "Example", "version": "1.0.0" },
"paths": {
"/pets": {
"get": {
"responses": {
"404": { "$ref": "shared.json#/components/responses/NotFound" }
}
}
}
}
})JSON")};
{.default_base = "https://example.com/openapi.json"});
assert(document.at("components").at("responses").defines("NotFound"));

◆ openapi_format()

SOURCEMETA_CORE_OPENAPI_EXPORT auto sourcemeta::core::openapi_format ( JSON & document,
const OpenAPIFrame & frame ) -> void

This function reorders an OpenAPI Description in place, following an opinionated OpenAPI aware order, and hands every Schema Object it holds to the JSON Schema formatter. Note that doing so invalidates the given frame, as the locations it holds point into the document. For example:

#include <sourcemeta/core/json.h>
#include <sourcemeta/core/jsonschema.h>
#include <sourcemeta/core/openapi.h>
#include <iostream>
auto document = sourcemeta::core::parse_json(R"JSON({
"info": { "version": "1.0.0", "title": "Example" },
"paths": {},
"openapi": "3.1.1"
})JSON");
sourcemeta::core::prettify(document, std::cout);
SOURCEMETA_CORE_OPENAPI_EXPORT auto openapi_format(JSON &document, const OpenAPIFrame &frame) -> void

◆ openapi_kind_name()

SOURCEMETA_CORE_OPENAPI_EXPORT auto sourcemeta::core::openapi_kind_name ( const OpenAPIFrame::ObjectKind kind) -> JSON::StringView
noexcept

The name that a frame exports a kind of Object as, which is the name the specification gives that Object hyphenated and in lower case. For example:

#include <sourcemeta/core/openapi.h>
#include <cassert>
"path-item");
@ PathItem
A Path Item Object, which describes the operations available on one path.
Definition openapi.h:183
SOURCEMETA_CORE_OPENAPI_EXPORT auto openapi_kind_name(const OpenAPIFrame::ObjectKind kind) noexcept -> JSON::StringView

◆ openapi_operation_kind_name()

SOURCEMETA_CORE_OPENAPI_EXPORT auto sourcemeta::core::openapi_operation_kind_name ( const OpenAPIFrame::OperationKind kind) -> JSON::StringView
noexcept

The name that a frame exports a route to an operation as. For example:

#include <sourcemeta/core/openapi.h>
#include <cassert>
"webhook");
@ Webhook
Reached through the webhooks that the entry document declares.
Definition openapi.h:253
SOURCEMETA_CORE_OPENAPI_EXPORT auto openapi_operation_kind_name(const OpenAPIFrame::OperationKind kind) noexcept -> JSON::StringView

◆ openapi_version()

SOURCEMETA_CORE_OPENAPI_EXPORT auto sourcemeta::core::openapi_version ( const JSON & document) -> std::optional< OpenAPIVersion >

Determine the version of an OpenAPI Description from its OpenAPI field without framing it, returning no value for a version we do not recognise and for anything that declares no such field to read. The patch component of the field carries no meaning, so every 3.1.x release maps to the same result. For example:

#include <sourcemeta/core/json.h>
#include <sourcemeta/core/openapi.h>
#include <cassert>
const auto document{sourcemeta::core::parse_json(R"({
"openapi": "3.1.1",
"info": { "title": "Example", "version": "1.0.0" },
"paths": {}
})")};
assert(sourcemeta::core::openapi_version(document).value() ==
SOURCEMETA_CORE_OPENAPI_EXPORT auto openapi_version(const JSON &document) -> std::optional< OpenAPIVersion >

◆ openapi_version_name()

SOURCEMETA_CORE_OPENAPI_EXPORT auto sourcemeta::core::openapi_version_name ( const OpenAPIVersion version) -> JSON::StringView
noexcept

The feature set a version designates, which OpenAPI Specification 3.1.1, Section 4.1 spells as "the `major`.`minor` portion of the version string". For example:

#include <sourcemeta/core/openapi.h>
#include <cassert>
SOURCEMETA_CORE_OPENAPI_EXPORT auto openapi_version_name(const OpenAPIVersion version) noexcept -> JSON::StringView