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

Components that are reference objects do not work #1506

Open
darrelmiller opened this issue Dec 19, 2023 · 2 comments
Open

Components that are reference objects do not work #1506

darrelmiller opened this issue Dec 19, 2023 · 2 comments
Assignees
Labels
type:bug A broken experience

Comments

@darrelmiller
Copy link
Member

darrelmiller commented Dec 19, 2023

Here is an example of a security object. Reading and writing this example fails to produce a valid OpenAPI.
image

openapi: 3.0
info:
  version: 2.0.0
  title: hello world
paths:
  /:
    get:
      responses:
        '200':
          description: OK

security:
  - ReferenceObject: []
components:
  securitySchemes:
    ReferenceObject:
      $ref: 'external.yaml#/components/securitySchemes/RealObject'    
    RealObject:
      type: http
      scheme: basic

A schema component that is reference object also fails for different reasons. In the output OpoenAPI, the transitive reference is lost and the inline reference points directly to the "realObject" instead of the "referenceObject".
image

openapi: 3.0
info:
  version: 2.0.0
  title: hello world
paths:
  /:
    get:
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReferenceObject'
components:
  schemas:
    ReferenceObject:
      $ref: '#/components/schemas/RealObject'
    RealObject:
      type: object
      properties:
        name: 
          type: string

Because of these bugs we need to revert PR #1491

@dldl-cmd
Copy link
Contributor

For the first issue, with the invalid written securityScheme this can be reproduced, by the following code, which indicates that it happens while writting the document.

var openApiDocument = new OpenApiDocument
{
    Components = new OpenApiComponents
    {
        SecuritySchemes = new Dictionary<string, OpenApiSecurityScheme>
        {
            ["ReferenceObject"] = new OpenApiSecurityScheme
            {
                Reference = new OpenApiReference
                {
                    Id = "RealObject",
                    Type = ReferenceType.Tag,
                    ExternalResource = "external.yaml"
                }
            },
            ["RealObject"] = new OpenApiSecurityScheme
            {
                Type = SecuritySchemeType.Http,
                Scheme = "scheme"
            }
        }
    }
};

var memoryStream = new MemoryStream();
var streamWriter = new FormattingStreamWriter(memoryStream, CultureInfo.InvariantCulture);
var writer = new OpenApiYamlWriter(streamWriter);

openApiDocument.SerializeAsV3(writer);

writer.Flush();

var writtenDocument = Encoding.UTF8.GetString(memoryStream.ToArray());

The issues is, that in the serialization of an OpenApiReference a SecurityScheme is always written as

<ReferenceV3>

instead of considering the context (e.g. being in the components section of the document) where the following is expected

$ref: <ReferenceV3>

The relevant code section is this one, where I could not find and easy way to detect the context in which the element is written.
https://github.com/microsoft/OpenAPI.NET/blob/6899d5f161bd0087ccea0a090cebbe4eaffdf99a/src/Microsoft.OpenApi/Models/OpenApiReference.cs#L180C1-L185C14

 public void SerializeAsV3(IOpenApiWriter writer)
 {
     Utils.CheckArgumentNull(writer);

     if (Type == ReferenceType.Tag)
     {
         // Write the string value only
         writer.WriteValue(ReferenceV3);
         return;
     }

     if (Type == ReferenceType.SecurityScheme)
     {
         // Write the string as property name
         writer.WritePropertyName(ReferenceV3);
         return;
     }

     writer.WriteStartObject();

     // $ref
     writer.WriteProperty(OpenApiConstants.DollarRef, ReferenceV3);

     writer.WriteEndObject();
 }

@dldl-cmd
Copy link
Contributor

dldl-cmd commented Jul 19, 2024

The second issue happens while reading the document:

var inputYaml = @"
openapi: 3.0
info:
  version: 2.0.0
  title: hello world
paths:
  /:
    get:
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReferenceObject'
components:
  schemas:
    ReferenceObject:
      $ref: '#/components/schemas/RealObject'
    RealObject:
      type: object
      properties:
        name:
          type: string
";

var reader = new OpenApiStringReader(); ;
var document = reader.Read(inputYaml, out OpenApiDiagnostic diagnostic);

var reference = document.Paths["/"].Operations[OperationType.Get].Responses["200"].Content["application/json"].Schema.Reference.ReferenceV3;
Console.WriteLine(reference);

The code above prints #/components/schemas/RealObject so the reference to ReferenceObject is lost while reading the document.

Turning of reference resolving does not create this issue. Without it the read and written document can be the same.

var reader = new OpenApiStringReader(new OpenApiReaderSettings
{
    ReferenceResolution = ReferenceResolutionSetting.DoNotResolveReferences
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type:bug A broken experience
Projects
None yet
Development

No branches or pull requests

3 participants