mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-08 20:47:43 +00:00
Operating at speed now.
Stripe API is slowest to build at about 1.2s, the depth of the schemas on that spec are insane. The only way to speed things up here is to NOT wait for threads to finish before returning the model, and this creates a broken guarantee as the model won't be finished building by the time its returned to the consumer. When running tests against this - they fail randomly. depending on which thread reaches the finish first, before trying to be read. This isn't an option, so for now, this is as fast as she will get, which is pretty good. 5ms for petstore and about 250ms for k8s.
This commit is contained in:
@@ -32,7 +32,7 @@ func (i *Info) Build(root *yaml.Node) error {
|
|||||||
license := License{}
|
license := License{}
|
||||||
_, kln, ln := utils.FindKeyNodeFull("license", root.Content)
|
_, kln, ln := utils.FindKeyNodeFull("license", root.Content)
|
||||||
go BuildModelAsync(ln, &license, &wg, &errs)
|
go BuildModelAsync(ln, &license, &wg, &errs)
|
||||||
wg.Wait()
|
//wg.Wait()
|
||||||
i.Contact = low.NodeReference[*Contact]{Value: &contact, ValueNode: cn, KeyNode: kln}
|
i.Contact = low.NodeReference[*Contact]{Value: &contact, ValueNode: cn, KeyNode: kln}
|
||||||
i.License = low.NodeReference[*License]{Value: &license, ValueNode: ln, KeyNode: kln}
|
i.License = low.NodeReference[*License]{Value: &license, ValueNode: ln, KeyNode: kln}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ func (p *PathItem) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
|||||||
var op Operation
|
var op Operation
|
||||||
|
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
BuildModelAsync(pathNode, &op, &wg, &errors)
|
go BuildModelAsync(pathNode, &op, &wg, &errors)
|
||||||
|
|
||||||
opRef := low.NodeReference[*Operation]{
|
opRef := low.NodeReference[*Operation]{
|
||||||
Value: &op,
|
Value: &op,
|
||||||
|
|||||||
@@ -1,99 +1,98 @@
|
|||||||
package v3
|
package v3
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
"github.com/pb33f/libopenapi/utils"
|
"github.com/pb33f/libopenapi/utils"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
LinksLabel = "links"
|
LinksLabel = "links"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Responses struct {
|
type Responses struct {
|
||||||
Codes map[low.KeyReference[string]]low.ValueReference[*Response]
|
Codes map[low.KeyReference[string]]low.ValueReference[*Response]
|
||||||
Default low.NodeReference[*Response]
|
Default low.NodeReference[*Response]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Responses) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
func (r *Responses) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
||||||
if utils.IsNodeMap(root) {
|
if utils.IsNodeMap(root) {
|
||||||
codes, err := ExtractMapFlatNoLookup[*Response](root, idx)
|
codes, err := ExtractMapFlatNoLookup[*Response](root, idx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if codes != nil {
|
if codes != nil {
|
||||||
r.Codes = codes
|
r.Codes = codes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Responses) FindResponseByCode(code string) *low.ValueReference[*Response] {
|
func (r *Responses) FindResponseByCode(code string) *low.ValueReference[*Response] {
|
||||||
return FindItemInMap[*Response](code, r.Codes)
|
return FindItemInMap[*Response](code, r.Codes)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Response struct {
|
type Response struct {
|
||||||
Description low.NodeReference[string]
|
Description low.NodeReference[string]
|
||||||
Headers low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Header]]
|
Headers low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Header]]
|
||||||
Content low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*MediaType]]
|
Content low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*MediaType]]
|
||||||
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
||||||
Links low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Link]]
|
Links low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Link]]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Response) FindContent(cType string) *low.ValueReference[*MediaType] {
|
func (r *Response) FindContent(cType string) *low.ValueReference[*MediaType] {
|
||||||
return FindItemInMap[*MediaType](cType, r.Content.Value)
|
return FindItemInMap[*MediaType](cType, r.Content.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Response) FindHeader(hType string) *low.ValueReference[*Header] {
|
func (r *Response) FindHeader(hType string) *low.ValueReference[*Header] {
|
||||||
return FindItemInMap[*Header](hType, r.Headers.Value)
|
return FindItemInMap[*Header](hType, r.Headers.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Response) FindLink(hType string) *low.ValueReference[*Link] {
|
func (r *Response) FindLink(hType string) *low.ValueReference[*Link] {
|
||||||
return FindItemInMap[*Link](hType, r.Links.Value)
|
return FindItemInMap[*Link](hType, r.Links.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Response) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
func (r *Response) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
||||||
r.Extensions = ExtractExtensions(root)
|
r.Extensions = ExtractExtensions(root)
|
||||||
|
|
||||||
// extract headers
|
// extract headers
|
||||||
headers, lN, kN, err := ExtractMapFlat[*Header](HeadersLabel, root, idx)
|
headers, lN, kN, err := ExtractMapFlat[*Header](HeadersLabel, root, idx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if headers != nil {
|
if headers != nil {
|
||||||
r.Headers = low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Header]]{
|
r.Headers = low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Header]]{
|
||||||
Value: headers,
|
Value: headers,
|
||||||
KeyNode: lN,
|
KeyNode: lN,
|
||||||
ValueNode: kN,
|
ValueNode: kN,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle content, if set.
|
con, clN, cN, cErr := ExtractMapFlat[*MediaType](ContentLabel, root, idx)
|
||||||
con, clN, cN, cErr := ExtractMapFlat[*MediaType](ContentLabel, root, idx)
|
if cErr != nil {
|
||||||
if cErr != nil {
|
return cErr
|
||||||
return cErr
|
}
|
||||||
}
|
if con != nil {
|
||||||
if con != nil {
|
r.Content = low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*MediaType]]{
|
||||||
r.Content = low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*MediaType]]{
|
Value: con,
|
||||||
Value: con,
|
KeyNode: clN,
|
||||||
KeyNode: clN,
|
ValueNode: cN,
|
||||||
ValueNode: cN,
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// handle links if set
|
// handle links if set
|
||||||
links, linkLabel, linkValue, lErr := ExtractMapFlat[*Link](LinksLabel, root, idx)
|
links, linkLabel, linkValue, lErr := ExtractMapFlat[*Link](LinksLabel, root, idx)
|
||||||
if lErr != nil {
|
if lErr != nil {
|
||||||
return lErr
|
return lErr
|
||||||
}
|
}
|
||||||
if links != nil {
|
if links != nil {
|
||||||
r.Links = low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Link]]{
|
r.Links = low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Link]]{
|
||||||
Value: links,
|
Value: links,
|
||||||
KeyNode: linkLabel,
|
KeyNode: linkLabel,
|
||||||
ValueNode: linkValue,
|
ValueNode: linkValue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -886,7 +886,7 @@ func (index *SpecIndex) GetGlobalCallbacksCount() int {
|
|||||||
return index.globalCallbacksCount
|
return index.globalCallbacksCount
|
||||||
}
|
}
|
||||||
|
|
||||||
index.pathRefsLock.Lock()
|
//index.pathRefsLock.Lock()
|
||||||
for path, p := range index.pathRefs {
|
for path, p := range index.pathRefs {
|
||||||
for _, m := range p {
|
for _, m := range p {
|
||||||
|
|
||||||
@@ -918,7 +918,7 @@ func (index *SpecIndex) GetGlobalCallbacksCount() int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
index.pathRefsLock.Unlock()
|
//index.pathRefsLock.Unlock()
|
||||||
return index.globalCallbacksCount
|
return index.globalCallbacksCount
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -932,7 +932,7 @@ func (index *SpecIndex) GetGlobalLinksCount() int {
|
|||||||
return index.globalLinksCount
|
return index.globalLinksCount
|
||||||
}
|
}
|
||||||
|
|
||||||
index.pathRefsLock.Lock()
|
//index.pathRefsLock.Lock()
|
||||||
for path, p := range index.pathRefs {
|
for path, p := range index.pathRefs {
|
||||||
for _, m := range p {
|
for _, m := range p {
|
||||||
|
|
||||||
@@ -963,7 +963,7 @@ func (index *SpecIndex) GetGlobalLinksCount() int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
index.pathRefsLock.Unlock()
|
//index.pathRefsLock.Unlock()
|
||||||
return index.globalLinksCount
|
return index.globalLinksCount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,10 +15,6 @@ func CreateDocument(info *datamodel.SpecInfo) (*v3.Document, error) {
|
|||||||
|
|
||||||
// build an index
|
// build an index
|
||||||
idx := index.NewSpecIndex(info.RootNode)
|
idx := index.NewSpecIndex(info.RootNode)
|
||||||
//rsolvr := resolver.NewResolver()
|
|
||||||
|
|
||||||
// todo handle errors
|
|
||||||
//rsolvr.Resolve()
|
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
var errors []error
|
var errors []error
|
||||||
|
|||||||
@@ -35,6 +35,17 @@ func BenchmarkCreateDocument_Stripe(b *testing.B) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkCreateDocument_Petstore(b *testing.B) {
|
||||||
|
data, _ := ioutil.ReadFile("../test_specs/petstorev3.json")
|
||||||
|
info, _ := datamodel.ExtractSpecInfo(data)
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_, err := CreateDocument(info)
|
||||||
|
if err != nil {
|
||||||
|
panic("this should not error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCreateDocument(t *testing.T) {
|
func TestCreateDocument(t *testing.T) {
|
||||||
assert.Equal(t, "3.0.1", doc.Version.Value)
|
assert.Equal(t, "3.0.1", doc.Version.Value)
|
||||||
assert.Equal(t, "Burger Shop", doc.Info.Value.Title.Value)
|
assert.Equal(t, "Burger Shop", doc.Info.Value.Title.Value)
|
||||||
|
|||||||
Reference in New Issue
Block a user