Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding basic support for XML structure #328

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

DimShadoWWW
Copy link

This pull request introduces basic support for XML tags in OpenAPI documentation, allowing the following features to be defined for schema fields:

  1. Custom XML Element Names:
    The xml:"customName" struct tag allows specifying a custom name for the XML element.
  2. Attribute Definition:
    The xml:"name,attr" struct tag marks a field as an XML attribute.
  3. Wrapped Elements:
    The xml:"name,wrapped" struct tag enables support for wrapping elements (e.g., <items><item>...</item></items>).

Copy link
Collaborator

@dylanhitt dylanhitt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice to split the json tag stuff and the xml tag stuff into helper functions. This function is getting rather large.

openapi.go Outdated Show resolved Hide resolved
openapi.go Outdated
if ok {
xmlTagName := strings.Split(xmlTag, ",")[0] // remove omitempty, etc
// if xml tag name is "-", don't add it to the schema
if xmlTagName != "-" {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of nesting more if can just do

if xmlTagName == "-" {
	continue
}

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we use continue, all subsequent code (such as handling examples, validation, and descriptions) will be skipped if the field isn't included in XML.

In this section, only XML-related information is processed.

Copy link
Collaborator

@dylanhitt dylanhitt Dec 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we would then need to change the JSON check above to handle the same case. I.E when the xml tag is provided but not the json tag.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also I think it would make it a bit cleaner to perform both these actions in helpers so we can early return.

We also will need to handle the case where both the xml and json tags are - we wouldn't want the description, examples, or validation processed. Kinda like how we do already with the continue in the json check for -. Would probably be worth to check that early for both so we can continue early.

IngressDate string `json:"in_date" xml:"date,attr"`
}

type MyOutputStructWithXmlAttribute struct {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should add a test for a struct with just xml attributes. As well as one with json:"-"

openapi.go Outdated Show resolved Hide resolved
openapi.go Outdated
Comment on lines 468 to 492
// We support the following xml tags:
// - "xml" field tag: specifies the XML element name
// - "xml=attr" field tag: specifies that the field is an XML attribute
// - "xml=wrapped" field tag: specifies that the field is wrapped in an XML element
xmlField := field.Tag.Get("xml")
// if xml tag name is "-", don't add it to the schema
if xmlField != "-" && xmlField != "" {
xmlFieldName := strings.Split(xmlField, ",")[0] // remove omitempty, etc

if xmlFieldName == "" {
xmlFieldName = field.Name
}

propertyValue.XML = &openapi3.XML{
Name: xmlFieldName,
}

xmlFields := strings.Split(xmlField, ",")
if slices.Contains(xmlFields, "attr") {
propertyValue.XML.Attribute = true
}
if slices.Contains(xmlFields, "wrapped") {
propertyValue.XML.Wrapped = true
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would move this in a dedicated method, and also move the code related to json tag parsing to its own method too.

Because now the code is too complex.

Also it would allow you to return with early return when needed. It would avoid imbricated if levels

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm working on it

Copy link
Author

@DimShadoWWW DimShadoWWW Jan 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ccoVeille
Refactor OpenAPI Metadata Parsing and Introduce MetadataParsers

  • Added a new file, openapi_metadata.go (and test file), which includes:

    • MetadataParsers: A struct to define functions responsible for constructing the OpenAPI specification and the order in which they are executed.
    • Modular methods for constructing the OpenAPI specification, extracted from parseStructTags:
      • ExampleMetadataParser
      • ValidationMetadataParser
      • DescriptionMetadataParser
      • XMLMetadataParser
      • JSONMetadataParser
  • Modified openapi.go:

    • Removed the parseStructTags function.
    • Introduced initialization for MetadataParsers to manage the parsing logic in a structured and extensible way.

This ensures better control in cases where different methods may update the same value in the OpenAPI specification.

Co-authored-by: ccoVeille <3875889+ccoVeille@users.noreply.github.com>
Copy link
Collaborator

@ccoVeille ccoVeille left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing work you did from a simple comment I made (am I right?)

A few remarks

Also. here is a more general feedback, I would have put all these metadata parser things in a package in internal to do not export them (I'm unsure it's possible)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you need the openapi_ prefix for this file, everything is about openapi.

Also metadata is not clear enough for a file name I think (with or without the openapi_prefix)

Maybe metadata parser of something like that.

Naming is hard

Comment on lines +143 to +149
func (mp *MetadataParsers) insertAtStart(entry MetadataParserEntry) {
mp.registeredParsers = append([]MetadataParserEntry{entry}, mp.registeredParsers...)
}

func (mp *MetadataParsers) insertAtEnd(entry MetadataParserEntry) {
mp.registeredParsers = append(mp.registeredParsers, entry)
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Append and prepend are more commonly used than insert at start/end

if !validPositions[position] {
return fmt.Errorf("Invalid position. Use 'start', 'end', 'before', or 'after'")
}
if (position == "before" || position == "after") && mp.findParserIndex(relativeTo) == -1 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before, after, end, start should be constants prefixed with position or something

Comment on lines +16 to +20
{Name: "exampleParser", Parser: ExampleMetadataParser},
{Name: "validationParser", Parser: ValidationMetadataParser},
{Name: "descriptionParser", Parser: DescriptionMetadataParser},
{Name: "XMLParser", Parser: XMLMetadataParser},
{Name: "JSONParser", Parser: JSONMetadataParser},
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't these names be constants prefixed with metadataParser

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants