Skip to content

Conversation

PerthCharern
Copy link
Contributor

@PerthCharern PerthCharern commented Nov 15, 2017

  • Update Reference implementation to handle all tag, security scheme, and $ref-style pointers correctly.

  • Unit tests will follow tomorrow. Given that this set of changes is quite large, I have uploaded this PR in case you guys have some free time to look at it tomorrow while I'm still working on the unit tests. I'll follow up as soon as I'm done.

Fixes #81

@msftclas
Copy link

@PerthCharern,
Thanks for your contribution as a Microsoft full-time employee or intern. You do not need to sign a CLA.
Thanks,
Microsoft Pull Request Bot

@@ -35,7 +35,7 @@ internal override void WriteAsV3(IOpenApiWriter writer)

foreach (var scheme in Schemes)
{
writer.WritePropertyName(scheme.Key.Pointer.Name);
writer.WritePropertyName(scheme.Key.Pointer.Id);
Copy link
Contributor Author

@PerthCharern PerthCharern Nov 15, 2017

Choose a reason for hiding this comment

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

writer.WritePropertyName(scheme.Key.Pointer.Id); [](start = 16, length = 48)

will modify this to leverage WriteAsV3 in SecurityScheme #Resolved

@@ -73,7 +74,8 @@ public OpenApiDocument Read(Stream input, out OpenApiDiagnostic diagnostic)
return OpenApiV2Deserializer.LoadOpenApi(rootNode);

default:
context.SetReferenceService(new OpenApiV3ReferenceService(rootNode));
var referenceService = new OpenApiV3ReferenceService(rootNode);
context.SetReferenceService(referenceService);
Copy link
Contributor Author

@PerthCharern PerthCharern Nov 15, 2017

Choose a reason for hiding this comment

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

will revert #Resolved

Copy link
Contributor

Choose a reason for hiding this comment

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

+1


In reply to: 151025011 [](ancestors = 151025011)

}
}
}
}
Copy link
Contributor Author

@PerthCharern PerthCharern Nov 15, 2017

Choose a reason for hiding this comment

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

This is existing code. I took this out of RootNode to its own class. #Resolved

}



Copy link
Contributor Author

@PerthCharern PerthCharern Nov 15, 2017

Choose a reason for hiding this comment

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

This is moved to ConvertToOpenApiReferenceV2Tests #Resolved

@PerthCharern
Copy link
Contributor Author

PerthCharern commented Nov 15, 2017

This is moved to ConvertToOpenApiReferenceV3Tests #Resolved


Refers to: src/Microsoft.OpenApi.Readers/V3/OpenApiV3ReferenceService.cs:170 in e342c66. [](commit_id = e342c66, deletion_comment = True)

@xuzhg
Copy link
Contributor

xuzhg commented Nov 15, 2017

        writer.WriteOptionalCollection(OpenApiConstants.Tags, Tags, (w, t) => t.WriteAsV3(w));

@darrelmiller
@PerthCharern

This line code has problem, right?

It should write as a list of string, but now it writes as a list of Tag object if it's not a reference. That's bug what i mentioned. #Resolved


Refers to: src/Microsoft.OpenApi/Models/OpenApiOperation.cs:134 in 7644970. [](commit_id = 7644970, deletion_comment = False)

@xuzhg
Copy link
Contributor

xuzhg commented Nov 15, 2017

    OpenApiReference Pointer { get; set; }

Can we rename the "Pointer" as "Reference"? #Resolved


Refers to: src/Microsoft.OpenApi/Interfaces/IOpenApiReference.cs:18 in 7644970. [](commit_id = 7644970, deletion_comment = False)

@@ -109,14 +61,22 @@ public string ReferenceV3
return GetExternalReference();
}

if (ReferenceType == ReferenceType.Tag)
if (!Type.HasValue)
Copy link
Contributor

@xuzhg xuzhg Nov 15, 2017

Choose a reason for hiding this comment

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

if (!Type.HasValue) [](start = 16, length = 19)

Need to test "Type != null" otherwise

Type.HasValue will throw "NullReference..." exception. #WontFix

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Both are the same. The compiler translates null comparison for a nullable to a call to HasValue anyway.


In reply to: 151210609 [](ancestors = 151210609)

if (Type == ReferenceType.SecurityScheme)
{
return Id;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't know the "tag" & "SecurityScheme" reference.

@darrelmiller would you please help to verify?

Copy link
Member

Choose a reason for hiding this comment

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

Reviewing now....

return "#/" + GetReferenceTypeNameAsV2() + "/" + Name;
}
}
if (!Type.HasValue)
Copy link
Contributor

@xuzhg xuzhg Nov 15, 2017

Choose a reason for hiding this comment

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

if (!Type.HasValue) [](start = 16, length = 19)

Same here #WontFix

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Both != null and .HasValue are the same in the compiler's eyes.


In reply to: 151210974 [](ancestors = 151210974)

@PerthCharern
Copy link
Contributor Author

PerthCharern commented Nov 15, 2017

        writer.WriteOptionalCollection(OpenApiConstants.Tags, Tags, (w, t) => t.WriteAsV3(w));

This should work now. See OpenApiTag.WriteAsV3.

I am writing unit tests, so we will know for sure soon.


In reply to: 344681626 [](ancestors = 344681626)


Refers to: src/Microsoft.OpenApi/Models/OpenApiOperation.cs:134 in 7644970. [](commit_id = 7644970, deletion_comment = False)

@PerthCharern
Copy link
Contributor Author

        writer.WriteOptionalCollection(OpenApiConstants.Tags, Tags, (w, t) => t.WriteAsV3(w));

Actually I see what you meant now. I'll fix this.


In reply to: 344683545 [](ancestors = 344683545,344681626)


Refers to: src/Microsoft.OpenApi/Models/OpenApiOperation.cs:134 in 7644970. [](commit_id = 7644970, deletion_comment = False)

@PerthCharern
Copy link
Contributor Author

    OpenApiReference Pointer { get; set; }

Will do. I prefer that as well.


In reply to: 344681934 [](ancestors = 344681934)


Refers to: src/Microsoft.OpenApi/Interfaces/IOpenApiReference.cs:18 in 7644970. [](commit_id = 7644970, deletion_comment = False)

@xuzhg
Copy link
Contributor

xuzhg commented Nov 15, 2017

others look good to me

…rences, so we got the unit test working one way now.

- Always write tag as strings regardless of whether Pointer exists in the Operation.
@PerthCharern
Copy link
Contributor Author

PerthCharern commented Nov 15, 2017

Unit tests for Operation (OpenApiOperationTests) have been added. Given that Operation contains Tag and SecurityScheme, this verifies that writing references for those two special objects works.

I'm working on the Reader unit tests, and will push a new commit as soon as I can. #Resolved

/// <summary>
/// The base class for Open API Reference service.
/// </summary>
internal abstract class OpenApiReferenceServiceBase : IOpenApiReferenceService
Copy link
Member

@darrelmiller darrelmiller Nov 15, 2017

Choose a reason for hiding this comment

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

Do we really need a base class and an interface? There really isn't any behavior in this class. Would it not be simpler with just the interface? #Resolved

Copy link
Contributor Author

@PerthCharern PerthCharern Nov 15, 2017

Choose a reason for hiding this comment

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

I agree. There used to be some logic in this class but I have since removed them. I'll remove this. #Resolved

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes. Originally i removed the interface. Don't know why @PerthCharern re-added it. 😄


In reply to: 151233291 [](ancestors = 151233291)

Copy link
Member

@darrelmiller darrelmiller Nov 15, 2017

Choose a reason for hiding this comment

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

We need some kind of standard interface, it's the base class that is really redundant and potentially restrictive. In my experience interfaces should almost always be favoured over base classes. #Resolved

var tagListPointer = new JsonPointer("#/tags/");
var tagListNode = (ListNode)RootNode.Find(tagListPointer);

var tags = tagListNode.CreateList(OpenApiV2Deserializer.LoadTag);
Copy link
Member

@darrelmiller darrelmiller Nov 15, 2017

Choose a reason for hiding this comment

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

Are we deserializing the entire list of tags every time we de-reference a single tag? That seems less than optimal #Resolved

Copy link
Contributor Author

@PerthCharern PerthCharern Nov 15, 2017

Choose a reason for hiding this comment

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

You are right. Maybe we can cache this? #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is fixed now.


In reply to: 151233994 [](ancestors = 151233994)

- Add Unit Test for full document reading including schema/tag/securityScheme. One test is not working properly since we can't do dictionary comparison with securityScheme being the key right now, but I've verified that the output is what we expect.
…sure that each tag can be referenced without re-deserializing again and again.
@PerthCharern
Copy link
Contributor Author

@darrelmiller @xuzhg

Apologies for the large PR :(

I have addressed all you guys' comments above and added two unit tests in FullDocumentReaderTests. The document files contain references using 1) $ref style (Schema), 2) Tag style, and 3) SecurityScheme style, so this should get us some confidence that deserialization with references is now working.


@andystumpp

Adding you to this PR per our discussion yesterday.

@@ -110,7 +101,7 @@ public IOpenApiReference GetReferencedObject(OpenApiDiagnostic diagnostic, OpenA
/// <param name="referenceService"></param>
public void SetReferenceService(IOpenApiReferenceService referenceService)
{
this._referenceService = referenceService;
_referenceService = referenceService;
}
Copy link

@andystumpp andystumpp Nov 15, 2017

Choose a reason for hiding this comment

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

Is there a reason why we don't use a property with a setter here? #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think so. I'll fix this.


In reply to: 151287727 [](ancestors = 151287727)

@andystumpp
Copy link

andystumpp commented Nov 16, 2017

        var obj = new OpenApiSecurityRequirement();

Just seeing this, should we rename it to "securityRequirement"? #Resolved


Refers to: src/Microsoft.OpenApi.Readers/V3/OpenApiSecurityRequirementDeserializer.cs:22 in 72d612e. [](commit_id = 72d612e, deletion_comment = False)

}

/// <summary>
/// Get the referenced object.
/// Gets the referenced object
Copy link

@andystumpp andystumpp Nov 16, 2017

Choose a reason for hiding this comment

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

Nit: Period at the end #Resolved

@@ -69,13 +70,13 @@ public OpenApiDocument Read(Stream input, out OpenApiDiagnostic diagnostic)
switch (inputVersion)
{
case "2.0":
context.SetReferenceService(new OpenApiV2ReferenceService(rootNode));
context.ReferenceService = new OpenApiV2ReferenceService(rootNode);
Copy link

@andystumpp andystumpp Nov 16, 2017

Choose a reason for hiding this comment

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

context.ReferenceService [](start = 20, length = 24)

The flow here is interesting:
In order to set the reference service in the context, you need the rootnode, for that though you need the context to have (partially?) initialized... Is there some potential circular reference? #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right, this flow is strange. Fixing this won't be trivial, so I will open an issue. Given that this is specific to the reader (not the models), this should not block us from releasing the model as planned.


In reply to: 151336769 [](ancestors = 151336769)

else
{
writer.WriteStartObject();
writer.WriteStartObject();
Copy link

@andystumpp andystumpp Nov 16, 2017

Choose a reason for hiding this comment

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

remove empty line #Resolved

@PerthCharern
Copy link
Contributor Author

@darrelmiller @xuzhg

Friendly ping on this. Given the breadth of the code this PR covers, I would like to check this in as soon as possible to prevent merge conflicts with future changes.

@PerthCharern PerthCharern merged commit 3e1077a into master Nov 16, 2017
@PerthCharern PerthCharern deleted the PerthCharern/FixBugForReference branch November 18, 2017 00:49
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.

5 participants