Skip to content

Commit 6bb2546

Browse files
committed
Add serialization logic
1 parent 7761651 commit 6bb2546

File tree

1 file changed

+379
-1
lines changed

1 file changed

+379
-1
lines changed

src/Microsoft.OpenApi/Models/OpenApiSchema.cs

Lines changed: 379 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) Microsoft Corporation. All rights reserved.
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT license.
33

44
using System;
@@ -377,5 +377,383 @@ public OpenApiSchema(OpenApiSchema schema)
377377
UnresolvedReference = schema?.UnresolvedReference ?? UnresolvedReference;
378378
Reference = schema?.Reference != null ? new(schema?.Reference) : null;
379379
}
380+
381+
/// <summary>
382+
/// Serialize <see cref="OpenApiParameter"/> to Open Api v3.1
383+
/// </summary>
384+
public virtual void SerializeAsV31(IOpenApiWriter writer)
385+
{
386+
SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer),
387+
(writer, element) => element.SerializeAsV31WithoutReference(writer));
388+
}
389+
390+
/// <summary>
391+
/// Serialize <see cref="OpenApiParameter"/> to Open Api v3.0
392+
/// </summary>
393+
public virtual void SerializeAsV3(IOpenApiWriter writer)
394+
{
395+
SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer),
396+
(writer, element) => element.SerializeAsV3WithoutReference(writer));
397+
}
398+
399+
private void SerializeInternal(IOpenApiWriter writer, Action<IOpenApiWriter, IOpenApiSerializable> callback,
400+
Action<IOpenApiWriter, IOpenApiReferenceable> action)
401+
{
402+
Utils.CheckArgumentNull(writer);
403+
var target = this;
404+
action(writer, target);
405+
}
406+
407+
/// <summary>
408+
/// Serialize to OpenAPI V3 document without using reference.
409+
/// </summary>
410+
public virtual void SerializeAsV31WithoutReference(IOpenApiWriter writer)
411+
{
412+
SerializeInternalWithoutReference(writer, OpenApiSpecVersion.OpenApi3_1,
413+
(writer, element) => element.SerializeAsV31(writer));
414+
}
415+
416+
/// <summary>
417+
/// Serialize to OpenAPI V3 document without using reference.
418+
/// </summary>
419+
public virtual void SerializeAsV3WithoutReference(IOpenApiWriter writer)
420+
{
421+
SerializeInternalWithoutReference(writer, OpenApiSpecVersion.OpenApi3_0,
422+
(writer, element) => element.SerializeAsV3(writer));
423+
}
424+
425+
/// <inheritdoc/>
426+
427+
public void SerializeInternalWithoutReference(IOpenApiWriter writer, OpenApiSpecVersion version,
428+
Action<IOpenApiWriter, IOpenApiSerializable> callback)
429+
{
430+
writer.WriteStartObject();
431+
432+
if (version == OpenApiSpecVersion.OpenApi3_1)
433+
{
434+
WriteV31Properties(writer);
435+
}
436+
437+
// title
438+
writer.WriteProperty(OpenApiConstants.Title, Title);
439+
440+
// multipleOf
441+
writer.WriteProperty(OpenApiConstants.MultipleOf, MultipleOf);
442+
443+
// maximum
444+
writer.WriteProperty(OpenApiConstants.Maximum, Maximum);
445+
446+
// exclusiveMaximum
447+
writer.WriteProperty(OpenApiConstants.ExclusiveMaximum, ExclusiveMaximum);
448+
449+
// minimum
450+
writer.WriteProperty(OpenApiConstants.Minimum, Minimum);
451+
452+
// exclusiveMinimum
453+
writer.WriteProperty(OpenApiConstants.ExclusiveMinimum, ExclusiveMinimum);
454+
455+
// maxLength
456+
writer.WriteProperty(OpenApiConstants.MaxLength, MaxLength);
457+
458+
// minLength
459+
writer.WriteProperty(OpenApiConstants.MinLength, MinLength);
460+
461+
// pattern
462+
writer.WriteProperty(OpenApiConstants.Pattern, Pattern);
463+
464+
// maxItems
465+
writer.WriteProperty(OpenApiConstants.MaxItems, MaxItems);
466+
467+
// minItems
468+
writer.WriteProperty(OpenApiConstants.MinItems, MinItems);
469+
470+
// uniqueItems
471+
writer.WriteProperty(OpenApiConstants.UniqueItems, UniqueItems);
472+
473+
// maxProperties
474+
writer.WriteProperty(OpenApiConstants.MaxProperties, MaxProperties);
475+
476+
// minProperties
477+
writer.WriteProperty(OpenApiConstants.MinProperties, MinProperties);
478+
479+
// required
480+
writer.WriteOptionalCollection(OpenApiConstants.Required, Required, (w, s) => w.WriteValue(s));
481+
482+
// enum
483+
writer.WriteOptionalCollection(OpenApiConstants.Enum, Enum, (nodeWriter, s) => nodeWriter.WriteAny(new OpenApiAny(s)));
484+
485+
// type
486+
writer.WriteProperty(OpenApiConstants.Type, Type);
487+
488+
// allOf
489+
writer.WriteOptionalCollection(OpenApiConstants.AllOf, AllOf, (w, s) => s.SerializeAsV3(w));
490+
491+
// anyOf
492+
writer.WriteOptionalCollection(OpenApiConstants.AnyOf, AnyOf, (w, s) => s.SerializeAsV3(w));
493+
494+
// oneOf
495+
writer.WriteOptionalCollection(OpenApiConstants.OneOf, OneOf, (w, s) => s.SerializeAsV3(w));
496+
497+
// not
498+
writer.WriteOptionalObject(OpenApiConstants.Not, Not, (w, s) => s.SerializeAsV3(w));
499+
500+
// items
501+
writer.WriteOptionalObject(OpenApiConstants.Items, Items, (w, s) => s.SerializeAsV3(w));
502+
503+
// properties
504+
writer.WriteOptionalMap(OpenApiConstants.Properties, Properties, (w, s) => s.SerializeAsV3(w));
505+
506+
// additionalProperties
507+
if (AdditionalPropertiesAllowed)
508+
{
509+
writer.WriteOptionalObject(
510+
OpenApiConstants.AdditionalProperties,
511+
AdditionalProperties,
512+
(w, s) => s.SerializeAsV3(w));
513+
}
514+
else
515+
{
516+
writer.WriteProperty(OpenApiConstants.AdditionalProperties, AdditionalPropertiesAllowed);
517+
}
518+
519+
// description
520+
writer.WriteProperty(OpenApiConstants.Description, Description);
521+
522+
// format
523+
writer.WriteProperty(OpenApiConstants.Format, Format);
524+
525+
// default
526+
writer.WriteOptionalObject(OpenApiConstants.Default, Default, (w, d) => w.WriteAny(d));
527+
528+
// nullable
529+
writer.WriteProperty(OpenApiConstants.Nullable, Nullable, false);
530+
531+
// discriminator
532+
writer.WriteOptionalObject(OpenApiConstants.Discriminator, Discriminator, (w, s) => s.SerializeAsV3(w));
533+
534+
// readOnly
535+
writer.WriteProperty(OpenApiConstants.ReadOnly, ReadOnly, false);
536+
537+
// writeOnly
538+
writer.WriteProperty(OpenApiConstants.WriteOnly, WriteOnly, false);
539+
540+
// xml
541+
writer.WriteOptionalObject(OpenApiConstants.Xml, Xml, (w, s) => s.SerializeAsV2(w));
542+
543+
// externalDocs
544+
writer.WriteOptionalObject(OpenApiConstants.ExternalDocs, ExternalDocs, (w, s) => s.SerializeAsV3(w));
545+
546+
// example
547+
writer.WriteOptionalObject(OpenApiConstants.Example, Example, (w, e) => w.WriteAny(e));
548+
549+
// deprecated
550+
writer.WriteProperty(OpenApiConstants.Deprecated, Deprecated, false);
551+
552+
// extensions
553+
writer.WriteExtensions(Extensions, OpenApiSpecVersion.OpenApi3_0);
554+
555+
writer.WriteEndObject();
556+
}
557+
558+
/// <inheritdoc/>
559+
560+
public void SerializeAsV2WithoutReference(IOpenApiWriter writer)
561+
{
562+
SerializeAsV2WithoutReference(
563+
writer: writer,
564+
parentRequiredProperties: new HashSet<string>(),
565+
propertyName: null);
566+
}
567+
568+
/// <inheritdoc/>
569+
570+
public void SerializeAsV2(IOpenApiWriter writer)
571+
{
572+
SerializeAsV2(writer: writer, parentRequiredProperties: new HashSet<string>(), propertyName: null);
573+
}
574+
575+
internal void WriteV31Properties(IOpenApiWriter writer)
576+
{
577+
writer.WriteProperty(OpenApiConstants.DollarSchema, Schema);
578+
writer.WriteProperty(OpenApiConstants.Id, Id);
579+
writer.WriteProperty(OpenApiConstants.Comment, Comment);
580+
writer.WriteProperty(OpenApiConstants.Vocabulary, Vocabulary);
581+
writer.WriteOptionalMap(OpenApiConstants.Defs, Definitions, (w, s) => s.SerializeAsV3(w));
582+
writer.WriteProperty(OpenApiConstants.DynamicRef, DynamicRef);
583+
writer.WriteProperty(OpenApiConstants.DynamicAnchor, DynamicAnchor);
584+
writer.WriteProperty(OpenApiConstants.RecursiveAnchor, RecursiveAnchor);
585+
writer.WriteProperty(OpenApiConstants.RecursiveRef, RecursiveRef);
586+
writer.WriteProperty(OpenApiConstants.V31ExclusiveMaximum, V31ExclusiveMaximum);
587+
writer.WriteProperty(OpenApiConstants.V31ExclusiveMinimum, V31ExclusiveMinimum);
588+
writer.WriteProperty(OpenApiConstants.UnevaluatedProperties, UnevaluatedProperties);
589+
}
590+
591+
/// <summary>
592+
/// Serialize <see cref="OpenApiSchema"/> to Open Api v2.0 and handles not marking the provided property
593+
/// as readonly if its included in the provided list of required properties of parent schema.
594+
/// </summary>
595+
/// <param name="writer">The open api writer.</param>
596+
/// <param name="parentRequiredProperties">The list of required properties in parent schema.</param>
597+
/// <param name="propertyName">The property name that will be serialized.</param>
598+
internal void SerializeAsV2(
599+
IOpenApiWriter writer,
600+
ISet<string> parentRequiredProperties,
601+
string propertyName)
602+
{
603+
var target = this;
604+
parentRequiredProperties ??= new HashSet<string>();
605+
606+
target.SerializeAsV2WithoutReference(writer, parentRequiredProperties, propertyName);
607+
}
608+
609+
/// <summary>
610+
/// Serialize to OpenAPI V2 document without using reference and handles not marking the provided property
611+
/// as readonly if its included in the provided list of required properties of parent schema.
612+
/// </summary>
613+
/// <param name="writer">The open api writer.</param>
614+
/// <param name="parentRequiredProperties">The list of required properties in parent schema.</param>
615+
/// <param name="propertyName">The property name that will be serialized.</param>
616+
internal void SerializeAsV2WithoutReference(
617+
IOpenApiWriter writer,
618+
ISet<string> parentRequiredProperties,
619+
string propertyName)
620+
{
621+
writer.WriteStartObject();
622+
WriteAsSchemaProperties(writer, parentRequiredProperties, propertyName);
623+
writer.WriteEndObject();
624+
}
625+
626+
internal void WriteAsSchemaProperties(
627+
IOpenApiWriter writer,
628+
ISet<string> parentRequiredProperties,
629+
string propertyName)
630+
{
631+
// format
632+
if (string.IsNullOrEmpty(Format))
633+
{
634+
Format = AllOf?.FirstOrDefault(static x => !string.IsNullOrEmpty(x.Format))?.Format ??
635+
AnyOf?.FirstOrDefault(static x => !string.IsNullOrEmpty(x.Format))?.Format ??
636+
OneOf?.FirstOrDefault(static x => !string.IsNullOrEmpty(x.Format))?.Format;
637+
}
638+
639+
writer.WriteProperty(OpenApiConstants.Format, Format);
640+
641+
// title
642+
writer.WriteProperty(OpenApiConstants.Title, Title);
643+
644+
// description
645+
writer.WriteProperty(OpenApiConstants.Description, Description);
646+
647+
// default
648+
writer.WriteOptionalObject(OpenApiConstants.Default, Default, (w, d) => w.WriteAny(d));
649+
650+
// multipleOf
651+
writer.WriteProperty(OpenApiConstants.MultipleOf, MultipleOf);
652+
653+
// maximum
654+
writer.WriteProperty(OpenApiConstants.Maximum, Maximum);
655+
656+
// exclusiveMaximum
657+
writer.WriteProperty(OpenApiConstants.ExclusiveMaximum, ExclusiveMaximum);
658+
659+
// minimum
660+
writer.WriteProperty(OpenApiConstants.Minimum, Minimum);
661+
662+
// exclusiveMinimum
663+
writer.WriteProperty(OpenApiConstants.ExclusiveMinimum, ExclusiveMinimum);
664+
665+
// maxLength
666+
writer.WriteProperty(OpenApiConstants.MaxLength, MaxLength);
667+
668+
// minLength
669+
writer.WriteProperty(OpenApiConstants.MinLength, MinLength);
670+
671+
// pattern
672+
writer.WriteProperty(OpenApiConstants.Pattern, Pattern);
673+
674+
// maxItems
675+
writer.WriteProperty(OpenApiConstants.MaxItems, MaxItems);
676+
677+
// minItems
678+
writer.WriteProperty(OpenApiConstants.MinItems, MinItems);
679+
680+
// uniqueItems
681+
writer.WriteProperty(OpenApiConstants.UniqueItems, UniqueItems);
682+
683+
// maxProperties
684+
writer.WriteProperty(OpenApiConstants.MaxProperties, MaxProperties);
685+
686+
// minProperties
687+
writer.WriteProperty(OpenApiConstants.MinProperties, MinProperties);
688+
689+
// required
690+
writer.WriteOptionalCollection(OpenApiConstants.Required, Required, (w, s) => w.WriteValue(s));
691+
692+
// enum
693+
writer.WriteOptionalCollection(OpenApiConstants.Enum, Enum, (w, s) => w.WriteAny(new OpenApiAny(s)));
694+
695+
// type
696+
writer.WriteProperty(OpenApiConstants.Type, Type);
697+
698+
// items
699+
writer.WriteOptionalObject(OpenApiConstants.Items, Items, (w, s) => s.SerializeAsV2(w));
700+
701+
// allOf
702+
writer.WriteOptionalCollection(OpenApiConstants.AllOf, AllOf, (w, s) => s.SerializeAsV2(w));
703+
704+
// If there isn't already an allOf, and the schema contains a oneOf or anyOf write an allOf with the first
705+
// schema in the list as an attempt to guess at a graceful downgrade situation.
706+
if (AllOf == null || AllOf.Count == 0)
707+
{
708+
// anyOf (Not Supported in V2) - Write the first schema only as an allOf.
709+
writer.WriteOptionalCollection(OpenApiConstants.AllOf, AnyOf?.Take(1), (w, s) => s.SerializeAsV2(w));
710+
711+
if (AnyOf == null || AnyOf.Count == 0)
712+
{
713+
// oneOf (Not Supported in V2) - Write the first schema only as an allOf.
714+
writer.WriteOptionalCollection(OpenApiConstants.AllOf, OneOf?.Take(1), (w, s) => s.SerializeAsV2(w));
715+
}
716+
}
717+
718+
// properties
719+
writer.WriteOptionalMap(OpenApiConstants.Properties, Properties, (w, key, s) =>
720+
s.SerializeAsV2(w, Required, key));
721+
722+
// additionalProperties
723+
if (AdditionalPropertiesAllowed)
724+
{
725+
writer.WriteOptionalObject(
726+
OpenApiConstants.AdditionalProperties,
727+
AdditionalProperties,
728+
(w, s) => s.SerializeAsV2(w));
729+
}
730+
else
731+
{
732+
writer.WriteProperty(OpenApiConstants.AdditionalProperties, AdditionalPropertiesAllowed);
733+
}
734+
735+
// discriminator
736+
writer.WriteProperty(OpenApiConstants.Discriminator, Discriminator?.PropertyName);
737+
738+
// readOnly
739+
// In V2 schema if a property is part of required properties of parent schema,
740+
// it cannot be marked as readonly.
741+
if (!parentRequiredProperties.Contains(propertyName))
742+
{
743+
writer.WriteProperty(name: OpenApiConstants.ReadOnly, value: ReadOnly, defaultValue: false);
744+
}
745+
746+
// xml
747+
writer.WriteOptionalObject(OpenApiConstants.Xml, Xml, (w, s) => s.SerializeAsV2(w));
748+
749+
// externalDocs
750+
writer.WriteOptionalObject(OpenApiConstants.ExternalDocs, ExternalDocs, (w, s) => s.SerializeAsV2(w));
751+
752+
// example
753+
writer.WriteOptionalObject(OpenApiConstants.Example, Example, (w, e) => w.WriteAny(e));
754+
755+
// extensions
756+
writer.WriteExtensions(Extensions, OpenApiSpecVersion.OpenApi2_0);
757+
}
380758
}
381759
}

0 commit comments

Comments
 (0)