libopenapi

package module
v0.13.11 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 17, 2023 License: MIT Imports: 12 Imported by: 70

README

libopenapi

libopenapi - enterprise grade OpenAPI tools for golang.

Pipeline GoReportCard codecov discord Docs

libopenapi has full support for Swagger (OpenAPI 2), OpenAPI 3, and OpenAPI 3.1. It can handle the largest and most complex specifications you can think of.


Sponsors & users

If your company is using libopenapi, please considering supporting this project, like our very kind sponsors:

speakeasy'

Speakeasy

scalar'

scalar


libopenapi is pretty new, so our list of notable projects that depend on libopenapi is small (let me know if you'd like to add your project)


Come chat with us

Need help? Have a question? Want to share your work? Join our discord and come say hi!

Check out the libopenapi-validator

Need to validate requests, responses, parameters or schemas? Use the new libopenapi-validator module.

Documentation

See all the documentation at https://pb33f.io/libopenapi/

Read the go docs at https://pkg.go.dev/github.com/pb33f/libopenapi


Quick-start tutorial

👀 Get rolling fast using libopenapi with the Parsing OpenAPI files using go guide 👀

Read the full docs at https://pkg.go.dev


Logo gopher is modified, originally from egonelbre

Documentation

Overview

Package libopenapi is a library containing tools for reading and in and manipulating Swagger (OpenAPI 2) and OpenAPI 3+ specifications into strongly typed documents. These documents have two APIs, a high level (porcelain) and a low level (plumbing).

Every single type has a 'GoLow()' method that drops down from the high API to the low API. Once in the low API, the entire original document data is available, including all comments, line and column numbers for keys and values.

There are two steps to creating a using Document. First, create a new Document using the NewDocument() method and pass in a specification []byte array that contains the OpenAPI Specification. It doesn't matter if YAML or JSON are used.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func CompareDocuments added in v0.2.0

func CompareDocuments(original, updated Document) (*model.DocumentChanges, []error)

CompareDocuments will accept a left and right Document implementing struct, build a model for the correct version and then compare model documents for changes.

If there are any errors when building the models, those errors are returned with a nil pointer for the model.DocumentChanges. If there are any changes found however between either Document, then a pointer to model.DocumentChanges is returned containing every single change, broken down, model by model.

Example (OpenAPI)
// How to compare two different OpenAPI specifications.

// load an original OpenAPI 3 specification from bytes
burgerShopOriginal, _ := os.ReadFile("test_specs/burgershop.openapi.yaml")

// load an **updated** OpenAPI 3 specification from bytes
burgerShopUpdated, _ := os.ReadFile("test_specs/burgershop.openapi-modified.yaml")

// create a new document from original specification bytes
originalDoc, err := NewDocument(burgerShopOriginal)

// if anything went wrong, an error is thrown
if err != nil {
	panic(fmt.Sprintf("cannot create new document: %e", err))
}

// create a new document from updated specification bytes
updatedDoc, err := NewDocument(burgerShopUpdated)

// if anything went wrong, an error is thrown
if err != nil {
	panic(fmt.Sprintf("cannot create new document: %e", err))
}

// Compare documents for all changes made
documentChanges, errs := CompareDocuments(originalDoc, updatedDoc)

// If anything went wrong when building models for documents.
if len(errs) > 0 {
	for i := range errs {
		fmt.Printf("error: %e\n", errs[i])
	}
	panic(fmt.Sprintf("cannot compare documents: %d errors reported", len(errs)))
}

// Extract SchemaChanges from components changes.
schemaChanges := documentChanges.ComponentsChanges.SchemaChanges

// Print out some interesting stats about the OpenAPI document changes.
fmt.Printf("There are %d changes, of which %d are breaking. %v schemas have changes.",
	documentChanges.TotalChanges(), documentChanges.TotalBreakingChanges(), len(schemaChanges))
Output:

There are 75 changes, of which 19 are breaking. 6 schemas have changes.
Example (Swagger)
// How to compare two different Swagger specifications.

// load an original OpenAPI 3 specification from bytes
petstoreOriginal, _ := os.ReadFile("test_specs/petstorev2-complete.yaml")

// load an **updated** OpenAPI 3 specification from bytes
petstoreUpdated, _ := os.ReadFile("test_specs/petstorev2-complete-modified.yaml")

// create a new document from original specification bytes
originalDoc, err := NewDocument(petstoreOriginal)

// if anything went wrong, an error is thrown
if err != nil {
	panic(fmt.Sprintf("cannot create new document: %e", err))
}

// create a new document from updated specification bytes
updatedDoc, err := NewDocument(petstoreUpdated)

// if anything went wrong, an error is thrown
if err != nil {
	panic(fmt.Sprintf("cannot create new document: %e", err))
}

// Compare documents for all changes made
documentChanges, errs := CompareDocuments(originalDoc, updatedDoc)

// If anything went wrong when building models for documents.
if len(errs) > 0 {
	for i := range errs {
		fmt.Printf("error: %e\n", errs[i])
	}
	panic(fmt.Sprintf("cannot compare documents: %d errors reported", len(errs)))
}

// Extract SchemaChanges from components changes.
schemaChanges := documentChanges.ComponentsChanges.SchemaChanges

// Print out some interesting stats about the Swagger document changes.
fmt.Printf("There are %d changes, of which %d are breaking. %v schemas have changes.",
	documentChanges.TotalChanges(), documentChanges.TotalBreakingChanges(), len(schemaChanges))
Output:

There are 52 changes, of which 27 are breaking. 5 schemas have changes.

Types

type Document

type Document interface {
	// GetVersion will return the exact version of the OpenAPI specification set for the document.
	GetVersion() string

	// GetRolodex will return the Rolodex instance that was used to load the document.
	GetRolodex() *index.Rolodex

	// GetSpecInfo will return the *datamodel.SpecInfo instance that contains all specification information.
	GetSpecInfo() *datamodel.SpecInfo

	// SetConfiguration will set the configuration for the document. This allows for finer grained control over
	// allowing remote or local references, as well as a BaseURL to allow for relative file references.
	SetConfiguration(configuration *datamodel.DocumentConfiguration)

	// GetConfiguration will return the configuration for the document. This allows for finer grained control over
	// allowing remote or local references, as well as a BaseURL to allow for relative file references.
	GetConfiguration() *datamodel.DocumentConfiguration

	// BuildV2Model will build out a Swagger (version 2) model from the specification used to create the document
	// If there are any issues, then no model will be returned, instead a slice of errors will explain all the
	// problems that occurred. This method will only support version 2 specifications and will throw an error for
	// any other types.
	BuildV2Model() (*DocumentModel[v2high.Swagger], []error)

	// BuildV3Model will build out an OpenAPI (version 3+) model from the specification used to create the document
	// If there are any issues, then no model will be returned, instead a slice of errors will explain all the
	// problems that occurred. This method will only support version 3 specifications and will throw an error for
	// any other types.
	BuildV3Model() (*DocumentModel[v3high.Document], []error)

	// RenderAndReload will render the high level model as it currently exists (including any mutations, additions
	// and removals to and from any object in the tree). It will then reload the low level model with the new bytes
	// extracted from the model that was re-rendered. This is useful if you want to make changes to the high level model
	// and then 'reload' the model into memory, so that line numbers and column numbers are correct and all update
	// according to the changes made.
	//
	// The method returns the raw YAML bytes that were rendered, and any errors that occurred during rebuilding of the model.
	// This is a destructive operation, and will re-build the entire model from scratch using the new bytes, so any
	// references to the old model will be lost. The second return is the new Document that was created, and the third
	// return is any errors hit trying to re-render.
	//
	// **IMPORTANT** This method only supports OpenAPI Documents. The Swagger model will not support mutations correctly
	// and will not update when called. This choice has been made because we don't want to continue supporting Swagger,
	// it's too old, so it should be motivation to upgrade to OpenAPI 3.
	RenderAndReload() ([]byte, Document, *DocumentModel[v3high.Document], []error)

	// Render will render the high level model as it currently exists (including any mutations, additions
	// and removals to and from any object in the tree). Unlike RenderAndReload, Render will simply print the state
	// of the model as it currently exists, and will not re-load the model into memory. It means that the low-level and
	// the high-level models will be out of sync, and the index will only be useful for the original document.
	//
	// Why use this instead of RenderAndReload?
	//
	// The simple answer is that RenderAndReload is a destructive operation, and will re-build the entire model from
	// scratch using the new bytes, which is desirable if you want to make changes to the high level model and then
	// 'reload' the model into memory, so that line numbers and column numbers are correct and the index is accurate.
	// However, if you don't care about the low-level model, and you're not using the index, and you just want to
	// print the state of the model as it currently exists, then Render() is the method to use.
	// **IMPORTANT** This method only supports OpenAPI Documents.
	Render() ([]byte, error)

	// Serialize will re-render a Document back into a []byte slice. If any modifications have been made to the
	// underlying data model using low level APIs, then those changes will be reflected in the serialized output.
	//
	// It's important to know that this should not be used if the resolver has been used on a specification to
	// for anything other than checking for circular references. If the resolver is used to resolve the spec, then this
	// method may spin out forever if the specification backing the model has circular references.
	// Deprecated: This method is deprecated and will be removed in a future release. Use RenderAndReload() instead.
	// This method does not support mutations correctly.
	Serialize() ([]byte, error)
}

Document Represents an OpenAPI specification that can then be rendered into a model or serialized back into a string document after being manipulated.

func NewDocument

func NewDocument(specByteArray []byte) (Document, error)

NewDocument will create a new OpenAPI instance from an OpenAPI specification []byte array. If anything goes wrong when parsing, reading or processing the OpenAPI specification, there will be no document returned, instead a slice of errors will be returned that explain everything that failed.

After creating a Document, the option to build a model becomes available, in either V2 or V3 flavors. The models are about 70% different between Swagger and OpenAPI 3, which is why two different models are available.

This function will automatically follow (meaning load) any file or remote references that are found anywhere. Which means recursively also, like a spider, it will follow every reference found, local or remote.

If this isn't the behavior you want, or that you feel this is a potential security risk, then you can use the NewDocumentWithConfiguration() function instead, which allows you to set a configuration that will allow you to control if file or remote references are allowed.

Example (FromOpenAPI3Document)
// How to read in an OpenAPI 3 Specification, into a Document.

// load an OpenAPI 3 specification from bytes
petstore, _ := os.ReadFile("test_specs/petstorev3.json")

// create a new document from specification bytes
document, err := NewDocument(petstore)

// if anything went wrong, an error is thrown
if err != nil {
	panic(fmt.Sprintf("cannot create new document: %e", err))
}

// because we know this is a v3 spec, we can build a ready to go model from it.
v3Model, errors := document.BuildV3Model()

// if anything went wrong when building the v3 model, a slice of errors will be returned
if len(errors) > 0 {
	for i := range errors {
		fmt.Printf("error: %e\n", errors[i])
	}
	panic(fmt.Sprintf("cannot create v3 model from document: %d errors reported", len(errors)))
}

// get a count of the number of paths and schemas.
paths := len(v3Model.Model.Paths.PathItems)
schemas := len(v3Model.Model.Components.Schemas)

// print the number of paths and schemas in the document
fmt.Printf("There are %d paths and %d schemas in the document", paths, schemas)
Output:

There are 13 paths and 8 schemas in the document
Example (FromSwaggerDocument)
// How to read in a Swagger / OpenAPI 2 Specification, into a Document.

// load a Swagger specification from bytes
petstore, _ := os.ReadFile("test_specs/petstorev2.json")

// create a new document from specification bytes
document, err := NewDocument(petstore)

// if anything went wrong, an error is thrown
if err != nil {
	panic(fmt.Sprintf("cannot create new document: %e", err))
}

// because we know this is a v2 spec, we can build a ready to go model from it.
v2Model, errors := document.BuildV2Model()

// if anything went wrong when building the v3 model, a slice of errors will be returned
if len(errors) > 0 {
	for i := range errors {
		fmt.Printf("error: %e\n", errors[i])
	}
	panic(fmt.Sprintf("cannot create v3 model from document: %d errors reported", len(errors)))
}

// get a count of the number of paths and schemas.
paths := len(v2Model.Model.Paths.PathItems)
schemas := len(v2Model.Model.Definitions.Definitions)

// print the number of paths and schemas in the document
fmt.Printf("There are %d paths and %d schemas in the document", paths, schemas)
Output:

There are 14 paths and 6 schemas in the document
Example (FromUnknownVersion)
// load an unknown version of an OpenAPI spec
petstore, _ := os.ReadFile("test_specs/burgershop.openapi.yaml")

// create a new document from specification bytes
document, err := NewDocument(petstore)

// if anything went wrong, an error is thrown
if err != nil {
	panic(fmt.Sprintf("cannot create new document: %e", err))
}

var paths, schemas int
var errors []error

// We don't know which type of document this is, so we can use the spec info to inform us
if document.GetSpecInfo().SpecType == utils.OpenApi3 {
	v3Model, errs := document.BuildV3Model()
	if len(errs) > 0 {
		errors = errs
	}
	if len(errors) <= 0 {
		paths = len(v3Model.Model.Paths.PathItems)
		schemas = len(v3Model.Model.Components.Schemas)
	}
}
if document.GetSpecInfo().SpecType == utils.OpenApi2 {
	v2Model, errs := document.BuildV2Model()
	if len(errs) > 0 {
		errors = errs
	}
	if len(errors) <= 0 {
		paths = len(v2Model.Model.Paths.PathItems)
		schemas = len(v2Model.Model.Definitions.Definitions)
	}
}

// if anything went wrong when building the model, report errors.
if len(errors) > 0 {
	for i := range errors {
		fmt.Printf("error: %e\n", errors[i])
	}
	panic(fmt.Sprintf("cannot create v3 model from document: %d errors reported", len(errors)))
}

// print the number of paths and schemas in the document
fmt.Printf("There are %d paths and %d schemas in the document", paths, schemas)
Output:

There are 5 paths and 6 schemas in the document
Example (FromWithDocumentConfigurationFailure)
// This example shows how to create a document that prevents the loading of external references/
// from files or the network

// load in the Digital Ocean OpenAPI specification
digitalOcean, _ := os.ReadFile("test_specs/digitalocean.yaml")

// create a DocumentConfiguration that prevents loading file and remote references
config := datamodel.NewDocumentConfiguration()

// create a new structured logger to capture error logs that will be spewed out by the rolodex
// when it tries to load external references. We're going to create a byte buffer to capture the logs
// and then look at them after the document is built.
var logs []byte
buf := bytes.NewBuffer(logs)
logger := slog.New(slog.NewTextHandler(buf, &slog.HandlerOptions{
	Level: slog.LevelError,
}))
config.Logger = logger // set the config logger to our new logger.

// Do not set any baseURL, as this will allow the rolodex to resolve relative references.
// without a baseURL (for remote references, or a basePath for local references) the rolodex
// will consider the reference to be local, and will not attempt to load it from the network.

// create a new document from specification bytes
doc, err := NewDocumentWithConfiguration(digitalOcean, config)

// if anything went wrong, an error is thrown
if err != nil {
	panic(fmt.Sprintf("cannot create new document: %e", err))
}

// only errors will be thrown, so just capture them and print the number of errors.
_, errors := doc.BuildV3Model()

// there should be 475 errors logs
logItems := strings.Split(buf.String(), "\n")
fmt.Printf("There are %d errors logged\n", len(logItems))

// if anything went wrong when building the v3 model, a slice of errors will be returned
if len(errors) > 0 {
	fmt.Println("Error building Digital Ocean spec errors reported")
}
Output:

There are 475 errors logged
Error building Digital Ocean spec errors reported
Example (FromWithDocumentConfigurationSuccess)
// This example shows how to create a document that prevents the loading of external references/
// from files or the network

// load in the Digital Ocean OpenAPI specification
digitalOcean, _ := os.ReadFile("test_specs/digitalocean.yaml")

// Digital Ocean needs a baseURL to be set, so we can resolve relative references.
baseURL, _ := url.Parse("https://raw.githubusercontent.com/digitalocean/openapi/main/specification")

// create a DocumentConfiguration that allows loading file and remote references, and sets the baseURL
// to somewhere that can resolve the relative references.
config := datamodel.DocumentConfiguration{
	BaseURL: baseURL,
	Logger: slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
		Level: slog.LevelError,
	})),
}

// create a new document from specification bytes
doc, err := NewDocumentWithConfiguration(digitalOcean, &config)

// if anything went wrong, an error is thrown
if err != nil {
	panic(fmt.Sprintf("cannot create new document: %e", err))
}

// only errors will be thrown, so just capture them and print the number of errors.
_, errors := doc.BuildV3Model()

// if anything went wrong when building the v3 model, a slice of errors will be returned
if len(errors) > 0 {
	fmt.Println("Error building Digital Ocean spec errors reported")
} else {
	fmt.Println("Digital Ocean spec built successfully")
}
Output:

Digital Ocean spec built successfully
Example (Infinite_circular_references)

If you want to know more about circular references that have been found during the parsing/indexing/building of a document, you can capture the []errors thrown which are pointers to *resolver.ResolvingError

// create a specification with an obvious and deliberate circular reference
spec := `openapi: "3.1"
components:
  schemas:
    One:
      description: "test one"
      properties:
        things:
          "$ref": "#/components/schemas/Two"
      required:
        - things
    Two:
      description: "test two"
      properties:
        testThing:
          "$ref": "#/components/schemas/One"
      required:
        - testThing
`
// create a new document from specification bytes
doc, err := NewDocument([]byte(spec))

// if anything went wrong, an error is thrown
if err != nil {
	panic(fmt.Sprintf("cannot create new document: %e", err))
}
_, errs := doc.BuildV3Model()

// extract resolving error
resolvingError := errs[0]

// resolving error is a pointer to *resolver.ResolvingError
// which provides access to rich details about the error.
circularReference := resolvingError.(*index.ResolvingError).CircularReference

// capture the journey with all details
var buf strings.Builder
for n := range circularReference.Journey {

	// add the full definition name to the journey.
	buf.WriteString(circularReference.Journey[n].Definition)
	if n < len(circularReference.Journey)-1 {
		buf.WriteString(" -> ")
	}
}

// print out the journey and the loop point.
fmt.Printf("Journey: %s\n", buf.String())
fmt.Printf("Loop Point: %s", circularReference.LoopPoint.Definition)
Output:

Journey: #/components/schemas/Two -> #/components/schemas/One -> #/components/schemas/Two
Loop Point: #/components/schemas/Two
Example (ModifyAndReRender)
// How to read in an OpenAPI 3 Specification, into a Document,
// modify the document and then re-render it back to YAML bytes.

// load an OpenAPI 3 specification from bytes
petstore, _ := os.ReadFile("test_specs/petstorev3.json")

// create a new document from specification bytes
doc, err := NewDocument(petstore)

// if anything went wrong, an error is thrown
if err != nil {
	panic(fmt.Sprintf("cannot create new document: %e", err))
}

// because we know this is a v3 spec, we can build a ready to go model from it.
v3Model, errors := doc.BuildV3Model()

// if anything went wrong when building the v3 model, a slice of errors will be returned
if len(errors) > 0 {
	for i := range errors {
		fmt.Printf("error: %e\n", errors[i])
	}
	panic(fmt.Sprintf("cannot create v3 model from document: %d errors reported", len(errors)))
}

// create a new path item and operation.
newPath := &v3high.PathItem{
	Description: "this is a new path item",
	Get: &v3high.Operation{
		Description: "this is a get operation",
		OperationId: "getNewThing",
		RequestBody: &v3high.RequestBody{
			Description: "this is a new request body",
		},
	},
}

// capture original number of paths
originalPaths := len(v3Model.Model.Paths.PathItems)

// add the path to the document
v3Model.Model.Paths.PathItems["/new/path"] = newPath

// render the document back to bytes and reload the model.
rawBytes, _, newModel, errs := doc.RenderAndReload()

// if anything went wrong when re-rendering the v3 model, a slice of errors will be returned
if len(errors) > 0 {
	panic(fmt.Sprintf("cannot re-render document: %d errors reported", len(errs)))
}

// capture new number of paths after re-rendering
newPaths := len(newModel.Model.Paths.PathItems)

// print the number of paths and schemas in the document
fmt.Printf("There were %d original paths. There are now %d paths in the document\n", originalPaths, newPaths)
fmt.Printf("The original spec had %d bytes, the new one has %d\n", len(petstore), len(rawBytes))
Output:

There were 13 original paths. There are now 14 paths in the document
The original spec had 31143 bytes, the new one has 31027
Example (MutateValuesAndSerialize)
// How to mutate values in an OpenAPI Specification, without re-ordering original content.

// create very small, and useless spec that does nothing useful, except showcase this feature.
spec := `
openapi: 3.1.0
info:
  title: This is a title
  contact:
    name: Some Person
    email: some@emailaddress.com
  license:
    url: https://some-place-on-the-internet.com/license
`
// create a new document from specification bytes
document, err := NewDocument([]byte(spec))

// if anything went wrong, an error is thrown
if err != nil {
	panic(fmt.Sprintf("cannot create new document: %e", err))
}

// because we know this is a v3 spec, we can build a ready to go model from it.
v3Model, errors := document.BuildV3Model()

// if anything went wrong when building the v3 model, a slice of errors will be returned
if len(errors) > 0 {
	for i := range errors {
		fmt.Printf("error: %e\n", errors[i])
	}
	panic(fmt.Sprintf("cannot create v3 model from document: %d errors reported", len(errors)))
}

// mutate the title, to do this we currently need to drop down to the low-level API.
v3Model.Model.GoLow().Info.Value.Title.Mutate("A new title for a useless spec")

// mutate the email address in the contact object.
v3Model.Model.GoLow().Info.Value.Contact.Value.Email.Mutate("buckaroo@pb33f.io")

// mutate the name in the contact object.
v3Model.Model.GoLow().Info.Value.Contact.Value.Name.Mutate("Buckaroo")

// mutate the URL for the license object.
v3Model.Model.GoLow().Info.Value.License.Value.URL.Mutate("https://pb33f.io/license")

// serialize the document back into the original YAML or JSON
mutatedSpec, serialError := document.Serialize()

// if something went wrong serializing
if serialError != nil {
	panic(fmt.Sprintf("cannot serialize document: %e", serialError))
}

// print our modified spec!
fmt.Println(string(mutatedSpec))
Output:

openapi: 3.1.0
info:
    title: A new title for a useless spec
    contact:
        name: Buckaroo
        email: buckaroo@pb33f.io
    license:
        url: https://pb33f.io/license
Example (Unpacking_extensions)

If you're using complex types with OpenAPI Extensions, it's simple to unpack extensions into complex types using `high.UnpackExtensions()`. libopenapi retains the original raw data in the low model (not the high) which means unpacking them can be a little complex.

This example demonstrates how to use the `UnpackExtensions` with custom OpenAPI extensions.

// define an example struct representing a cake
type cake struct {
	Candles               int    `yaml:"candles"`
	Frosting              string `yaml:"frosting"`
	Some_Strange_Var_Name string `yaml:"someStrangeVarName"`
}

// define a struct that holds a map of cake pointers.
type cakes struct {
	Description string
	Cakes       map[string]*cake
}

// define a struct representing a burger
type burger struct {
	Sauce string
	Patty string
}

// define a struct that holds a map of cake pointers
type burgers struct {
	Description string
	Burgers     map[string]*burger
}

// create a specification with a schema and parameter that use complex custom cakes and burgers extensions.
spec := `openapi: "3.1"
components:
  schemas:
    SchemaOne:
      description: "Some schema with custom complex extensions"
      x-custom-cakes:
        description: some cakes
        cakes:
          someCake:
            candles: 10
            frosting: blue
            someStrangeVarName: something
          anotherCake:
            candles: 1
            frosting: green
  parameters:
    ParameterOne:
      description: "Some parameter also using complex extensions"
      x-custom-burgers:
        description: some burgers
        burgers:
          someBurger:
            sauce: ketchup
            patty: meat 
          anotherBurger:
            sauce: mayo
            patty: lamb`
// create a new document from specification bytes
doc, err := NewDocument([]byte(spec))

// if anything went wrong, an error is thrown
if err != nil {
	panic(fmt.Sprintf("cannot create new document: %e", err))
}

// build a v3 model.
docModel, errs := doc.BuildV3Model()

// if anything went wrong building, indexing and resolving the model, an error is thrown
if errs != nil {
	panic(fmt.Sprintf("cannot create new document: %e", err))
}

// get a reference to SchemaOne and ParameterOne
schemaOne := docModel.Model.Components.Schemas["SchemaOne"].Schema()
parameterOne := docModel.Model.Components.Parameters["ParameterOne"]

// unpack schemaOne extensions into complex `cakes` type
schemaOneExtensions, schemaUnpackErrors := high.UnpackExtensions[cakes, *low.Schema](schemaOne)
if schemaUnpackErrors != nil {
	panic(fmt.Sprintf("cannot unpack schema extensions: %e", err))
}

// unpack parameterOne into complex `burgers` type
parameterOneExtensions, paramUnpackErrors := high.UnpackExtensions[burgers, *v3.Parameter](parameterOne)
if paramUnpackErrors != nil {
	panic(fmt.Sprintf("cannot unpack parameter extensions: %e", err))
}

// extract extension by name for schemaOne
customCakes := schemaOneExtensions["x-custom-cakes"]

// extract extension by name for schemaOne
customBurgers := parameterOneExtensions["x-custom-burgers"]

// print out schemaOne complex extension details.
fmt.Printf("schemaOne 'x-custom-cakes' (%s) has %d cakes, 'someCake' has %d candles and %s frosting\n",
	customCakes.Description,
	len(customCakes.Cakes),
	customCakes.Cakes["someCake"].Candles,
	customCakes.Cakes["someCake"].Frosting,
)

// print out parameterOne complex extension details.
fmt.Printf("parameterOne 'x-custom-burgers' (%s) has %d burgers, 'anotherBurger' has %s sauce and a %s patty\n",
	customBurgers.Description,
	len(customBurgers.Burgers),
	customBurgers.Burgers["anotherBurger"].Sauce,
	customBurgers.Burgers["anotherBurger"].Patty,
)
Output:

schemaOne 'x-custom-cakes' (some cakes) has 2 cakes, 'someCake' has 10 candles and blue frosting
parameterOne 'x-custom-burgers' (some burgers) has 2 burgers, 'anotherBurger' has mayo sauce and a lamb patty

func NewDocumentWithConfiguration added in v0.6.0

func NewDocumentWithConfiguration(specByteArray []byte, configuration *datamodel.DocumentConfiguration) (Document, error)

NewDocumentWithConfiguration is the same as NewDocument, except it's a convenience function that calls NewDocument under the hood and then calls SetConfiguration() on the returned Document.

func NewDocumentWithTypeCheck added in v0.9.6

func NewDocumentWithTypeCheck(specByteArray []byte, bypassCheck bool) (Document, error)

type DocumentModel

type DocumentModel[T v2high.Swagger | v3high.Document] struct {
	Model T
	Index *index.SpecIndex // index created from the document.
}

DocumentModel represents either a Swagger document (version 2) or an OpenAPI document (version 3) that is built from a parent Document.

Directories

Path Synopsis
Package datamodel contains two sets of models, high and low.
Package datamodel contains two sets of models, high and low.
high
Package high contains a set of high-level models that represent OpenAPI 2 and 3 documents.
Package high contains a set of high-level models that represent OpenAPI 2 and 3 documents.
high/base
Package base contains shared high-level models that are used between both versions 2 and 3 of OpenAPI.
Package base contains shared high-level models that are used between both versions 2 and 3 of OpenAPI.
high/v2
Package v2 represents all Swagger / OpenAPI 2 high-level models.
Package v2 represents all Swagger / OpenAPI 2 high-level models.
high/v3
Package v3 represents all OpenAPI 3+ high-level models.
Package v3 represents all OpenAPI 3+ high-level models.
low
Package low contains a set of low-level models that represent OpenAPI 2 and 3 documents.
Package low contains a set of low-level models that represent OpenAPI 2 and 3 documents.
low/base
Package base contains shared low-level models that are used between both versions 2 and 3 of OpenAPI.
Package base contains shared low-level models that are used between both versions 2 and 3 of OpenAPI.
low/v2
Package v2 represents all Swagger / OpenAPI 2 low-level models.
Package v2 represents all Swagger / OpenAPI 2 low-level models.
low/v3
Package v3 represents all OpenAPI 3+ low-level models.
Package v3 represents all OpenAPI 3+ low-level models.
Package index contains an OpenAPI indexer that will very quickly scan through an OpenAPI specification (all versions) and extract references to all the important nodes you might want to look up, as well as counts on total objects.
Package index contains an OpenAPI indexer that will very quickly scan through an OpenAPI specification (all versions) and extract references to all the important nodes you might want to look up, as well as counts on total objects.
Package what_changed
Package what_changed
model
Package model
Package model

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL