Browse Source

* OpenAPI, initial commit

Michaël Van Canneyt 9 months ago
parent
commit
3f4298dbca

+ 7 - 0
packages/fcl-json/fpmake.pp

@@ -43,6 +43,13 @@ begin
       AddUnit('fpjson');
       AddUnit('jsonparser');
      end;
+
+    T:=P.Targets.AddUnit('jsoncomparer.pp');
+    T.ResourceStrings:=true;
+    with T.Dependencies do
+      begin
+      AddUnit('fpjson');
+     end;
     T:=P.Targets.AddUnit('jsonfpcunit.pp');
     T.ResourceStrings:=true;
     with T.Dependencies do

+ 3 - 0
packages/fcl-json/namespaced/FpJson.Comparer.pp

@@ -0,0 +1,3 @@
+unit FpJson.Comparer;
+{$DEFINE FPC_DOTTEDUNITS}
+{$i jsoncomparer.pp}

+ 1 - 0
packages/fcl-json/namespaces.lst

@@ -13,3 +13,4 @@ src/jsonreader.pp=namespaced/FpJson.Reader.pp
 src/jsonwriter.pp=namespaced/FpJson.Writer.pp
 src/jsonconf.pp=namespaced/FpJson.Conf.pp
 src/jsonfpcunit.pp=namespaced/FpJson.FpcUnit.pp
+src/jsoncomparer.pp=namespaced/FpJson.Comparer.pp

+ 208 - 0
packages/fcl-json/src/jsoncomparer.pp

@@ -0,0 +1,208 @@
+{
+    This file is part of the Free Component Library
+
+    Implementation of a TJSONComparer class
+    Copyright (c) 2024 Michael Van Canneyt [email protected]
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+{$IFNDEF FPC_DOTTEDUNITS}
+unit jsoncomparer;
+{$ENDIF}
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses
+{$IFDEF FPC_DOTTEDUNITS}
+  System.Classes, System.SysUtils, FpJson.Data;
+{$ELSE}
+  Classes, SysUtils, fpjson;
+{$ENDIF}
+
+type
+
+  { TJSONComparer }
+
+  TJSONComparer = Class(TObject)
+  private
+    FEpsilon: Double;
+    FErrors : TStrings;
+    procedure addDiff(const aPath, aDiff: String);
+    procedure addDiff(const aPath: String; const aFmt: String; const aArgs: array of const);
+  Protected
+    Procedure CompareArray(const aPath : String; aExpected,aActual : TJSONArray);
+    Procedure CompareObject(const aPath : String; aExpected,aActual : TJSONObject);
+    Procedure doCompare(const aPath : String; aExpected,aActual : TJSONData);
+  Public
+    constructor create(aErrors : TStrings);
+    Procedure Compare(aExpected,aActual : TJSONData);
+    class Procedure Compare(aExpected,aActual : TJSONData; aErrors : TStrings);
+    property Epsilon : Double Read FEpsilon Write FEpsilon;
+  end;
+
+implementation
+
+resourcestring
+  SExpectedArrayElements =  'Expected %d array elements, got %d';
+  SExpectedObjectKeys = 'Expected %d object keys, got %d';
+  SElementExpected = 'Element expected, but not present.';
+  SElementUnexpected = 'Element present, but not expected.';
+  SElementTypesDiffer = 'Element types differ, expected %s, got: %s';
+  SElementValueDiffers = 'Expected %s, got: %s';
+  SElementIntegerValueDiffers = 'expected %d, got: %d';
+  
+{ TJSONComparer }
+
+procedure TJSONComparer.addDiff(const aPath,aDiff : String);
+
+begin
+  FErrors.Add(aPath+': '+aDiff);
+end;
+
+procedure TJSONComparer.addDiff(const aPath : String; const aFmt: String; const aArgs: array of const);
+begin
+  AddDiff(aPath,Format(aFmt,aArgs));
+end;
+
+procedure TJSONComparer.CompareArray(const aPath: String; aExpected, aActual: TJSONArray);
+var
+  i,lCount : integer;
+begin
+  lCount:=aExpected.Count;
+  if lCount<>aActual.Count then
+    AddDiff(aPath,SExpectedArrayElements,[aExpected.Count,aActual.Count]);
+  if (aActual.Count<lCount) then
+    lCount:=aActual.Count;
+  for I:=0 to lCount-1 do
+    DoCompare(Format('%s[%d]',[aPath,I]),aExpected[i],aActual[i]);
+end;
+
+procedure TJSONComparer.CompareObject(const aPath: String; aExpected, aActual: TJSONObject);
+var
+  i,lCount : integer;
+  Names : TStringList;
+  lExpect,lActual : TJSONData;
+  lName : String;
+
+begin
+  lCount:=aExpected.Count;
+  if lCount<>aActual.Count then
+    AddDiff(aPath,SExpectedObjectKeys,[aExpected.Count,aActual.Count]);
+  Names:=TStringList.Create;
+  try
+    for I:=0 to aExpected.Count-1 do
+      Names.Add(aExpected.Names[i]);
+    Names.CaseSensitive:=True;
+    Names.Sorted:=true;
+    For I:=0 to Names.Count-1 do
+      begin
+      lName:=Names[i];
+      lExpect:=aExpected.Elements[lName];
+      lActual:=aActual.Find(lName);
+      DoCompare(Format('%s.%s',[aPath,lName]),lExpect,lActual);
+      end;
+    For I:=0 to aActual.Count-1 do
+      begin
+      lName:=aActual.Names[i];
+      if Names.IndexOf(lName)=-1 then
+        DoCompare(Format('%s.%s',[aPath,lName]),Nil,aActual.Items[i]);
+      end;
+  finally
+    Names.Free;
+  end;
+end;
+
+procedure TJSONComparer.doCompare(const aPath: String; aExpected, aActual: TJSONData);
+begin
+  if (aActual=Nil) and (aExpected=Nil) then
+    exit;
+  if (aActual=Nil) then
+    begin
+    AddDiff(aPath,SElementExpected);
+    Exit;
+    end
+  else if (aExpected=Nil) then
+    begin
+    AddDiff(aPath,SElementUnexpected);
+    Exit;
+    end;
+  if aActual.JSONType<>aExpected.JSONType then
+    begin
+    AddDiff(aPath,SElementTypesDiffer,[JSONTypeName(aExpected.JSONType),JSONTypeName(aActual.JSONType)]);
+    exit;
+    end;
+  case aActual.JSONType of
+    jtNull: ;
+    jtBoolean :
+      if aActual.AsBoolean<>aExpected.AsBoolean then
+        AddDiff(aPath,SElementValueDiffers ,[aExpected.AsJSON,aActual.AsJSON]);
+    jtNumber :
+      begin
+      if TJSONNumber(aExpected).NumberType=TJSONNumber(aActual).NumberType then
+        begin
+        case TJSONNumber(aExpected).NumberType of
+          ntInteger :
+            if (aExpected.AsInteger<>aActual.AsInteger) then
+              AddDiff(aPath,SElementIntegerValueDiffers,[aExpected.AsInteger<>aActual.AsInteger]);
+          ntInt64:
+            if (aExpected.AsInt64<>aActual.AsInt64) then
+              AddDiff(aPath,SElementIntegerValueDiffers,[aExpected.AsInteger<>aActual.AsInteger]);
+          ntQWord:
+            if (aExpected.AsQWord<>aActual.AsQWord) then
+              AddDiff(aPath,SElementIntegerValueDiffers,[aExpected.AsInteger<>aActual.AsInteger]);
+          ntFloat:
+          if Abs(aExpected.AsFloat-aActual.AsFloat)>Epsilon then
+            AddDiff(aPath,SElementValueDiffers,[aExpected.AsJSON,aActual.AsJSON]);
+        end
+        end
+      else
+        if Abs(aExpected.AsFloat-aActual.AsFloat)>Epsilon then
+          AddDiff(aPath,SElementValueDiffers,[aExpected.AsJSON,aActual.AsJSON]);
+      end;
+    jtString :
+      begin
+      if aExpected.AsString<>aActual.AsString then
+        AddDiff(aPath,SElementValueDiffers,[aExpected.AsString,aActual.AsString])
+      end;
+    jtArray:
+      CompareArray(aPath,TJSONArray(aExpected),TJSONArray(aActual));
+    jtObject:
+      CompareObject(aPath,TJSONObject(aExpected),TJSONObject(aActual));
+  end;
+end;
+
+constructor TJSONComparer.create(aErrors: TStrings);
+
+begin
+  FErrors:=aErrors;
+  FEpsilon:=1E-8;
+end;
+
+procedure TJSONComparer.Compare(aExpected, aActual: TJSONData);
+begin
+  DoCompare('#',aExpected,aActual);
+end;
+
+class procedure TJSONComparer.Compare(aExpected, aActual: TJSONData; aErrors: TStrings);
+
+var
+  cmp: TJSONComparer;
+begin
+  cmp:=TJSONComparer.Create(aErrors);
+  try
+    cmp.Compare(aExpected,aActual);
+  finally
+    cmp.Free;
+  end;
+end;
+
+end.
+

+ 93 - 0
packages/fcl-openapi/fpmake.pp

@@ -0,0 +1,93 @@
+{$ifndef ALLPACKAGES}
+{$mode objfpc}{$H+}
+program fpmake;
+
+uses {$ifdef unix}cthreads,{$endif} fpmkunit;
+
+Var
+  T : TTarget;
+  P : TPackage;
+begin
+  With Installer do
+    begin
+{$endif ALLPACKAGES}
+
+    P:=AddPackage('fcl-openapi');
+    P.ShortName:='openapi';
+{$ifdef ALLPACKAGES}
+    P.Directory:=ADirectory;
+{$endif ALLPACKAGES}
+    P.Version:='3.3.1';
+    P.Dependencies.Add('fcl-base');
+    P.Dependencies.Add('rtl-objpas');
+    P.Dependencies.Add('fcl-fpcunit');
+    P.Dependencies.Add('fcl-json');
+    P.Dependencies.Add('fcl-jsonschema');
+    P.Dependencies.Add('regexpr');
+    P.Author := 'Michael van Canneyt';
+    P.License := 'LGPL with modification, ';
+    P.HomepageURL := 'www.freepascal.org';
+    P.Email := '';
+    P.Description := 'OpenAPI (swagger) spec reader & code generator.';
+    P.NeedLibC:= false;
+    P.OSes:=AllOSes-[embedded,msdos,win16,macosclassic,palmos,zxspectrum,msxdos,amstradcpc,sinclairql,human68k,ps1];
+    if Defaults.CPU=jvm then
+      P.OSes := P.OSes - [java,android];
+
+    P.SourcePath.Add('src');
+
+    T:=P.Targets.AddUnit('fpopenapi.consts.pp');
+//    T.ResourceStrings:=true;
+    
+    T:=P.Targets.AddUnit('fpopenapi.types.pp');
+    with T.Dependencies do
+      AddUnit('fpopenapi.consts');
+
+    T:=P.Targets.AddUnit('fpopenapi.objects.pp');
+    with T.Dependencies do
+      begin
+      AddUnit('fpopenapi.consts');
+      AddUnit('fpopenapi.types');
+      end;
+
+    T:=P.Targets.AddUnit('fpopenapi.reader.pp');
+    with T.Dependencies do
+      begin
+      AddUnit('fpopenapi.consts');
+      AddUnit('fpopenapi.types');
+      AddUnit('fpopenapi.objects');
+      end;
+    T:=P.Targets.AddUnit('fpopenapi.writer.pp');
+    with T.Dependencies do
+      begin
+      AddUnit('fpopenapi.consts');
+      AddUnit('fpopenapi.types');
+      AddUnit('fpopenapi.objects');
+      end;
+
+   T:=P.Targets.AddUnit('fpopenapi.pascaltypes.pp');
+   with T.Dependencies do
+     begin
+     AddUnit('fpopenapi.types');
+     AddUnit('fpopenapi.objects');
+     end;
+
+(*
+   T:=P.Targets.AddUnit('fpopenapi.codegen.pp');
+   with T.Dependencies do
+     begin
+     AddUnit('fpopenapi.pascaltypes');
+     AddUnit('fpopenapi.types');
+     AddUnit('fpopenapi.objects');
+     end;
+
+*) 
+      
+{$ifndef ALLPACKAGES}
+    Run;
+    end;
+end.
+{$endif ALLPACKAGES}
+
+
+

+ 229 - 0
packages/fcl-openapi/src/fpopenapi.consts.pp

@@ -0,0 +1,229 @@
+{
+    This file is part of the Free Component Library (FCL)
+    Copyright (c) 2024 by Michael Van Canneyt ([email protected])
+
+    Basic OpenAPI constants
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+
+unit fpopenapi.consts;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+Const
+  SOpenAPiVersion3_1_0 = '3.1.0';
+
+  KWExtensionPrefix = 'x-';
+
+  KWOpenAPIOpenApi = 'openapi';
+  KWOpenAPIInfo = 'info';
+  KWOpenAPIJSONSchemaDialect = 'jsonSchemaDialect';
+  KWOpenAPIServers= 'servers';
+  KWOpenAPIPaths = 'paths';
+  KWOpenAPIWebHooks = 'webhooks';
+  KWOpenAPIComponents = 'components';
+  KWOpenAPISecurity = 'security';
+  KWOpenAPITags = 'tags';
+  KWOpenAPIExternalDocs = 'externalDocs';
+
+  // Info
+  KWInfoTitle = 'title';
+  KWInfoSummary = 'summary';
+  KWInfoDescription = 'description';
+  KWInfoTermsOfService = 'termsOfService';
+  KWInfoContact = 'contact';
+  KWInfoLicense = 'license';
+  KWInfoVersion = 'version';
+
+  // Contact object
+  KWContactName = 'name';
+  KWContactUrl = 'url';
+  KWContactEmail = 'email';
+
+  // Licence Object
+  KWLicenseName = 'name';
+  KWLicenseIdentifier = 'identifier';
+  KWLicenseUrl = 'url';
+
+  // Server object
+  KWServerUrl = 'url';
+  KWServerDescription = 'description';
+  KWServerVariables = 'variables';
+
+  // Server Variable object
+  KWServerVariableEnum = 'enum';
+  KWServerVariableDefault = 'default';
+  KWServerVariableDescription = 'description';
+
+  // Components object
+  KWComponentsSchemas = 'schemas';
+  KWComponentsResponses = 'responses';
+  KWComponentsParameters = 'parameters';
+  KWComponentsExamples = 'examples';
+  KWComponentsRequestBodies = 'requestBodies';
+  KWComponentsHeaders = 'headers';
+  KWComponentsSecuritySchemes = 'securitySchemes';
+  KWComponentsLinks = 'securitySchemes';
+  KWComponentsCallbacks = 'callbacks';
+  KWComponentsPathItems = 'pathItems';
+
+  // Path item object
+  KWPathItemRef = '$ref';
+  KWPathItemSummary = 'summary';
+  KWPathItemDescription = 'description';
+  KWPathItemGet = 'get';
+  KWPathItemPut = 'put';
+  KWPathItemPost = 'post';
+  KWPathItemDelete = 'delete';
+  KWPathItemOptions = 'options';
+  KWPathItemHead = 'head';
+  KWPathItemPatch = 'patch';
+  KWPathItemTrace = 'trace';
+  KWPathItemServers = 'servers';
+  KWPathItemParameters = 'parameters';
+
+  // Operation object
+  KWOperationTags = 'tags';
+  KWOperationSummary = 'summary';
+  KWOperationDescription = 'description';
+  KWOperationExternalDocs = 'externalDocs';
+  KWOperationOperationId = 'operationId';
+  KWOperationParameters = 'parameters';
+  KWOperationRequestBody = 'requestBody';
+  KWOperationResponses = 'responses';
+  KWOperationCallbacks = 'callbacks';
+  KWOperationDeprecated = 'deprecated';
+  KWOperationSecurity = 'security';
+  KWOperationServers = 'servers';
+
+  // External documentaton object
+  KWExternalDocsDescription = 'description';
+  KWExternalDocsUrl = 'url';
+
+  // Parameter object
+  KWParameterName = 'name';
+  KWParameterIn = 'in';
+  KWParameterDescription = 'description';
+  KWParameterRequired = 'required';
+  KWParameterDeprecated = 'deprecated';
+  KWParameterAllowEmptyValue = 'allowEmptyValue';
+  KWParameterStyle = 'style';
+  KWParameterExplode = 'explode';
+  KWParameterAllowReserved = 'allowReserved';
+  KWParameterSchema = 'schema';
+  KWParameterExample = 'example';
+  KWParameterExamples = 'examples';
+  KWParameterContent = 'content';
+
+  // ParameterStyle
+  KWParameterStyleMatrix = 'matrix';
+  KWParameterStyleLabel = 'matrix';
+  KWParameterStyleForm = 'form';
+  KWParameterStyleSimple = 'simple';
+  KWParameterStyleSpaceDelimited = 'spaceDelimited';
+  KWParameterStylePipeDelimited = 'pipeDelimited';
+  KWParameterStyleDeepObject = 'deepObject';
+
+  // Request body object
+  KWRequestBodyDescription = 'description';
+  KWRequestBodyContent = 'content';
+  KWRequestBodyRequired = 'required';
+
+  // Media Type Object
+  KWMediaTypeSchema = 'schema';
+  KWMediaTypeExample = 'example';
+  KWMediaTypeExamples = 'examples';
+  KWMediaTypeEncoding = 'encoding';
+
+  // Encoding object
+  KWEncodingContentType = 'contentType';
+  KWEncodingHeaders = 'headers';
+  KWEncodingStyle = 'style';
+  KWEncodingExplode = 'explode';
+  KWEncodingAllowReserved = 'allowReserved';
+
+  // Responses Object
+  KWResponsesDefault = 'default';
+
+  // Response Object
+  KWResponseDescription = 'description';
+  KWResponseHeaders = 'headers';
+  KWResponseContent = 'content';
+  KWResponseLinks = 'links';
+
+  // Example object
+  KWExampleSummary = 'summary';
+  KWExampleDescription= 'description';
+  KWExampleValue = 'value';
+  KWExampleExternalValue = 'externalValue';
+
+  // Link Object
+  KWLinkOperationRef = 'operationRef';
+  KWLinkOperationId = 'operationId';
+  KWLinkParameters = 'parameters';
+  KWLinkRequestBody = 'requestBody';
+  KWLinkDescription = 'description';
+  KWLinkServer = 'server';
+
+  // Tag Object
+  KWTagName = 'name';
+  KWTagDescription = 'description';
+  KWTagExternalDocs = 'externalDocs';
+
+  // Reference Object
+  KWReferenceRef = '$ref';
+  KWReferenceSummary = 'summary';
+  KWReferenceDescription = 'description';
+
+  // Schema object
+  KWSchemaDiscriminator = 'discriminator';
+  KWSchemaXML = 'xml';
+  KWSchemaExternalDocs = 'externalDocs';
+  KWSchemaExample = 'example';
+
+  KWDiscriminatorPropertyName = 'propertyName';
+  KWDiscriminatorMapping = 'mapping';
+
+  // XML Object
+  KWXMLName = 'name';
+  KWXMLNamespace = 'namespace';
+  KWXMLPrefix = 'prefix';
+  KWXMLAttribute = 'attribute';
+  KWXMLWrapped = 'wrapped';
+
+  // Security scheme object
+  KWSecuritySchemeType = 'type';
+  KWSecuritySchemeDescription = 'description';
+  KWSecuritySchemeName = 'name';
+  KWSecuritySchemeIn = 'in';
+  KWSecuritySchemeScheme = 'scheme';
+  KWSecuritySchemeBearerFormat = 'bearerFormat';
+  KWSecuritySchemeFlows = 'flows';
+  KWSecuritySchemeOpenIdConnectUrl = 'openIdConnectUrl';
+
+  // Oauth Flows object
+  KWOAuthFlowsImplicit = 'implicit';
+  KWOAuthFlowsPassword= 'password';
+  KWOAuthFlowsClientCredentials = 'credentials';
+  KWOAuthFlowsClientAuthorizationCode = 'authorizationCode';
+
+  // Oauth Flow object
+  KWOAuthFlowAuthorizationUrl = 'authorizationUrl';
+  KWOAuthFlowTokenURL = 'tokenUrl';
+  KWOAuthFlowRefreshURL = 'refreshUrl';
+  KWOAuthFlowScopes = 'scopes';
+
+
+implementation
+
+end.
+

+ 5374 - 0
packages/fcl-openapi/src/fpopenapi.objects.pp

@@ -0,0 +1,5374 @@
+{
+    This file is part of the Free Component Library (FCL)
+    Copyright (c) 2024 by Michael Van Canneyt ([email protected])
+
+    Classes describing OpenAPI structures
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+
+unit fpopenapi.objects;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses
+  {$IFDEF FPC_DOTTEDUNITS}
+  System.Classes, System.SysUtils, System.Contnrs, FpJson.Data, 
+  {$ELSE}
+  Classes, SysUtils, contnrs, fpJSON, 
+  {$ENDIF}
+  fpopenapi.Types, fpjson.schema.schema;
+
+Type
+  EOpenAPi = Class(Exception);
+
+  // Forward definitions
+  TOpenAPI = class;
+  TInfo = class;
+  TContact = class;
+  TLicense = class;
+  TServer = class;
+  TServerList = class;
+  TServerVariable = class;
+  TServerVariableMap = class;
+  TComponents = class;
+  TPathItem = class;
+  TPathItemOrReference = class;
+  TPathItemOrReferenceMap = class;
+  TApiOperation = class;
+  TExternalDocumentation = class;
+  TParameter = class;
+  TParameterOrReference = class;
+  TParameterOrReferenceMap = class;
+  TParameterStyle = class;
+  TRequestBody = class;
+  TRequestBodyOrReference = class;
+  TRequestBodyOrReferenceMap = class;
+  TMediaType = class;
+  TMediaTypeMap = class;
+  TEncoding = class;
+  TEncodingMap = class;
+  TResponses = class;
+  TResponse = class;
+  TResponseOrReference = class;
+  TResponseOrReferenceMap = class;
+  TExample = class;
+  TExampleOrReference = class;
+  TExampleOrReferenceMap = class;
+  TLink = class;
+  TLinkOrReference = class;
+  TLinkOrReferenceMap = class;
+  TTag = class;
+  TReference = class;
+  TSchema = class;
+  TDiscriminator = class;
+  TXML = class;
+  TSecurityScheme = class;
+  TSecuritySchemeOrReference = class;
+  TSecuritySchemeOrReferenceMap = class;
+  TOAuthFlows = class;
+  TOauthFlow = class;
+  THeader = class;
+  THeaderOrReference = class;
+  THeaderOrReferenceMap = class;
+  TCallback = class;
+  TCallbackOrReference = class;
+  TCallbackOrReferenceMap = class;
+  TSecurityRequirement = class;
+  TSecurityRequirementList = class;
+  TBaseOpenAPIObjectList = class;
+
+  { TBaseOpenAPIObject }
+
+  TBaseOpenAPIObject = class(TObject)
+  private
+    FParent: TBaseOpenAPIObject;
+    FPathComponent : TJSONStringType;
+    FChildren : TBaseOpenAPIObjectList;
+  protected
+    function CreateChildrenList : TBaseOpenAPIObjectList; virtual;
+    procedure AddChild(aChild : TBaseOpenAPIObject);
+    procedure RemoveChild(aChild : TBaseOpenAPIObject);
+    procedure SetPathComponent(const aValue : TJSONStringType);
+  Public
+    constructor create(aParent : TBaseOpenAPIObject; aPathComponent : TJSONStringType); virtual;
+    destructor destroy; override;
+    Function GetChildByPathComponent(const aName : TJSONStringType): TBaseOpenAPIObject;
+    Function Find(const aPath : TJSONStringType): TBaseOpenAPIObject;
+    function PathComponent : TJSONStringType;
+    function Path : TJSONStringType;
+    property Parent : TBaseOpenAPIObject read FParent;
+  end;
+  TOpenAPIObjectClass = Class of TBaseOpenAPIObject;
+
+  { TBaseOpenAPIObjectList }
+
+  TBaseOpenAPIObjectList = Class(TFPObjectList)
+  private
+    function GetObject(aIndex : Integer): TBaseOpenAPIObject;
+  Public
+    Property Objects[aIndex : Integer] : TBaseOpenAPIObject Read GetObject; default;
+  end;
+
+
+  TExtendableObject = class(TBaseOpenAPIObject)
+  private
+    FExtensions : TJSONObject;
+    function GetExtensions: TJSONObject;
+    procedure SetExtensions(AValue: TJSONObject);
+  protected
+    Function CreateExtensions : TJSONObject; virtual;
+  Public
+    Function HasExtensions : Boolean;
+    Property Extensions : TJSONObject Read GetExtensions Write SetExtensions;
+  end;
+
+
+
+  { TNamedOpenAPiObject }
+
+  { TNamedObject }
+
+  TNamedObject = Class(TObject)
+  private
+    FName: TJSONStringType;
+    FObject: TObject;
+  Public
+    Constructor Create(aName: TJSONStringType; aObject : TObject);
+    Destructor Destroy; override;
+    Property Name : TJSONStringType Read FName;
+    Property Object_ : TObject Read FObject;
+  end;
+
+  { TNamedObjectList }
+
+  TNamedObjectList = class(TBaseOpenAPIObject)
+  Private
+    FList : TFPObjectList;
+    FHash : TFPObjectHashTable; //
+    FType : TClass;
+    function GetCount: Integer;
+    function GetName(aIndex : Integer): TJSONStringType;
+    function GetNamedObject(aIndex : Integer): TNamedObject;
+    procedure SetName(aIndex : Integer; AValue: TJSONStringType);
+    procedure SetNamedObject(aIndex : Integer; AValue: TNamedObject);
+  Protected
+    Function GetObjectByName(const aName : String): TObject;
+    Procedure Add(const AName : TJSONStringType; aObject : TObject);
+  Public
+    Constructor Create(aParent: TBaseOpenAPIObject; const aPathComponent : TJSONStringType; aType : TClass); virtual; reintroduce;
+    Destructor Destroy; override;
+    Function CreateNew(const AName : TJSONStringType) : TObject; virtual; abstract;
+    Procedure Delete(aName : TJSONStringType);
+    Procedure Delete(aIndex : Integer);
+    Function IndexOfName(aName : TJSONStringType) : Integer;
+    Property Names[aIndex : Integer] : TJSONStringType Read GetName Write SetName;
+    Property NamedObjects[aIndex : Integer] : TNamedObject Read GetNamedObject;
+    property Count : Integer Read GetCount;
+  end;
+  TNamedObjectListClass = Class of TNamedObjectList;
+
+  { TNamedOpenAPIObjectList }
+
+  TNamedOpenAPIObjectList = Class(TNamedObjectList)
+  private
+    function GetApiObject(aIndex : Integer): TBaseOpenAPIObject;
+  Public
+    constructor Create(aParent : TBaseOpenAPIObject; const aPathComponent : TJSONStringType; aType: TClass); override;
+    Function CreateNew(const AName : TJSONStringType) : TObject; override;
+    Property APIObjects[aIndex : Integer] : TBaseOpenAPIObject Read GetApiObject;
+  end;
+
+  { TNamedOpenAPiObject }
+
+
+  { TJSONSchemaMap }
+
+  TJSONSchemaMap = Class(TNamedObjectList)
+  private
+    function GetNamedSchema(aName: TJSONStringType): TJSONSchema;
+  public
+    function Add(const AName : TJSONStringType): TJSONSchema; reintroduce;
+    Function CreateNew(const AName : TJSONStringType) : TObject; override;
+    Property Schemas[aName: TJSONStringType] : TJSONSchema Read GetNamedSchema; default;
+  end;
+
+  { TPathsList }
+
+  TPathsList = class(TNamedOpenAPIObjectList)
+  Private
+    function GetObject(const aName : TJSONStringType) : TPathItem;
+    function GetObjectByIndex(aIndex : Integer): TPathItem;
+  Public
+    constructor Create(aParent : TBaseOpenAPIObject; Const aPathComponent: TJSONStringType); reintroduce;
+    function AddItem(const aName : TJSONStringType) : TPathItem;
+    property Paths[aName : TJSONStringType] : TPathItem Read GetObject; default;
+    property PathByIndex[aIndex : Integer] : TPathItem Read GetObjectByIndex;
+  end;
+
+  { TTagList }
+
+  TTagList = class(TBaseOpenAPIObjectList)
+  private
+    function GetTag(aIndex : Integer): TTag;
+  Public
+    procedure AddTag(aTag : TTag);
+    property Tags [aIndex : Integer] : TTag Read GetTag; default;
+  end;
+
+  { TParameterOrReferenceList }
+
+  TParameterOrReferenceList = class(TBaseOpenAPIObjectList)
+  private
+    function GetParam(aIndex : Integer): TParameterOrReference;
+  Public
+    Function AddParam(aParent : TBaseOpenAPIObject) : TParameterOrReference;
+    Property Params[aIndex : Integer] : TParameterOrReference Read GetParam; default;
+  end;
+
+  TJSONDataMap = class(TObject);
+
+
+  { TOpenAPI }
+
+  TOpenAPI = Class(TExtendableObject)
+  Private
+    FKeywords : TOpenAPIKeywords;
+    FOpenApi : string;
+    FInfo : TInfo;
+    FJSONSchemaDialect : string;
+    FServers : TServerList;
+    FPaths : TPathsList;
+    FWebHooks : TPathItemOrReferenceMap;
+    FComponents : TComponents;
+    FSecurity : TSecurityRequirementList;
+    FTags : TTagList;
+    FExternalDocs : TExternalDocumentation;
+    Function Get_Info : TInfo;
+    Function Get_Servers : TServerList;
+    Function Get_Paths : TPathsList;
+    Function Get_WebHooks : TPathItemOrReferenceMap;
+    Function Get_Components : TComponents;
+    Function Get_Security : TSecurityRequirementList;
+    Function Get_Tags : TTagList;
+    Function Get_ExternalDocs : TExternalDocumentation;
+    procedure Set_OpenApi(const aValue : string);
+    procedure Set_Info(const aValue : TInfo);
+    procedure Set_JSONSchemaDialect(const aValue : string);
+    procedure Set_Servers(const aValue : TServerList);
+    procedure Set_Paths(const aValue : TPathsList);
+    procedure Set_WebHooks(const aValue : TPathItemOrReferenceMap);
+    procedure Set_Components(const aValue : TComponents);
+    procedure Set_Security(const aValue : TSecurityRequirementList);
+    procedure Set_Tags(const aValue : TTagList);
+    procedure Set_ExternalDocs(const aValue : TExternalDocumentation);
+  Protected
+    procedure AddKeyword(aKeyword : TOpenAPIKeyword); virtual;
+    procedure RemoveKeyword(aKeyword : TOpenAPIKeyword); virtual;
+  public
+    Constructor Create; reintroduce;
+    destructor destroy; override;
+    function HasKeyWord(aKeyword :TOpenAPIKeyword) : Boolean;
+    property OpenApi: string Read FOpenApi write Set_OpenApi;
+    property Info: TInfo Read Get_Info write Set_Info;
+    property JSONSchemaDialect: string Read FJSONSchemaDialect write Set_JSONSchemaDialect;
+    property Servers: TServerList Read Get_Servers write Set_Servers;
+    property Paths: TPathsList Read Get_Paths write Set_Paths;
+    property WebHooks: TPathItemOrReferenceMap Read Get_WebHooks write Set_WebHooks;
+    property Components: TComponents Read Get_Components write Set_Components;
+    property Security: TSecurityRequirementList Read Get_Security write Set_Security;
+    property Tags: TTagList Read Get_Tags write Set_Tags;
+    property ExternalDocs: TExternalDocumentation Read Get_ExternalDocs write Set_ExternalDocs;
+  end;
+  TOpenAPIArray = array of TOpenAPI;
+
+  { TInfo }
+
+  TInfo = Class(TExtendableObject)
+  Private
+    FKeywords : TInfoKeywords;
+    FTitle : string;
+    FSummary : string;
+    FDescription : string;
+    FTermsOfService : string;
+    FContact : TContact;
+    FLicense : TLicense;
+    FVersion : string;
+    Function Get_Contact : TContact;
+    Function Get_License : TLicense;
+    procedure Set_Title(const aValue : string);
+    procedure Set_Summary(const aValue : string);
+    procedure Set_Description(const aValue : string);
+    procedure Set_TermsOfService(const aValue : string);
+    procedure Set_Contact(const aValue : TContact);
+    procedure Set_License(const aValue : TLicense);
+    procedure Set_Version(const aValue : string);
+  Protected
+    procedure AddKeyword(aKeyword : TInfoKeyword); virtual;
+    procedure RemoveKeyword(aKeyword : TInfoKeyword); virtual;
+  public
+    destructor destroy; override;
+    function HasKeyWord(aKeyword :TInfoKeyword) : Boolean;
+    property Title: string Read FTitle write Set_Title;
+    property Summary: string Read FSummary write Set_Summary;
+    property Description: string Read FDescription write Set_Description;
+    property TermsOfService: string Read FTermsOfService write Set_TermsOfService;
+    property Contact: TContact Read Get_Contact write Set_Contact;
+    property License: TLicense Read Get_License write Set_License;
+    property Version: string Read FVersion write Set_Version;
+  end;
+  TInfoArray = array of TInfo;
+
+
+  { TContact }
+
+  TContact = Class(TExtendableObject)
+  Private
+    FKeywords : TContactKeywords;
+    FName : string;
+    FUrl : string;
+    FEmail : string;
+    procedure Set_Name(const aValue : string);
+    procedure Set_Url(const aValue : string);
+    procedure Set_Email(const aValue : string);
+  Protected
+    procedure AddKeyword(aKeyword : TContactKeyword); virtual;
+    procedure RemoveKeyword(aKeyword : TContactKeyword); virtual;
+  public
+    destructor destroy; override;
+    function HasKeyWord(aKeyword :TContactKeyword) : Boolean;
+    property Name: string Read FName write Set_Name;
+    property Url: string Read FUrl write Set_Url;
+    property Email: string Read FEmail write Set_Email;
+  end;
+  TContactArray = array of TContact;
+
+  { TLicense }
+
+  TLicense = Class(TExtendableObject)
+  Private
+    FKeywords : TLicenseKeywords;
+    FName : string;
+    FIdentifier : string;
+    FUrl : string;
+    procedure Set_Name(const aValue : string);
+    procedure Set_Identifier(const aValue : string);
+    procedure Set_Url(const aValue : string);
+  Protected
+    procedure AddKeyword(aKeyword : TLicenseKeyword); virtual;
+    procedure RemoveKeyword(aKeyword : TLicenseKeyword); virtual;
+  public
+    destructor destroy; override;
+    function HasKeyWord(aKeyword :TLicenseKeyword) : Boolean;
+    property Name: string Read FName write Set_Name;
+    property Identifier: string Read FIdentifier write Set_Identifier;
+    property Url: string Read FUrl write Set_Url;
+  end;
+  TLicenseArray = array of TLicense;
+
+  { TServer }
+
+  TServer = Class(TExtendableObject)
+  Private
+    FKeywords : TServerKeywords;
+    FServerUrl : string;
+    FDescription : string;
+    FVariables : TServerVariableMap;
+    Function Get_Variables : TServerVariableMap;
+    procedure Set_ServerUrl(const aValue : string);
+    procedure Set_Description(const aValue : string);
+    procedure Set_Variables(const aValue : TServerVariableMap);
+  Protected
+    procedure AddKeyword(aKeyword : TServerKeyword); virtual;
+    procedure RemoveKeyword(aKeyword : TServerKeyword); virtual;
+  public
+    destructor destroy; override;
+    function HasKeyWord(aKeyword :TServerKeyword) : Boolean;
+    property Url: string Read FServerUrl write Set_ServerUrl;
+    property Description: string Read FDescription write Set_Description;
+    property Variables: TServerVariableMap Read Get_Variables write Set_Variables;
+  end;
+  TServerArray = array of TServer;
+
+  { TServerList }
+
+  TServerList = class(TFPObjectList)
+  Private
+    function GetObj(aIndex : Integer): TServer;
+    procedure SetObj(aIndex : Integer; aValue : TServer);
+  Public
+    function ToArray : TServerArray;
+    property Servers[aIndex : integer] : TServer Read GetObj Write SetObj; default;
+  end;
+
+  { TServerVariable }
+
+  TServerVariable = Class(TExtendableObject)
+  Private
+    FKeywords : TServerVariableKeywords;
+    FEnum : TStrings;
+    FDefault : string;
+    FDescription : string;
+    Function Get_Enum : TStrings;
+    procedure Set_Enum(const aValue : TStrings);
+    procedure Set_Default(const aValue : string);
+    procedure Set_Description(const aValue : string);
+  Protected
+    procedure AddKeyword(aKeyword : TServerVariableKeyword); virtual;
+    procedure RemoveKeyword(aKeyword : TServerVariableKeyword); virtual;
+  public
+    destructor destroy; override;
+    function HasKeyWord(aKeyword :TServerVariableKeyword) : Boolean;
+    property Enum: TStrings Read Get_Enum write Set_Enum;
+    property Default: string Read FDefault write Set_Default;
+    property Description: string Read FDescription write Set_Description;
+  end;
+  TServerVariableArray = array of TServerVariable;
+
+  { TServerVariableMap }
+
+  TServerVariableMap = Class(TNamedOpenAPIObjectList)
+  Private
+    function GetObject(const aName : TJSONStringType) : TServerVariable;
+  Public
+    constructor Create(aParent : TBaseOpenAPIObject; const aPathComponent : TJSONStringType); reintroduce;
+    function AddItem(const aName : TJSONStringType) : TServerVariable;
+    property ServerVariables[aName : TJSONStringType] : TServerVariable Read GetObject; default;
+  end;
+
+  { TComponents }
+
+  TComponents = Class(TExtendableObject)
+  Private
+    FKeywords : TComponentsKeywords;
+    FSchemas : TJSONSchemaMap;
+    FResponses : TResponseOrReferenceMap;
+    FParameters : TParameterOrReferenceMap;
+    FExamples : TExampleOrReferenceMap;
+    FRequestBodies : TRequestBodyOrReferenceMap;
+    FHeaders : THeaderOrReferenceMap;
+    FSecuritySchemes : TSecuritySchemeOrReferenceMap;
+    FLinks : TLinkOrReferenceMap;
+    FCallbacks : TLinkOrReferenceMap;
+    FPathItems : TPathItemOrReferenceMap;
+    Function Get_Schemas : TJSONSchemaMap;
+    Function Get_Responses : TResponseOrReferenceMap;
+    Function Get_Parameters : TParameterOrReferenceMap;
+    Function Get_Examples : TExampleOrReferenceMap;
+    Function Get_RequestBodies : TRequestBodyOrReferenceMap;
+    Function Get_Headers : THeaderOrReferenceMap;
+    Function Get_SecuritySchemes : TSecuritySchemeOrReferenceMap;
+    Function Get_Links : TLinkOrReferenceMap;
+    Function Get_Callbacks : TLinkOrReferenceMap;
+    Function Get_PathItems : TPathItemOrReferenceMap;
+    procedure Set_Schemas(const aValue : TJSONSchemaMap);
+    procedure Set_Responses(const aValue : TResponseOrReferenceMap);
+    procedure Set_Parameters(const aValue : TParameterOrReferenceMap);
+    procedure Set_Examples(const aValue : TExampleOrReferenceMap);
+    procedure Set_RequestBodies(const aValue : TRequestBodyOrReferenceMap);
+    procedure Set_Headers(const aValue : THeaderOrReferenceMap);
+    procedure Set_SecuritySchemes(const aValue : TSecuritySchemeOrReferenceMap);
+    procedure Set_Links(const aValue : TLinkOrReferenceMap);
+    procedure Set_Callbacks(const aValue : TLinkOrReferenceMap);
+    procedure Set_PathItems(const aValue : TPathItemOrReferenceMap);
+  Protected
+    procedure AddKeyword(aKeyword : TComponentsKeyword); virtual;
+    procedure RemoveKeyword(aKeyword : TComponentsKeyword); virtual;
+  public
+    destructor destroy; override;
+    function HasKeyWord(aKeyword :TComponentsKeyword) : Boolean;
+    property Schemas: TJSONSchemaMap Read Get_Schemas write Set_Schemas;
+    property Responses: TResponseOrReferenceMap Read Get_Responses write Set_Responses;
+    property Parameters: TParameterOrReferenceMap Read Get_Parameters write Set_Parameters;
+    property Examples: TExampleOrReferenceMap Read Get_Examples write Set_Examples;
+    property RequestBodies: TRequestBodyOrReferenceMap Read Get_RequestBodies write Set_RequestBodies;
+    property Headers: THeaderOrReferenceMap Read Get_Headers write Set_Headers;
+    property SecuritySchemes: TSecuritySchemeOrReferenceMap Read Get_SecuritySchemes write Set_SecuritySchemes;
+    property Links: TLinkOrReferenceMap Read Get_Links write Set_Links;
+    property Callbacks: TLinkOrReferenceMap Read Get_Callbacks write Set_Callbacks;
+    property PathItems: TPathItemOrReferenceMap Read Get_PathItems write Set_PathItems;
+  end;
+  TComponentsArray = array of TComponents;
+
+  { TPathItem }
+
+  TPathItem = Class(TExtendableObject)
+  Private
+    FKeywords : TPathItemKeywords;
+    FRef : string;
+    FSummary : string;
+    FDescription : string;
+    FGet : TApiOperation;
+    FPut : TApiOperation;
+    FPost : TApiOperation;
+    FDelete : TApiOperation;
+    FOptions : TApiOperation;
+    FHead : TApiOperation;
+    FPatch : TApiOperation;
+    FTrace : TApiOperation;
+    FServers : TServerList;
+    FParameters : TParameterOrReferenceList;
+    Function Get_Get : TApiOperation;
+    Function Get_Put : TApiOperation;
+    Function Get_Post : TApiOperation;
+    Function Get_Delete : TApiOperation;
+    Function Get_Options : TApiOperation;
+    Function Get_Head : TApiOperation;
+    Function Get_Patch : TApiOperation;
+    Function Get_Trace : TApiOperation;
+    Function Get_Servers : TServerList;
+    Function Get_Parameters : TParameterOrReferenceList;
+    procedure Set_Ref(const aValue : string);
+    procedure Set_Summary(const aValue : string);
+    procedure Set_Description(const aValue : string);
+    procedure Set_Get(const aValue : TApiOperation);
+    procedure Set_Put(const aValue : TApiOperation);
+    procedure Set_Post(const aValue : TApiOperation);
+    procedure Set_Delete(const aValue : TApiOperation);
+    procedure Set_Options(const aValue : TApiOperation);
+    procedure Set_Head(const aValue : TApiOperation);
+    procedure Set_Patch(const aValue : TApiOperation);
+    procedure Set_Trace(const aValue : TApiOperation);
+    procedure Set_Servers(const aValue : TServerList);
+    procedure Set_Parameters(const aValue : TParameterOrReferenceList);
+  Protected
+    procedure AddKeyword(aKeyword : TPathItemKeyword); virtual;
+    procedure RemoveKeyword(aKeyword : TPathItemKeyword); virtual;
+  public
+    destructor destroy; override;
+    function HasKeyWord(aKeyword :TPathItemKeyword) : Boolean;
+    function GetOperation(aKeyword : TPathItemOperationKeyword) : TAPIOperation;
+    property Ref: string Read FRef write Set_Ref;
+    property Summary: string Read FSummary write Set_Summary;
+    property Description: string Read FDescription write Set_Description;
+    property Get: TApiOperation Read Get_Get write Set_Get;
+    property Put: TApiOperation Read Get_Put write Set_Put;
+    property Post: TApiOperation Read Get_Post write Set_Post;
+    property Delete: TApiOperation Read Get_Delete write Set_Delete;
+    property Options: TApiOperation Read Get_Options write Set_Options;
+    property Head: TApiOperation Read Get_Head write Set_Head;
+    property Patch: TApiOperation Read Get_Patch write Set_Patch;
+    property Trace: TApiOperation Read Get_Trace write Set_Trace;
+    property Servers: TServerList Read Get_Servers write Set_Servers;
+    property Parameters: TParameterOrReferenceList Read Get_Parameters write Set_Parameters;
+  end;
+  TPathItemArray = array of TPathItem;
+
+  TPathItemOrReference = Class(TPathItem)
+  Private
+    FReference : TReference;
+    function GetReference : TReference;
+  Public
+    destructor Destroy; override;
+    function HasReference : Boolean;
+    property Reference : TReference Read GetReference;
+  end;
+
+  { TPathItemOrReferenceMap }
+
+  TPathItemOrReferenceMap = Class(TNamedOpenAPIObjectList)
+  Private
+    function GetObject(const aName : TJSONStringType) : TPathItemOrReference;
+  Public
+    constructor Create(aParent : TBaseOpenAPIObject; aPathComponent : TJSONStringType); reintroduce;
+    function AddItem(const aName : TJSONStringType) : TPathItemOrReference;
+    property PathItemOrReferences[aName : TJSONStringType] : TPathItemOrReference Read GetObject; default;
+  end;
+
+  { TApiOperation }
+
+  TApiOperation = Class(TExtendableObject)
+  Private
+    FKeywords : TApiOperationKeywords;
+    FTags : TStrings;
+    FSummary : string;
+    FDescription : string;
+    FExternalDocs : TExternalDocumentation;
+    FOperationId : string;
+    FParameters : TParameterOrReferenceList;
+    FRequestBody : TRequestBodyOrReference;
+    FResponses : TResponses;
+    FCallbacks : TCallBackOrReferenceMap;
+    FDeprecated : Boolean;
+    FSecurity : TSecurityRequirementList;
+    FServers : TServerList;
+    Function Get_Tags : TStrings;
+    Function Get_ExternalDocs : TExternalDocumentation;
+    Function Get_Parameters : TParameterOrReferenceList;
+    Function Get_RequestBody : TRequestBodyOrReference;
+    Function Get_Responses : TResponses;
+    Function Get_Callbacks : TCallBackOrReferenceMap;
+    Function Get_Security : TSecurityRequirementList;
+    Function Get_Servers : TServerList;
+    procedure Set_Tags(const aValue : TStrings);
+    procedure Set_Summary(const aValue : string);
+    procedure Set_Description(const aValue : string);
+    procedure Set_ExternalDocs(const aValue : TExternalDocumentation);
+    procedure Set_OperationId(const aValue : string);
+    procedure Set_Parameters(const aValue : TParameterOrReferenceList);
+    procedure Set_RequestBody(const aValue : TRequestBodyOrReference);
+    procedure Set_Responses(const aValue : TResponses);
+    procedure Set_Callbacks(const aValue : TCallBackOrReferenceMap);
+    procedure Set_Deprecated(const aValue : Boolean);
+    procedure Set_Security(const aValue : TSecurityRequirementList);
+    procedure Set_Servers(const aValue : TServerList);
+  Protected
+    procedure AddKeyword(aKeyword : TApiOperationKeyword); virtual;
+    procedure RemoveKeyword(aKeyword : TApiOperationKeyword); virtual;
+  public
+    destructor destroy; override;
+    function HasKeyWord(aKeyword :TApiOperationKeyword) : Boolean;
+    property Tags: TStrings Read Get_Tags write Set_Tags;
+    property Summary: string Read FSummary write Set_Summary;
+    property Description: string Read FDescription write Set_Description;
+    property ExternalDocs: TExternalDocumentation Read Get_ExternalDocs write Set_ExternalDocs;
+    property OperationId: string Read FOperationId write Set_OperationId;
+    property Parameters: TParameterOrReferenceList Read Get_Parameters write Set_Parameters;
+    property RequestBody: TRequestBodyOrReference Read Get_RequestBody write Set_RequestBody;
+    property Responses: TResponses Read Get_Responses write Set_Responses;
+    property Callbacks: TCallBackOrReferenceMap Read Get_Callbacks write Set_Callbacks;
+    property Deprecated: Boolean Read FDeprecated write Set_Deprecated;
+    property Security: TSecurityRequirementList Read Get_Security write Set_Security;
+    property Servers: TServerList Read Get_Servers write Set_Servers;
+  end;
+  TApiOperationArray = array of TApiOperation;
+
+  { TExternalDocumentation }
+
+  TExternalDocumentation = Class(TExtendableObject)
+  Private
+    FKeywords : TExternalDocumentationKeywords;
+    FDescription : string;
+    FUrl : string;
+    procedure Set_Description(const aValue : string);
+    procedure Set_Url(const aValue : string);
+  Protected
+    procedure AddKeyword(aKeyword : TExternalDocumentationKeyword); virtual;
+    procedure RemoveKeyword(aKeyword : TExternalDocumentationKeyword); virtual;
+  public
+    destructor destroy; override;
+    function HasKeyWord(aKeyword :TExternalDocumentationKeyword) : Boolean;
+    property Description: string Read FDescription write Set_Description;
+    property Url: string Read FUrl write Set_Url;
+  end;
+  TExternalDocumentationArray = array of TExternalDocumentation;
+
+  { TParameter }
+
+  TParameterOrHeader = Class(TExtendableObject)
+  Private
+    FKeywords : TParameterKeywords;
+    FName : string;
+    FIn_ : string;
+    FDescription : string;
+    FRequired : Boolean;
+    FDeprecated : Boolean;
+    FAllowEmptyValue : Boolean;
+    FStyle : string;
+    FExplode : Boolean;
+    FAllowReserved : Boolean;
+    FSchema : TJSONSchema;
+    FExample : TJSONData;
+    FExamples : TExampleOrReferenceMap;
+    FContent : TMediaTypeMap;
+    Function Get_Schema : TJSONSchema;
+    Function Get_Examples : TExampleOrReferenceMap;
+    Function Get_Content : TMediaTypeMap;
+    procedure Set_Name(const aValue : string); virtual;
+    procedure Set_In_(const aValue : string); virtual;
+    procedure Set_Description(const aValue : string);
+    procedure Set_Required(const aValue : Boolean);
+    procedure Set_Deprecated(const aValue : Boolean);
+    procedure Set_AllowEmptyValue(const aValue : Boolean);
+    procedure Set_Style(const aValue : string);
+    procedure Set_Explode(const aValue : Boolean);
+    procedure Set_AllowReserved(const aValue : Boolean);
+    procedure Set_Schema(const aValue : TJSONSchema);
+    procedure Set_Example(const aValue : TJSONData);
+    procedure Set_Examples(const aValue : TExampleOrReferenceMap);
+    procedure Set_Content(const aValue : TMediaTypeMap);
+  Protected
+    procedure AddKeyword(aKeyword : TParameterKeyword); virtual;
+    procedure RemoveKeyword(aKeyword : TParameterKeyword); virtual;
+    property Name: string Read FName write Set_Name;
+    property In_: string Read FIn_ write Set_In_;
+  public
+    destructor destroy; override;
+    function HasKeyWord(aKeyword :TParameterKeyword) : Boolean;
+    property Description: string Read FDescription write Set_Description;
+    property Required: Boolean Read FRequired write Set_Required;
+    property Deprecated: Boolean Read FDeprecated write Set_Deprecated;
+    property AllowEmptyValue: Boolean Read FAllowEmptyValue write Set_AllowEmptyValue;
+    property Style: string Read FStyle write Set_Style;
+    property Explode: Boolean Read FExplode write Set_Explode;
+    property AllowReserved: Boolean Read FAllowReserved write Set_AllowReserved;
+    property Schema: TJSONSchema Read Get_Schema write Set_Schema;
+    property Example: TJSONData Read FExample write Set_Example;
+    property Examples: TExampleOrReferenceMap Read Get_Examples write Set_Examples;
+    property Content: TMediaTypeMap Read Get_Content write Set_Content;
+  end;
+
+  TParameter = Class(TParameterOrHeader)
+  Public
+    Property Name;
+    property In_;
+  end;
+  TParameterArray = array of TParameter;
+
+  THeader = Class(TParameterOrHeader)
+  end;
+  THeaderArray = array of THeader;
+
+
+  TParameterOrReference = Class(TParameter)
+  Private
+    FReference : TReference;
+    function GetReference : TReference;
+  Public
+    destructor Destroy; override;
+    function HasReference : Boolean;
+    property Reference : TReference Read GetReference;
+  end;
+
+  { TParameterOrReferenceMap }
+
+  TParameterOrReferenceMap = Class(TNamedOpenAPIObjectList)
+  Private
+    function GetObject(const aName : TJSONStringType) : TParameterOrReference;
+  Public
+    constructor Create(aParent : TBaseOpenAPIObject; const aPathComponent : TJSONStringType); reintroduce;
+    function AddItem(const aName : TJSONStringType) : TParameterOrReference;
+    property ParameterOrReferences[aName : TJSONStringType] : TParameterOrReference Read GetObject; default;
+  end;
+
+  { TParameterStyle }
+
+  TParameterStyle = Class(TExtendableObject)
+  Private
+    FKeywords : TParameterStyleKeywords;
+    FMatrix : string;
+    FLabel_ : string;
+    FForm : string;
+    FSimple : string;
+    FSpaceDelimited : string;
+    FPipeDelimited : string;
+    FDeepObject : string;
+    procedure Set_Matrix(const aValue : string);
+    procedure Set_Label_(const aValue : string);
+    procedure Set_Form(const aValue : string);
+    procedure Set_Simple(const aValue : string);
+    procedure Set_SpaceDelimited(const aValue : string);
+    procedure Set_PipeDelimited(const aValue : string);
+    procedure Set_DeepObject(const aValue : string);
+  Protected
+    procedure AddKeyword(aKeyword : TParameterStyleKeyword); virtual;
+    procedure RemoveKeyword(aKeyword : TParameterStyleKeyword); virtual;
+  public
+    destructor destroy; override;
+    function HasKeyWord(aKeyword :TParameterStyleKeyword) : Boolean;
+    property Matrix: string Read FMatrix write Set_Matrix;
+    property Label_: string Read FLabel_ write Set_Label_;
+    property Form: string Read FForm write Set_Form;
+    property Simple: string Read FSimple write Set_Simple;
+    property SpaceDelimited: string Read FSpaceDelimited write Set_SpaceDelimited;
+    property PipeDelimited: string Read FPipeDelimited write Set_PipeDelimited;
+    property DeepObject: string Read FDeepObject write Set_DeepObject;
+  end;
+  TParameterStyleArray = array of TParameterStyle;
+
+  { TRequestBody }
+
+  TRequestBody = Class(TExtendableObject)
+  Private
+    FKeywords : TRequestBodyKeywords;
+    FDescription : string;
+    FContent : TMediaTypeMap;
+    FRequired : Boolean;
+    Function Get_Content : TMediaTypeMap;
+    procedure Set_Description(const aValue : string);
+    procedure Set_Content(const aValue : TMediaTypeMap);
+    procedure Set_Required(const aValue : Boolean);
+  Protected
+    procedure AddKeyword(aKeyword : TRequestBodyKeyword); virtual;
+    procedure RemoveKeyword(aKeyword : TRequestBodyKeyword); virtual;
+  public
+    destructor destroy; override;
+    function HasKeyWord(aKeyword :TRequestBodyKeyword) : Boolean;
+    property Description: string Read FDescription write Set_Description;
+    property Content: TMediaTypeMap Read Get_Content write Set_Content;
+    property Required: Boolean Read FRequired write Set_Required;
+  end;
+  TRequestBodyArray = array of TRequestBody;
+
+
+  TRequestBodyOrReference = Class(TRequestBody)
+  Private
+    FReference : TReference;
+    function GetReference : TReference;
+  Public
+    destructor Destroy; override;
+    function HasReference : Boolean;
+    property Reference : TReference Read GetReference;
+  end;
+
+  { TRequestBodyOrReferenceMap }
+
+  TRequestBodyOrReferenceMap = Class(TNamedOpenAPIObjectList)
+  Private
+    function GetObject(const aName : TJSONStringType) : TRequestBodyOrReference;
+  Public
+    constructor Create(aParent : TBaseOpenAPIObject; const aPathComponent : TJSONStringType); reintroduce;
+    function AddItem(const aName : TJSONStringType) : TRequestBodyOrReference;
+    property RequestBodyOrReferences[aName : TJSONStringType] : TRequestBodyOrReference Read GetObject; default;
+  end;
+
+  { TMediaType }
+
+  TMediaType = Class(TExtendableObject)
+  Private
+    FKeywords : TMediaTypeKeywords;
+    FSchema : TJSONSchema;
+    FExample : TJSONData;
+    FExamples : TExampleOrReferenceMap;
+    FEncoding : TEncodingMap;
+    Function Get_Schema : TJSONSchema;
+    Function Get_Examples : TExampleOrReferenceMap;
+    Function Get_Encoding : TEncodingMap;
+    procedure Set_Schema(const aValue : TJSONSchema);
+    procedure Set_Example(const aValue : TJSONData);
+    procedure Set_Examples(const aValue : TExampleOrReferenceMap);
+    procedure Set_Encoding(const aValue : TEncodingMap);
+  Protected
+    procedure AddKeyword(aKeyword : TMediaTypeKeyword); virtual;
+    procedure RemoveKeyword(aKeyword : TMediaTypeKeyword); virtual;
+  public
+    destructor destroy; override;
+    function HasKeyWord(aKeyword :TMediaTypeKeyword) : Boolean;
+    property Schema: TJSONSchema Read Get_Schema write Set_Schema;
+    property Example: TJSONData Read FExample write Set_Example;
+    property Examples: TExampleOrReferenceMap Read Get_Examples write Set_Examples;
+    property Encoding: TEncodingMap Read Get_Encoding write Set_Encoding;
+  end;
+  TMediaTypeArray = array of TMediaType;
+
+  { TMediaTypeMap }
+
+  TMediaTypeMap = Class(TNamedOpenAPIObjectList)
+  Private
+    function GetObject(const aName : TJSONStringType) : TMediaType;
+  Public
+    constructor Create(aParent : TBaseOpenAPIObject; const aPathcomponent : TJSONStringType); reintroduce;
+    function AddItem(const aName : TJSONStringType) : TMediaType;
+    property MediaTypes[aName : TJSONStringType] : TMediaType Read GetObject; default;
+  end;
+
+  { TEncoding }
+
+  TEncoding = Class(TExtendableObject)
+  Private
+    FKeywords : TEncodingKeywords;
+    FContentType : string;
+    FHeaders : THeaderOrReferenceMap;
+    FStyle : string;
+    FExplode : Boolean;
+    FAllowReserved : Boolean;
+    Function Get_Headers : THeaderOrReferenceMap;
+    procedure Set_ContentType(const aValue : string);
+    procedure Set_Headers(const aValue : THeaderOrReferenceMap);
+    procedure Set_Style(const aValue : string);
+    procedure Set_Explode(const aValue : Boolean);
+    procedure Set_AllowReserved(const aValue : Boolean);
+  Protected
+    procedure AddKeyword(aKeyword : TEncodingKeyword); virtual;
+    procedure RemoveKeyword(aKeyword : TEncodingKeyword); virtual;
+  public
+    destructor destroy; override;
+    function HasKeyWord(aKeyword :TEncodingKeyword) : Boolean;
+    property ContentType: string Read FContentType write Set_ContentType;
+    property Headers: THeaderOrReferenceMap Read Get_Headers write Set_Headers;
+    property Style: string Read FStyle write Set_Style;
+    property Explode: Boolean Read FExplode write Set_Explode;
+    property AllowReserved: Boolean Read FAllowReserved write Set_AllowReserved;
+  end;
+  TEncodingArray = array of TEncoding;
+
+  { TEncodingMap }
+
+  TEncodingMap = Class(TNamedOpenAPIObjectList)
+  Private
+    function GetObject(const aName : TJSONStringType) : TEncoding;
+  Public
+    constructor Create(aParent : TBaseOpenAPIObject; const aPathComponent : TJSONStringType); reintroduce;
+    function AddItem(const aName : TJSONStringType) : TEncoding;
+    property Encodings[aName : TJSONStringType] : TEncoding Read GetObject; default;
+  end;
+
+  { TResponses }
+
+  TResponses = Class(TNamedOpenAPIObjectList)
+  Private
+    function GetObject(const aName : TJSONStringType) : TResponse;
+    function GetResponseByIndex(aIndex : Integer): TResponse;
+  Public
+    constructor Create(aParent : TBaseOpenAPIObject; const aPathComponent : TJSONStringType); reintroduce;
+    function AddItem(const aName : TJSONStringType) : TResponse;
+    property ResponseByIndex[aIndex : Integer] : TResponse Read GetResponseByIndex;
+    property Encodings[aName : TJSONStringType] : TResponse Read GetObject; default;
+  end;
+  TResponsesArray = array of TResponses;
+
+  { TResponse }
+
+  TResponse = Class(TExtendableObject)
+  Private
+    FKeywords : TResponseKeywords;
+    FDescription : string;
+    FHeaders : THeaderOrReferenceMap;
+    FContent : TMediaTypeMap;
+    FLinks : TLinkOrReferenceMap;
+    Function Get_Headers : THeaderOrReferenceMap;
+    Function Get_Content : TMediaTypeMap;
+    Function Get_Links : TLinkOrReferenceMap;
+    procedure Set_Description(const aValue : string);
+    procedure Set_Headers(const aValue : THeaderOrReferenceMap);
+    procedure Set_Content(const aValue : TMediaTypeMap);
+    procedure Set_Links(const aValue : TLinkOrReferenceMap);
+  Protected
+    procedure AddKeyword(aKeyword : TResponseKeyword); virtual;
+    procedure RemoveKeyword(aKeyword : TResponseKeyword); virtual;
+  public
+    destructor destroy; override;
+    function HasKeyWord(aKeyword :TResponseKeyword) : Boolean;
+    property Description: string Read FDescription write Set_Description;
+    property Headers: THeaderOrReferenceMap Read Get_Headers write Set_Headers;
+    property Content: TMediaTypeMap Read Get_Content write Set_Content;
+    property Links: TLinkOrReferenceMap Read Get_Links write Set_Links;
+  end;
+  TResponseArray = array of TResponse;
+
+  TResponseOrReference = Class(TResponse)
+  Private
+    FReference : TReference;
+    function GetReference : TReference;
+  Public
+    destructor Destroy; override;
+    function HasReference : Boolean;
+    property Reference : TReference Read GetReference;
+  end;
+
+  { TResponseOrReferenceMap }
+
+  TResponseOrReferenceMap = Class(TNamedOpenAPIObjectList)
+  Private
+    function GetObject(const aName : TJSONStringType) : TResponseOrReference;
+  Public
+    constructor Create(aParent : TBaseOpenAPIObject; const aPathComponent : TJSONStringType); reintroduce;
+    function AddItem(const aName : TJSONStringType) : TResponseOrReference;
+    property ResponseOrReferences[aName : TJSONStringType] : TResponseOrReference Read GetObject; default;
+  end;
+
+  { TExample }
+
+  TExample = Class(TExtendableObject)
+  Private
+    FKeywords : TExampleKeywords;
+    FSummary : string;
+    FDescription : string;
+    FValue : TJSONData;
+    FExternalValue : string;
+    procedure Set_Summary(const aValue : string);
+    procedure Set_Description(const aValue : string);
+    procedure Set_Value(const aValue : TJSONData);
+    procedure Set_ExternalValue(const aValue : string);
+  Protected
+    procedure AddKeyword(aKeyword : TExampleKeyword); virtual;
+    procedure RemoveKeyword(aKeyword : TExampleKeyword); virtual;
+  public
+    destructor destroy; override;
+    function HasKeyWord(aKeyword :TExampleKeyword) : Boolean;
+    property Summary: string Read FSummary write Set_Summary;
+    property Description: string Read FDescription write Set_Description;
+    property Value: TJSONData Read FValue write Set_Value;
+    property ExternalValue: string Read FExternalValue write Set_ExternalValue;
+  end;
+  TExampleArray = array of TExample;
+
+  TExampleOrReference = Class(TExample)
+  Private
+    FReference : TReference;
+    function GetReference : TReference;
+  Public
+    destructor Destroy; override;
+    function HasReference : Boolean;
+    property Reference : TReference Read GetReference;
+  end;
+
+  { TExampleOrReferenceMap }
+
+  TExampleOrReferenceMap = Class(TNamedOpenAPIObjectList)
+  Private
+    function GetObject(const aName : TJSONStringType) : TExampleOrReference;
+  Public
+    constructor Create(aParent : TBaseOpenAPIObject; const aPathComponent : TJSONStringType); reintroduce;
+    function AddItem(const aName : TJSONStringType) : TExampleOrReference;
+    property ExampleOrReferences[aName : TJSONStringType] : TExampleOrReference Read GetObject; default;
+  end;
+
+  { TLink }
+
+  TLink = Class(TExtendableObject)
+  Private
+    FKeywords : TLinkKeywords;
+    FOperationRef : string;
+    FOperationId : string;
+    FParameters : TJSONObject;
+    FRequestBody : TJSONData;
+    FDescription : string;
+    FServer : TServer;
+    Function Get_Parameters : TJSONObject;
+    Function Get_Server : TServer;
+    procedure Set_OperationRef(const aValue : string);
+    procedure Set_OperationId(const aValue : string);
+    procedure Set_Parameters(const aValue : TJSONObject);
+    procedure Set_RequestBody(const aValue : TJSONData);
+    procedure Set_Description(const aValue : string);
+    procedure Set_Server(const aValue : TServer);
+  Protected
+    procedure AddKeyword(aKeyword : TLinkKeyword); virtual;
+    procedure RemoveKeyword(aKeyword : TLinkKeyword); virtual;
+  public
+    destructor destroy; override;
+    function HasKeyWord(aKeyword :TLinkKeyword) : Boolean;
+    property OperationRef: string Read FOperationRef write Set_OperationRef;
+    property OperationId: string Read FOperationId write Set_OperationId;
+    property Parameters: TJSONObject Read Get_Parameters write Set_Parameters;
+    property RequestBody: TJSONData Read FRequestBody write Set_RequestBody;
+    property Description: string Read FDescription write Set_Description;
+    property Server: TServer Read Get_Server write Set_Server;
+  end;
+  TLinkArray = array of TLink;
+
+  TLinkOrReference = Class(TLink)
+  Private
+    FReference : TReference;
+    function GetReference : TReference;
+  Public
+    destructor Destroy; override;
+    function HasReference : Boolean;
+    property Reference : TReference Read GetReference;
+  end;
+
+  { TLinkOrReferenceMap }
+
+  TLinkOrReferenceMap = Class(TNamedOpenAPIObjectList)
+  Private
+    function GetObject(const aName : TJSONStringType) : TLinkOrReference;
+  Public
+    constructor Create(aParent : TBaseOpenAPIObject; const aPathComponent : TJSONStringType); reintroduce;
+    function AddItem(const aName : TJSONStringType) : TLinkOrReference;
+    property LinkOrReferences[aName : TJSONStringType] : TLinkOrReference Read GetObject; default;
+  end;
+
+  { TTag }
+
+  TTag = Class(TExtendableObject)
+  Private
+    FKeywords : TTagKeywords;
+    FName : string;
+    FDescription : string;
+    FExternalDocs : TExternalDocumentation;
+    Function Get_ExternalDocs : TExternalDocumentation;
+    procedure Set_Name(const aValue : string);
+    procedure Set_Description(const aValue : string);
+    procedure Set_ExternalDocs(const aValue : TExternalDocumentation);
+  Protected
+    procedure AddKeyword(aKeyword : TTagKeyword); virtual;
+    procedure RemoveKeyword(aKeyword : TTagKeyword); virtual;
+  public
+    destructor destroy; override;
+    function HasKeyWord(aKeyword :TTagKeyword) : Boolean;
+    property Name: string Read FName write Set_Name;
+    property Description: string Read FDescription write Set_Description;
+    property ExternalDocs: TExternalDocumentation Read Get_ExternalDocs write Set_ExternalDocs;
+  end;
+  TTagArray = array of TTag;
+
+
+  { TReference }
+
+  TReference = Class(TExtendableObject)
+  Private
+    FKeywords : TReferenceKeywords;
+    FRef : string;
+    FSummary : string;
+    FDescription : string;
+    procedure Set_Ref(const aValue : string);
+    procedure Set_Summary(const aValue : string);
+    procedure Set_Description(const aValue : string);
+  Protected
+    procedure AddKeyword(aKeyword : TReferenceKeyword); virtual;
+    procedure RemoveKeyword(aKeyword : TReferenceKeyword); virtual;
+  public
+    destructor destroy; override;
+    function HasKeyWord(aKeyword :TReferenceKeyword) : Boolean;
+    property Ref: string Read FRef write Set_Ref;
+    property Summary: string Read FSummary write Set_Summary;
+    property Description: string Read FDescription write Set_Description;
+  end;
+  TReferenceArray = array of TReference;
+
+  { TSchema }
+
+  TSchema = Class(TExtendableObject)
+  Private
+    FKeywords : TSchemaKeywords;
+    FDiscriminator : TDiscriminator;
+    FXML : TXML;
+    FExternalDocs : TExternalDocumentation;
+    FExample : TJSONData;
+    Function Get_Discriminator : TDiscriminator;
+    Function Get_XML : TXML;
+    Function Get_ExternalDocs : TExternalDocumentation;
+    procedure Set_Discriminator(const aValue : TDiscriminator);
+    procedure Set_XML(const aValue : TXML);
+    procedure Set_ExternalDocs(const aValue : TExternalDocumentation);
+    procedure Set_Example(const aValue : TJSONData);
+  Protected
+    procedure AddKeyword(aKeyword : TSchemaKeyword); virtual;
+    procedure RemoveKeyword(aKeyword : TSchemaKeyword); virtual;
+  public
+    destructor destroy; override;
+    function HasKeyWord(aKeyword :TSchemaKeyword) : Boolean;
+    property Discriminator: TDiscriminator Read Get_Discriminator write Set_Discriminator;
+    property XML: TXML Read Get_XML write Set_XML;
+    property ExternalDocs: TExternalDocumentation Read Get_ExternalDocs write Set_ExternalDocs;
+    property Example: TJSONData Read FExample write Set_Example;
+  end;
+  TSchemaArray = array of TSchema;
+
+  { TDiscriminator }
+
+  TDiscriminator = Class(TExtendableObject)
+  Private
+    FKeywords : TDiscriminatorKeywords;
+    FPropertyName : string;
+    FMapping : TStrings;
+    Function Get_Mapping : TStrings;
+    procedure Set_PropertyName(const aValue : string);
+    procedure Set_Mapping(const aValue : TStrings);
+  Protected
+    procedure AddKeyword(aKeyword : TDiscriminatorKeyword); virtual;
+    procedure RemoveKeyword(aKeyword : TDiscriminatorKeyword); virtual;
+  public
+    destructor destroy; override;
+    function HasKeyWord(aKeyword :TDiscriminatorKeyword) : Boolean;
+    property PropertyName: string Read FPropertyName write Set_PropertyName;
+    property Mapping: TStrings Read Get_Mapping write Set_Mapping;
+  end;
+  TDiscriminatorArray = array of TDiscriminator;
+
+  { TXML }
+
+  TXML = Class(TExtendableObject)
+  Private
+    FKeywords : TXMLKeywords;
+    FName : string;
+    FNamespace : string;
+    FPrefix : string;
+    FAttribute : Boolean;
+    FWrapped : Boolean;
+    procedure Set_Name(const aValue : string);
+    procedure Set_Namespace(const aValue : string);
+    procedure Set_Prefix(const aValue : string);
+    procedure Set_Attribute(const aValue : Boolean);
+    procedure Set_Wrapped(const aValue : Boolean);
+  Protected
+    procedure AddKeyword(aKeyword : TXMLKeyword); virtual;
+    procedure RemoveKeyword(aKeyword : TXMLKeyword); virtual;
+  public
+    destructor destroy; override;
+    function HasKeyWord(aKeyword :TXMLKeyword) : Boolean;
+    property Name: string Read FName write Set_Name;
+    property Namespace: string Read FNamespace write Set_Namespace;
+    property Prefix: string Read FPrefix write Set_Prefix;
+    property Attribute: Boolean Read FAttribute write Set_Attribute;
+    property Wrapped: Boolean Read FWrapped write Set_Wrapped;
+  end;
+  TXMLArray = array of TXML;
+
+  { TSecurityScheme }
+
+  TSecurityScheme = Class(TExtendableObject)
+  Private
+    FKeywords : TSecuritySchemeKeywords;
+    FType_ : string;
+    FDescription : string;
+    FName : string;
+    FIn_ : string;
+    FScheme : string;
+    FBearerFormat : string;
+    FFlows : TOAuthFlows;
+    FOpenIdConnectUrl : string;
+    Function Get_Flows : TOAuthFlows;
+    procedure Set_Type_(const aValue : string);
+    procedure Set_Description(const aValue : string);
+    procedure Set_Name(const aValue : string);
+    procedure Set_In_(const aValue : string);
+    procedure Set_Scheme(const aValue : string);
+    procedure Set_BearerFormat(const aValue : string);
+    procedure Set_Flows(const aValue : TOAuthFlows);
+    procedure Set_OpenIdConnectUrl(const aValue : string);
+  Protected
+    procedure AddKeyword(aKeyword : TSecuritySchemeKeyword); virtual;
+    procedure RemoveKeyword(aKeyword : TSecuritySchemeKeyword); virtual;
+  public
+    destructor destroy; override;
+    function HasKeyWord(aKeyword :TSecuritySchemeKeyword) : Boolean;
+    property Type_: string Read FType_ write Set_Type_;
+    property Description: string Read FDescription write Set_Description;
+    property Name: string Read FName write Set_Name;
+    property In_: string Read FIn_ write Set_In_;
+    property Scheme: string Read FScheme write Set_Scheme;
+    property BearerFormat: string Read FBearerFormat write Set_BearerFormat;
+    property Flows: TOAuthFlows Read Get_Flows write Set_Flows;
+    property OpenIdConnectUrl: string Read FOpenIdConnectUrl write Set_OpenIdConnectUrl;
+  end;
+  TSecuritySchemeArray = array of TSecurityScheme;
+
+  TSecuritySchemeOrReference = Class(TSecurityScheme)
+  Private
+    FReference : TReference;
+    function GetReference : TReference;
+  Public
+    destructor Destroy; override;
+    function HasReference : Boolean;
+    property Reference : TReference Read GetReference;
+  end;
+
+  { TSecuritySchemeOrReferenceMap }
+
+  TSecuritySchemeOrReferenceMap = Class(TNamedOpenAPIObjectList)
+  Private
+    function GetObject(const aName : TJSONStringType) : TSecuritySchemeOrReference;
+  Public
+    constructor Create(aParent : TBaseOpenAPIObject; const aPathComponent : TJSONStringType); reintroduce;
+    function AddItem(const aName : TJSONStringType) : TSecuritySchemeOrReference;
+    property SecuritySchemeOrReferences[aName : TJSONStringType] : TSecuritySchemeOrReference Read GetObject; default;
+  end;
+
+  { TOAuthFlows }
+
+  TOAuthFlows = Class(TExtendableObject)
+  Private
+    FKeywords : TOAuthFlowsKeywords;
+    FImplicit : TOAuthFlow;
+    FPassword : TOAuthFlow;
+    FClientCredentials : TOAuthFlow;
+    FClientAuthorizationCode : TOAuthFlow;
+    Function Get_Implicit : TOAuthFlow;
+    Function Get_Password : TOAuthFlow;
+    Function Get_ClientCredentials : TOAuthFlow;
+    Function Get_ClientAuthorizationCode : TOAuthFlow;
+    procedure Set_Implicit(const aValue : TOAuthFlow);
+    procedure Set_Password(const aValue : TOAuthFlow);
+    procedure Set_ClientCredentials(const aValue : TOAuthFlow);
+    procedure Set_ClientAuthorizationCode(const aValue : TOAuthFlow);
+  Protected
+    procedure AddKeyword(aKeyword : TOAuthFlowsKeyword); virtual;
+    procedure RemoveKeyword(aKeyword : TOAuthFlowsKeyword); virtual;
+  public
+    destructor destroy; override;
+    function HasKeyWord(aKeyword :TOAuthFlowsKeyword) : Boolean;
+    property Implicit: TOAuthFlow Read Get_Implicit write Set_Implicit;
+    property Password: TOAuthFlow Read Get_Password write Set_Password;
+    property ClientCredentials: TOAuthFlow Read Get_ClientCredentials write Set_ClientCredentials;
+    property ClientAuthorizationCode: TOAuthFlow Read Get_ClientAuthorizationCode write Set_ClientAuthorizationCode;
+  end;
+  TOAuthFlowsArray = array of TOAuthFlows;
+
+  { TOauthFlow }
+
+  TOauthFlow = Class(TExtendableObject)
+  Private
+    FKeywords : TOauthFlowKeywords;
+    FAuthorizationUrl : string;
+    FTokenURL : string;
+    FRefreshURL : string;
+    FScopes : TStrings;
+    Function Get_Scopes : TStrings;
+    procedure Set_AuthorizationUrl(const aValue : string);
+    procedure Set_TokenURL(const aValue : string);
+    procedure Set_RefreshURL(const aValue : string);
+    procedure Set_Scopes(const aValue : TStrings);
+  Protected
+    procedure AddKeyword(aKeyword : TOauthFlowKeyword); virtual;
+    procedure RemoveKeyword(aKeyword : TOauthFlowKeyword); virtual;
+  public
+    destructor destroy; override;
+    function HasKeyWord(aKeyword :TOauthFlowKeyword) : Boolean;
+    property AuthorizationUrl: string Read FAuthorizationUrl write Set_AuthorizationUrl;
+    property TokenURL: string Read FTokenURL write Set_TokenURL;
+    property RefreshURL: string Read FRefreshURL write Set_RefreshURL;
+    property Scopes: TStrings Read Get_Scopes write Set_Scopes;
+  end;
+  TOauthFlowArray = array of TOauthFlow;
+
+  { THeader }
+
+
+  THeaderOrReference = Class(THeader)
+  Private
+    FReference : TReference;
+    function GetReference : TReference;
+  Public
+    destructor Destroy; override;
+    function HasReference : Boolean;
+    property Reference : TReference Read GetReference;
+  end;
+
+  { THeaderOrReferenceMap }
+
+  THeaderOrReferenceMap = Class(TNamedOpenAPIObjectList)
+  Private
+    function GetObject(const aName : TJSONStringType) : THeaderOrReference;
+  Public
+    constructor Create(aParent : TBaseOpenAPIObject; const aPathComponent : TJSONStringType); reintroduce;
+    function AddItem(const aName : TJSONStringType) : THeaderOrReference;
+    property HeaderOrReferences[aName : TJSONStringType] : THeaderOrReference Read GetObject; default;
+  end;
+
+  { TCallback }
+
+  TCallback = Class(TPathItemOrReferenceMap);
+
+  TCallbackArray = array of TCallback;
+
+  TCallbackOrReference = Class(TCallback)
+  Private
+    FReference : TReference;
+    function GetReference : TReference;
+  Public
+    destructor Destroy; override;
+    function HasReference : Boolean;
+    property Reference : TReference Read GetReference;
+  end;
+
+  { TCallbackOrReferenceMap }
+
+  TCallbackOrReferenceMap = Class(TNamedOpenAPIObjectList)
+  Private
+    function GetObject(const aName : TJSONStringType) : TCallbackOrReference;
+  Public
+    constructor Create(aParent : TBaseOpenAPIObject; const aPathComponent : TJSONStringType); reintroduce;
+    function AddItem(const aName : TJSONStringType) : TCallbackOrReference;
+    property CallbackOrReferences[aName : TJSONStringType] : TCallbackOrReference Read GetObject; default;
+  end;
+
+  { TNamedStringList }
+
+  TNamedStringList = class(TNamedObjectList)
+  Public
+    Function CreateNew(const aName : TJSONStringType) : TObject; override;
+  end;
+
+  { TSecurityRequirement }
+
+  TSecurityRequirement = Class(TBaseOpenAPIObject)
+  Private
+    FList : TNamedStringList;
+    function GetCount: Integer;
+    function GetList(aIndex : Integer): TStrings;
+    function GetName(aIndex : Integer): String;
+    function GetRequirements(aName : TJSONStringType): TStrings;
+  public
+    constructor Create (aParent : TBaseOpenAPIObject; const aPathComponent : TJSONStringType); reintroduce;
+    destructor destroy; override;
+    Function AddItem(const AName : TJSONStringType) : TStrings;
+    property Requirements[aName : TJSONStringType] : TStrings Read GetRequirements;
+    property Names[aIndex : Integer] : String Read GetName;
+    property Lists[aIndex : Integer] : TStrings Read GetList;
+    Property Count : Integer Read GetCount;
+  end;
+  TSecurityRequirementArray = array of TSecurityRequirement;
+
+  { TSecurityRequirementList }
+
+  TSecurityRequirementList = class(TFPObjectList)
+  Private
+    function GetObj(aIndex : Integer): TSecurityRequirement;
+    procedure SetObj(aIndex : Integer; aValue : TSecurityRequirement);
+  Public
+    function ToArray : TSecurityRequirementArray;
+    Procedure AddSecurity(aSecurity : TSecurityRequirement);
+    function AddSecurity(aParent : TBaseOpenAPIObject) : TSecurityRequirement;
+    property SecurityRequirements[aIndex : integer] : TSecurityRequirement Read GetObj Write SetObj; default;
+  end;
+
+
+function EncodeJSONPointer(S : TJSONStringType) : TJSONStringType;
+function DecodeJSONPointer(S : TJSONStringType) : TJSONStringType;
+
+implementation
+
+function EncodeJSONPointer(S : TJSONStringType) : TJSONStringType;
+
+Const ZeroOne : Array[Boolean] of char = ('0','1');
+
+var
+  I,Count : Integer;
+  C : TJSONCharType;
+
+begin
+  Count:=0;
+  For I:=1 to Length(S) do
+    if S[i] in ['~','/'] then
+      Inc(Count);
+  if Count=0 then
+    Exit(S);
+  SetLength(Result,Length(S)+Count);
+  Count:=1;
+  For I:=1 to Length(S) do
+    begin
+    C:=S[I];
+    if Not (C in ['~','/']) then
+      Result[Count]:=C
+    else
+      begin
+      Result[Count]:='~';
+      Inc(Count);
+      Result[Count]:=ZeroOne[C='/'];
+      end;
+    inc(Count);
+    end;
+end;
+
+function DecodeJSONPointer(S : TJSONStringType) : TJSONStringType;
+
+begin
+  Result:=StringReplace(S,'~1','/',[rfReplaceAll]);
+  Result:=StringReplace(Result,'~0','~',[rfReplaceAll]);
+end;
+
+{ TExtendableObject }
+
+function TExtendableObject.GetExtensions: TJSONObject;
+begin
+  if FExtensions=Nil then
+    FExtensions:=TJSONObject.Create;
+  Result:=FExtensions;
+end;
+
+procedure TExtendableObject.SetExtensions(AValue: TJSONObject);
+begin
+  If (FExtensions=aValue) then exit;
+  FreeAndNil(FExtensions);
+  FExtensions:=aValue;
+end;
+
+function TExtendableObject.CreateExtensions: TJSONObject;
+begin
+  Result:=TJSONObject.Create;
+end;
+
+function TExtendableObject.HasExtensions: Boolean;
+begin
+  Result:=Assigned(FExtensions) and (FExtensions.Count>0);
+end;
+
+{ TNamedObject }
+
+constructor TNamedObject.Create(aName: TJSONStringType; aObject: TObject);
+begin
+  FName:=aName;
+  FObject:=aObject;
+end;
+
+destructor TNamedObject.Destroy;
+begin
+  FreeAndNil(FObject);
+  inherited Destroy;
+end;
+
+
+{ TNamedOpenAPIObjectList }
+
+function TNamedObjectList.GetName(aIndex : Integer): TJSONStringType;
+begin
+  Result:=NamedObjects[aIndex].Name;
+end;
+
+function TNamedObjectList.GetCount: Integer;
+begin
+  Result:=FList.Count;
+end;
+
+function TNamedObjectList.GetNamedObject(aIndex: Integer): TNamedObject;
+begin
+  Result:=TNamedObject(FList[aIndex]);
+end;
+
+
+procedure TNamedObjectList.SetName(aIndex : Integer; AValue: TJSONStringType);
+begin
+  NamedObjects[aIndex].FName:=aValue;
+end;
+
+procedure TNamedObjectList.SetNamedObject(aIndex: Integer; AValue: TNamedObject);
+begin
+  FList[aIndex]:=aValue;
+end;
+
+
+function TNamedObjectList.GetObjectByName(const aName: String): TObject;
+
+var
+  Obj : TNamedObject;
+begin
+  Result:=Nil;
+  Obj:=TNamedObject(FHash.Items[aName]);
+  If Assigned(Obj) then
+    Result:=Obj.Object_;
+end;
+
+procedure TNamedObjectList.Add(const AName: TJSONStringType; aObject: TObject);
+
+var
+  Itm : TNamedObject;
+
+begin
+  if not aObject.InheritsFrom(FType) then
+    Raise EListError.CreateFmt('%s is not of type %s',[aObject.ClassName,FType.ClassName]);
+  Itm:=TNamedObject.Create(aName,aObject);
+  FList.Add(Itm);
+  FHash.Add(aName,Itm);
+end;
+
+
+constructor TNamedObjectList.Create(aParent: TBaseOpenAPIObject; const aPathComponent : TJSONStringType; aType: TClass);
+begin
+  Inherited Create(aParent,aPathComponent);
+  FType:=aType;
+  FList:=TFPObjectList.Create;
+  FHash:=TFPObjectHashTable.Create(False);
+end;
+
+function TNamedOpenAPIObjectList.GetApiObject(aIndex : Integer): TBaseOpenAPIObject;
+begin
+  Result:=NamedObjects[aIndex].Object_ as TBaseOpenAPIObject;
+end;
+
+constructor TNamedOpenAPIObjectList.Create(aParent: TBaseOpenAPIObject; const aPathComponent : TJSONStringType; aType: TClass);
+begin
+  if not aType.InheritsFrom(TBaseOpenAPIObject) then
+    Raise EOpenAPi.CreateFmt('Class %s does not inherit from TOpenAPIObject',[aType.ClassName]);
+  Inherited Create(aParent,aPathComponent,aType);
+end;
+
+function TNamedOpenAPIObjectList.CreateNew(const AName: TJSONStringType): TObject;
+begin
+  Result:=TOpenAPIObjectClass(FType).create(Self,aName);
+  Add(aName,Result);
+end;
+
+{ TJSONSchemaMap }
+
+function TJSONSchemaMap.GetNamedSchema(aName: TJSONStringType): TJSONSchema;
+begin
+  Result:=TJSONSchema(GetObjectByName(aName));
+end;
+
+function TJSONSchemaMap.CreateNew(const AName: TJSONStringType): TObject;
+begin
+  if aName<>'' then ;
+  Result:=TJSONSchema.Create;
+end;
+
+function TJSONSchemaMap.Add(const AName: TJSONStringType): TJSONSchema;
+begin
+  Result:=TJSONSchema(CreateNew(aName));
+  Inherited Add(aName,Result);
+end;
+
+destructor TNamedObjectList.Destroy;
+begin
+  FreeAndNil(FList);
+  FreeAndNil(FHash);
+  inherited Destroy;
+end;
+
+procedure TNamedObjectList.Delete(aName: TJSONStringType);
+
+var
+  Idx : Integer;
+begin
+  Idx:=IndexOfName(aName);
+  if Idx<>-1 then
+    Delete(Idx);
+end;
+
+procedure TNamedObjectList.Delete(aIndex: Integer);
+begin
+  FList.Delete(aIndex);
+end;
+
+function TNamedObjectList.IndexOfName(aName: TJSONStringType): Integer;
+begin
+  Result:=Count;
+  While (Result>=0) and Not SameText(Names[Result],aName) do
+    Dec(Result);
+end;
+
+{ TPathsList }
+
+function TPathsList.GetObject(const aName: TJSONStringType): TPathItem;
+begin
+  Result:=TPathItem(GetObjectByName(aName));
+end;
+
+function TPathsList.GetObjectByIndex(aIndex : Integer): TPathItem;
+begin
+  Result:=TPathItem(NamedObjects[aIndex].Object_);
+end;
+
+constructor TPathsList.Create(aParent: TBaseOpenAPIObject;
+  const aPathComponent: TJSONStringType);
+begin
+  Inherited Create(aParent,aPathComponent,TPathItem);
+end;
+
+function TPathsList.AddItem(const aName: TJSONStringType): TPathItem;
+begin
+  Result:=CreateNew(aName) as TPathItem;
+  //  Add(aName,Result);
+end;
+
+{ TTagList }
+
+function TTagList.GetTag(aIndex : Integer): TTag;
+begin
+  Result:=Items[aIndex] as TTag;
+end;
+
+procedure TTagList.AddTag(aTag: TTag);
+begin
+  Inherited Add(aTag);
+end;
+
+{ TParameterOrReferenceList }
+
+function TParameterOrReferenceList.GetParam(aIndex : Integer
+  ): TParameterOrReference;
+begin
+  Result:=TParameterOrReference(Items[aIndex]);
+end;
+
+function TParameterOrReferenceList.AddParam(aParent: TBaseOpenAPIObject): TParameterOrReference;
+begin
+  Result:=TParameterOrReference.Create(aParent,Format('[%d]',[Count]));
+  Add(Result);
+end;
+
+
+function TOpenAPI.Get_Info : TInfo;
+
+begin
+  if Not assigned(FInfo) then
+    begin
+    FInfo:=TInfo.Create(self,'info');
+    AddKeyWord(oakInfo);
+    end;
+  Result:=FInfo;
+end;
+
+
+function TOpenAPI.Get_Servers : TServerList;
+
+begin
+  if Not assigned(FServers) then
+    begin
+    FServers:=TServerList.Create;
+    AddKeyWord(oakServers);
+    end;
+  Result:=FServers;
+end;
+
+
+function TOpenAPI.Get_Paths : TPathsList;
+
+begin
+  if Not assigned(FPaths) then
+    begin
+    FPaths:=TPathsList.Create(Self,'paths');
+    AddKeyWord(oakPaths);
+    end;
+  Result:=FPaths;
+end;
+
+
+function TOpenAPI.Get_WebHooks : TPathItemOrReferenceMap;
+
+begin
+  if Not assigned(FWebHooks) then
+    begin
+    FWebHooks:=TPathItemOrReferenceMap.Create(Self,'webhooks');
+    AddKeyWord(oakWebHooks);
+    end;
+  Result:=FWebHooks;
+end;
+
+
+function TOpenAPI.Get_Components : TComponents;
+
+begin
+  if Not assigned(FComponents) then
+    begin
+    FComponents:=TComponents.Create(Self,'components');
+    AddKeyWord(oakComponents);
+    end;
+  Result:=FComponents;
+end;
+
+
+function TOpenAPI.Get_Security : TSecurityRequirementList;
+
+begin
+  if Not assigned(FSecurity) then
+    begin
+    FSecurity:=TSecurityRequirementList.Create; // (Self,'security');
+    AddKeyWord(oakSecurity);
+    end;
+  Result:=FSecurity;
+end;
+
+
+function TOpenAPI.Get_Tags : TTagList;
+
+begin
+  if Not assigned(FTags) then
+    begin
+    FTags:=TTagList.Create;
+    AddKeyWord(oakTags);
+    end;
+  Result:=FTags;
+end;
+
+
+function TOpenAPI.Get_ExternalDocs : TExternalDocumentation;
+
+begin
+  if Not assigned(FExternalDocs) then
+    begin
+    FExternalDocs:=TExternalDocumentation.Create(Self,'externalDocs');
+    AddKeyWord(oakExternalDocs);
+    end;
+  Result:=FExternalDocs;
+end;
+
+
+procedure TOpenAPI.Set_OpenApi(const aValue : string);
+
+begin
+  if (FOpenApi=aValue) then exit;
+  FOpenApi:=aValue;
+  AddKeyWord(oakOpenApi);
+end;
+
+
+procedure TOpenAPI.Set_Info(const aValue : TInfo);
+
+begin
+  if (FInfo=aValue) then exit;
+  FreeAndNil(FInfo);
+  FInfo:=aValue;
+  AddKeyWord(oakInfo);
+end;
+
+
+procedure TOpenAPI.Set_JSONSchemaDialect(const aValue : string);
+
+begin
+  if (FJSONSchemaDialect=aValue) then exit;
+  FJSONSchemaDialect:=aValue;
+  AddKeyWord(oakJSONSchemaDialect);
+end;
+
+
+procedure TOpenAPI.Set_Servers(const aValue : TServerList);
+
+begin
+  if (FServers=aValue) then exit;
+  FreeAndNil(FServers);
+  FServers:=aValue;
+  AddKeyWord(oakServers);
+end;
+
+
+procedure TOpenAPI.Set_Paths(const aValue : TPathsList);
+
+begin
+  if (FPaths=aValue) then exit;
+  FreeAndNil(FPaths);
+  FPaths:=aValue;
+  AddKeyWord(oakPaths);
+end;
+
+
+procedure TOpenAPI.Set_WebHooks(const aValue : TPathItemOrReferenceMap);
+
+begin
+  if (FWebHooks=aValue) then exit;
+  FreeAndNil(FWebHooks);
+  FWebHooks:=aValue;
+  AddKeyWord(oakWebHooks);
+end;
+
+
+procedure TOpenAPI.Set_Components(const aValue : TComponents);
+
+begin
+  if (FComponents=aValue) then exit;
+  FreeAndNil(FComponents);
+  FComponents:=aValue;
+  AddKeyWord(oakComponents);
+end;
+
+
+procedure TOpenAPI.Set_Security(const aValue : TSecurityRequirementList);
+
+begin
+  if (FSecurity=aValue) then exit;
+  FreeAndNil(FSecurity);
+  FSecurity:=aValue;
+  AddKeyWord(oakSecurity);
+end;
+
+
+procedure TOpenAPI.Set_Tags(const aValue : TTagList);
+
+begin
+  if (FTags=aValue) then exit;
+  FreeAndNil(FTags);
+  FTags:=aValue;
+  AddKeyWord(oakTags);
+end;
+
+
+procedure TOpenAPI.Set_ExternalDocs(const aValue : TExternalDocumentation);
+
+begin
+  if (FExternalDocs=aValue) then exit;
+  FreeAndNil(FExternalDocs);
+  FExternalDocs:=aValue;
+  AddKeyWord(oakExternalDocs);
+end;
+
+
+procedure TOpenAPI.AddKeyword(aKeyword : TOpenAPIKeyword);
+
+begin
+  Include(FKeywords,aKeyword);
+end;
+
+
+procedure TOpenAPI.RemoveKeyword(aKeyword : TOpenAPIKeyword);
+
+begin
+  Exclude(FKeywords,aKeyword);
+end;
+
+
+function TOpenAPI.HasKeyWord(aKeyword: TOpenAPIKeyword): Boolean;
+
+begin
+  Result:=aKeyword in FKeywords;
+end;
+
+
+destructor TOpenAPI.destroy;
+
+begin
+  FreeAndNil(FInfo);
+  FreeAndNil(FServers);
+  FreeAndNil(FPaths);
+  FreeAndNil(FWebHooks);
+  FreeAndNil(FComponents);
+  FreeAndNil(FSecurity);
+  FreeAndNil(FTags);
+  FreeAndNil(FExternalDocs);
+  Inherited;
+end;
+
+constructor TOpenAPI.Create;
+begin
+  Inherited Create(Nil,'');
+end;
+
+
+
+function TInfo.Get_Contact : TContact;
+
+begin
+  if Not assigned(FContact) then
+    begin
+    FContact:=TContact.Create(Self,'contact');
+    AddKeyWord(ikContact);
+    end;
+  Result:=FContact;
+end;
+
+
+function TInfo.Get_License : TLicense;
+
+begin
+  if Not assigned(FLicense) then
+    begin
+    FLicense:=TLicense.Create(Self,'license');
+    AddKeyWord(ikLicense);
+    end;
+  Result:=FLicense;
+end;
+
+
+procedure TInfo.Set_Title(const aValue : string);
+
+begin
+  if (FTitle=aValue) then exit;
+  FTitle:=aValue;
+  AddKeyWord(ikTitle);
+end;
+
+
+procedure TInfo.Set_Summary(const aValue : string);
+
+begin
+  if (FSummary=aValue) then exit;
+  FSummary:=aValue;
+  AddKeyWord(ikSummary);
+end;
+
+
+procedure TInfo.Set_Description(const aValue : string);
+
+begin
+  if (FDescription=aValue) then exit;
+  FDescription:=aValue;
+  AddKeyWord(ikDescription);
+end;
+
+
+procedure TInfo.Set_TermsOfService(const aValue : string);
+
+begin
+  if (FTermsOfService=aValue) then exit;
+  FTermsOfService:=aValue;
+  AddKeyWord(ikTermsOfService);
+end;
+
+
+procedure TInfo.Set_Contact(const aValue : TContact);
+
+begin
+  if (FContact=aValue) then exit;
+  FreeAndNil(FContact);
+  FContact:=aValue;
+  AddKeyWord(ikContact);
+end;
+
+
+procedure TInfo.Set_License(const aValue : TLicense);
+
+begin
+  if (FLicense=aValue) then exit;
+  FreeAndNil(FLicense);
+  FLicense:=aValue;
+  AddKeyWord(ikLicense);
+end;
+
+
+procedure TInfo.Set_Version(const aValue : string);
+
+begin
+  if (FVersion=aValue) then exit;
+  FVersion:=aValue;
+  AddKeyWord(ikVersion);
+end;
+
+
+procedure TInfo.AddKeyword(aKeyword : TInfoKeyword);
+
+begin
+  Include(FKeywords,aKeyword);
+end;
+
+
+procedure TInfo.RemoveKeyword(aKeyword : TInfoKeyword);
+
+begin
+  Exclude(FKeywords,aKeyword);
+end;
+
+
+Function TInfo.HasKeyword(aKeyword : TInfoKeyword) : Boolean;
+
+begin
+  Result:=aKeyword in FKeywords;
+end;
+
+
+destructor TInfo.destroy;
+
+begin
+  FreeAndNil(FContact);
+  FreeAndNil(FLicense);
+  Inherited;
+end;
+
+
+
+
+procedure TContact.Set_Name(const aValue : string);
+
+begin
+  if (FName=aValue) then exit;
+  FName:=aValue;
+  AddKeyWord(cokName);
+end;
+
+
+procedure TContact.Set_Url(const aValue : string);
+
+begin
+  if (FUrl=aValue) then exit;
+  FUrl:=aValue;
+  AddKeyWord(cokUrl);
+end;
+
+
+procedure TContact.Set_Email(const aValue : string);
+
+begin
+  if (FEmail=aValue) then exit;
+  FEmail:=aValue;
+  AddKeyWord(cokEmail);
+end;
+
+
+procedure TContact.AddKeyword(aKeyword : TContactKeyword);
+
+begin
+  Include(FKeywords,aKeyword);
+end;
+
+
+procedure TContact.RemoveKeyword(aKeyword : TContactKeyword);
+
+begin
+  Exclude(FKeywords,aKeyword);
+end;
+
+
+Function TContact.HasKeyword(aKeyword : TContactKeyword) : Boolean;
+
+begin
+  Result:=aKeyword in FKeywords;
+end;
+
+
+destructor TContact.destroy;
+
+begin
+  Inherited;
+end;
+
+
+procedure TLicense.Set_Name(const aValue : string);
+
+begin
+  if (FName=aValue) then exit;
+  FName:=aValue;
+  AddKeyWord(lkName);
+end;
+
+
+procedure TLicense.Set_Identifier(const aValue : string);
+
+begin
+  if (FIdentifier=aValue) then exit;
+  FIdentifier:=aValue;
+  AddKeyWord(lkIdentifier);
+end;
+
+
+procedure TLicense.Set_Url(const aValue : string);
+
+begin
+  if (FUrl=aValue) then exit;
+  FUrl:=aValue;
+  AddKeyWord(lkUrl);
+end;
+
+
+procedure TLicense.AddKeyword(aKeyword : TLicenseKeyword);
+
+begin
+  Include(FKeywords,aKeyword);
+end;
+
+
+procedure TLicense.RemoveKeyword(aKeyword : TLicenseKeyword);
+
+begin
+  Exclude(FKeywords,aKeyword);
+end;
+
+
+Function TLicense.HasKeyword(aKeyword : TLicenseKeyword) : Boolean;
+
+begin
+  Result:=aKeyword in FKeywords;
+end;
+
+
+destructor TLicense.destroy;
+
+begin
+  Inherited;
+end;
+
+
+function TServer.Get_Variables : TServerVariableMap;
+
+begin
+  if Not assigned(FVariables) then
+    begin
+    FVariables:=TServerVariableMap.Create(Self,'variables');
+    AddKeyWord(skVariables);
+    end;
+  Result:=FVariables;
+end;
+
+
+procedure TServer.Set_ServerUrl(const aValue : string);
+
+begin
+  if (FServerUrl=aValue) then exit;
+  FServerUrl:=aValue;
+  AddKeyWord(skServerUrl);
+end;
+
+
+procedure TServer.Set_Description(const aValue : string);
+
+begin
+  if (FDescription=aValue) then exit;
+  FDescription:=aValue;
+  AddKeyWord(skDescription);
+end;
+
+
+procedure TServer.Set_Variables(const aValue : TServerVariableMap);
+
+begin
+  if (FVariables=aValue) then exit;
+  FreeAndNil(FVariables);
+  FVariables:=aValue;
+  AddKeyWord(skVariables);
+end;
+
+
+procedure TServer.AddKeyword(aKeyword : TServerKeyword);
+
+begin
+  Include(FKeywords,aKeyword);
+end;
+
+
+procedure TServer.RemoveKeyword(aKeyword : TServerKeyword);
+
+begin
+  Exclude(FKeywords,aKeyword);
+end;
+
+
+Function TServer.HasKeyword(aKeyword : TServerKeyword) : Boolean;
+
+begin
+  Result:=aKeyword in FKeywords;
+end;
+
+
+destructor TServer.destroy;
+
+begin
+  FreeAndNil(FVariables);
+  Inherited;
+end;
+
+
+function TServerList.GetObj(aIndex : Integer): TServer;
+
+begin
+  Result:=TServer(Items[aIndex]);
+end;
+
+
+procedure TServerList.SetObj(aIndex : Integer; aValue : TServer);
+
+begin
+  Items[aIndex]:=aValue;
+end;
+
+
+function TServerList.ToArray : TServerArray;
+
+var
+  I : Integer;
+
+begin
+  Result:=[];
+  SetLength(Result,Count);
+  For I:=0 to Count-1 do
+    Result[I]:=GetObj(I);
+end;
+
+
+function TServerVariable.Get_Enum : TStrings;
+
+begin
+  if Not assigned(FEnum) then
+    begin
+    FEnum:=TStringList.Create;
+    AddKeyWord(svkEnum);
+    end;
+  Result:=FEnum;
+end;
+
+
+procedure TServerVariable.Set_Enum(const aValue : TStrings);
+
+begin
+  if (FEnum=aValue) then exit;
+  FreeAndNil(FEnum);
+  FEnum:=aValue;
+  AddKeyWord(svkEnum);
+end;
+
+
+procedure TServerVariable.Set_Default(const aValue : string);
+
+begin
+  if (FDefault=aValue) then exit;
+  FDefault:=aValue;
+  AddKeyWord(svkDefault);
+end;
+
+
+procedure TServerVariable.Set_Description(const aValue : string);
+
+begin
+  if (FDescription=aValue) then exit;
+  FDescription:=aValue;
+  AddKeyWord(svkDescription);
+end;
+
+
+procedure TServerVariable.AddKeyword(aKeyword : TServerVariableKeyword);
+
+begin
+  Include(FKeywords,aKeyword);
+end;
+
+
+procedure TServerVariable.RemoveKeyword(aKeyword : TServerVariableKeyword);
+
+begin
+  Exclude(FKeywords,aKeyword);
+end;
+
+
+Function TServerVariable.HasKeyword(aKeyword : TServerVariableKeyword) : Boolean;
+
+begin
+  Result:=aKeyword in FKeywords;
+end;
+
+
+destructor TServerVariable.destroy;
+
+begin
+  FreeAndNil(FEnum);
+  Inherited;
+end;
+
+
+
+function TServerVariableMap.GetObject(const aName : TJSONStringType) : TServerVariable;
+
+begin
+  Result:=TServerVariable(GetObjectByName(aName));
+end;
+
+
+constructor TServerVariableMap.Create(aParent: TBaseOpenAPIObject; const aPathComponent: TJSONStringType);
+
+begin
+  Inherited Create(aParent,aPathComponent,TServerVariable);
+end;
+
+
+function TServerVariableMap.AddItem(const aName : TJSONStringType) : TServerVariable;
+
+begin
+  Result:=CreateNew(aName) as TServerVariable;
+//  Add(aName,Result);
+end;
+
+
+function TComponents.Get_Schemas : TJSONSchemaMap;
+
+begin
+  if Not assigned(FSchemas) then
+    begin
+    FSchemas:=TJSONSchemaMap.Create(Self,'schemas',TJSONSchema);
+    AddKeyWord(ckSchemas);
+    end;
+  Result:=FSchemas;
+end;
+
+
+function TComponents.Get_Responses : TResponseOrReferenceMap;
+
+begin
+  if Not assigned(FResponses) then
+    begin
+    FResponses:=TResponseOrReferenceMap.Create(Self,'responses');
+    AddKeyWord(ckResponses);
+    end;
+  Result:=FResponses;
+end;
+
+
+function TComponents.Get_Parameters : TParameterOrReferenceMap;
+
+begin
+  if Not assigned(FParameters) then
+    begin
+    FParameters:=TParameterOrReferenceMap.Create(Self,'parameters');
+    AddKeyWord(ckParameters);
+    end;
+  Result:=FParameters;
+end;
+
+
+function TComponents.Get_Examples : TExampleOrReferenceMap;
+
+begin
+  if Not assigned(FExamples) then
+    begin
+    FExamples:=TExampleOrReferenceMap.Create(Self,'examples');
+    AddKeyWord(ckExamples);
+    end;
+  Result:=FExamples;
+end;
+
+
+function TComponents.Get_RequestBodies : TRequestBodyOrReferenceMap;
+
+begin
+  if Not assigned(FRequestBodies) then
+    begin
+    FRequestBodies:=TRequestBodyOrReferenceMap.Create(Self,'requestBodies');
+    AddKeyWord(ckRequestBodies);
+    end;
+  Result:=FRequestBodies;
+end;
+
+
+function TComponents.Get_Headers : THeaderOrReferenceMap;
+
+begin
+  if Not assigned(FHeaders) then
+    begin
+    FHeaders:=THeaderOrReferenceMap.Create(Self,'headers');
+    AddKeyWord(ckHeaders);
+    end;
+  Result:=FHeaders;
+end;
+
+
+function TComponents.Get_SecuritySchemes : TSecuritySchemeOrReferenceMap;
+
+begin
+  if Not assigned(FSecuritySchemes) then
+    begin
+    FSecuritySchemes:=TSecuritySchemeOrReferenceMap.Create(Self,'securitySchemes');
+    AddKeyWord(ckSecuritySchemes);
+    end;
+  Result:=FSecuritySchemes;
+end;
+
+
+function TComponents.Get_Links : TLinkOrReferenceMap;
+
+begin
+  if Not assigned(FLinks) then
+    begin
+    FLinks:=TLinkOrReferenceMap.Create(Self,'links');
+    AddKeyWord(ckLinks);
+    end;
+  Result:=FLinks;
+end;
+
+
+function TComponents.Get_Callbacks : TLinkOrReferenceMap;
+
+begin
+  if Not assigned(FCallbacks) then
+    begin
+    FCallbacks:=TLinkOrReferenceMap.Create(Self,'callbacks');
+    AddKeyWord(ckCallbacks);
+    end;
+  Result:=FCallbacks;
+end;
+
+
+function TComponents.Get_PathItems : TPathItemOrReferenceMap;
+
+begin
+  if Not assigned(FPathItems) then
+    begin
+    FPathItems:=TPathItemOrReferenceMap.Create(Self,'pathitems');
+    AddKeyWord(ckPathItems);
+    end;
+  Result:=FPathItems;
+end;
+
+
+procedure TComponents.Set_Schemas(const aValue : TJSONSchemaMap);
+
+begin
+  if (FSchemas=aValue) then exit;
+  FreeAndNil(FSchemas);
+  FSchemas:=aValue;
+  AddKeyWord(ckSchemas);
+end;
+
+
+procedure TComponents.Set_Responses(const aValue : TResponseOrReferenceMap);
+
+begin
+  if (FResponses=aValue) then exit;
+  FreeAndNil(FResponses);
+  FResponses:=aValue;
+  AddKeyWord(ckResponses);
+end;
+
+
+procedure TComponents.Set_Parameters(const aValue : TParameterOrReferenceMap);
+
+begin
+  if (FParameters=aValue) then exit;
+  FreeAndNil(FParameters);
+  FParameters:=aValue;
+  AddKeyWord(ckParameters);
+end;
+
+
+procedure TComponents.Set_Examples(const aValue : TExampleOrReferenceMap);
+
+begin
+  if (FExamples=aValue) then exit;
+  FreeAndNil(FExamples);
+  FExamples:=aValue;
+  AddKeyWord(ckExamples);
+end;
+
+
+procedure TComponents.Set_RequestBodies(const aValue : TRequestBodyOrReferenceMap);
+
+begin
+  if (FRequestBodies=aValue) then exit;
+  FreeAndNil(FRequestBodies);
+  FRequestBodies:=aValue;
+  AddKeyWord(ckRequestBodies);
+end;
+
+
+procedure TComponents.Set_Headers(const aValue : THeaderOrReferenceMap);
+
+begin
+  if (FHeaders=aValue) then exit;
+  FreeAndNil(FHeaders);
+  FHeaders:=aValue;
+  AddKeyWord(ckHeaders);
+end;
+
+
+procedure TComponents.Set_SecuritySchemes(const aValue : TSecuritySchemeOrReferenceMap);
+
+begin
+  if (FSecuritySchemes=aValue) then exit;
+  FreeAndNil(FSecuritySchemes);
+  FSecuritySchemes:=aValue;
+  AddKeyWord(ckSecuritySchemes);
+end;
+
+
+procedure TComponents.Set_Links(const aValue : TLinkOrReferenceMap);
+
+begin
+  if (FLinks=aValue) then exit;
+  FreeAndNil(FLinks);
+  FLinks:=aValue;
+  AddKeyWord(ckLinks);
+end;
+
+
+procedure TComponents.Set_Callbacks(const aValue : TLinkOrReferenceMap);
+
+begin
+  if (FCallbacks=aValue) then exit;
+  FreeAndNil(FCallbacks);
+  FCallbacks:=aValue;
+  AddKeyWord(ckCallbacks);
+end;
+
+
+procedure TComponents.Set_PathItems(const aValue : TPathItemOrReferenceMap);
+
+begin
+  if (FPathItems=aValue) then exit;
+  FreeAndNil(FPathItems);
+  FPathItems:=aValue;
+  AddKeyWord(ckPathItems);
+end;
+
+
+procedure TComponents.AddKeyword(aKeyword : TComponentsKeyword);
+
+begin
+  Include(FKeywords,aKeyword);
+end;
+
+
+procedure TComponents.RemoveKeyword(aKeyword : TComponentsKeyword);
+
+begin
+  Exclude(FKeywords,aKeyword);
+end;
+
+
+Function TComponents.HasKeyword(aKeyword : TComponentsKeyword) : Boolean;
+
+begin
+  Result:=aKeyword in FKeywords;
+end;
+
+
+destructor TComponents.destroy;
+
+begin
+  FreeAndNil(FSchemas);
+  FreeAndNil(FResponses);
+  FreeAndNil(FParameters);
+  FreeAndNil(FExamples);
+  FreeAndNil(FRequestBodies);
+  FreeAndNil(FHeaders);
+  FreeAndNil(FSecuritySchemes);
+  FreeAndNil(FLinks);
+  FreeAndNil(FCallbacks);
+  FreeAndNil(FPathItems);
+  Inherited;
+end;
+
+
+
+function TPathItem.Get_Get : TApiOperation;
+
+begin
+  if Not assigned(FGet) then
+    begin
+    FGet:=TApiOperation.Create(Self,'get');
+    AddKeyWord(pkGet);
+    end;
+  Result:=FGet;
+end;
+
+
+function TPathItem.Get_Put : TApiOperation;
+
+begin
+  if Not assigned(FPut) then
+    begin
+    FPut:=TApiOperation.Create(Self,'put');
+    AddKeyWord(pkPut);
+    end;
+  Result:=FPut;
+end;
+
+
+function TPathItem.Get_Post : TApiOperation;
+
+begin
+  if Not assigned(FPost) then
+    begin
+    FPost:=TApiOperation.Create(Self,'post');
+    AddKeyWord(pkPost);
+    end;
+  Result:=FPost;
+end;
+
+
+function TPathItem.Get_Delete : TApiOperation;
+
+begin
+  if Not assigned(FDelete) then
+    begin
+    FDelete:=TApiOperation.Create(Self,'delete');
+    AddKeyWord(pkDelete);
+    end;
+  Result:=FDelete;
+end;
+
+
+function TPathItem.Get_Options : TApiOperation;
+
+begin
+  if Not assigned(FOptions) then
+    begin
+    FOptions:=TApiOperation.Create(Self,'options');
+    AddKeyWord(pkOptions);
+    end;
+  Result:=FOptions;
+end;
+
+
+function TPathItem.Get_Head : TApiOperation;
+
+begin
+  if Not assigned(FHead) then
+    begin
+    FHead:=TApiOperation.Create(Self,'head');
+    AddKeyWord(pkHead);
+    end;
+  Result:=FHead;
+end;
+
+
+function TPathItem.Get_Patch : TApiOperation;
+
+begin
+  if Not assigned(FPatch) then
+    begin
+    FPatch:=TApiOperation.Create(Self,'patch');
+    AddKeyWord(pkPatch);
+    end;
+  Result:=FPatch;
+end;
+
+
+function TPathItem.Get_Trace : TApiOperation;
+
+begin
+  if Not assigned(FTrace) then
+    begin
+    FTrace:=TApiOperation.Create(Self,'trace');
+    AddKeyWord(pkTrace);
+    end;
+  Result:=FTrace;
+end;
+
+
+function TPathItem.Get_Servers : TServerList;
+
+begin
+  if Not assigned(FServers) then
+    begin
+    FServers:=TServerList.Create;
+    AddKeyWord(pkServers);
+    end;
+  Result:=FServers;
+end;
+
+
+function TPathItem.Get_Parameters : TParameterOrReferenceList;
+
+begin
+  if Not assigned(FParameters) then
+    begin
+    FParameters:=TParameterOrReferenceList.Create;
+    AddKeyWord(pkParameters);
+    end;
+  Result:=FParameters;
+end;
+
+
+procedure TPathItem.Set_Ref(const aValue : string);
+
+begin
+  if (FRef=aValue) then exit;
+  FRef:=aValue;
+  AddKeyWord(pkRef);
+end;
+
+
+procedure TPathItem.Set_Summary(const aValue : string);
+
+begin
+  if (FSummary=aValue) then exit;
+  FSummary:=aValue;
+  AddKeyWord(pkSummary);
+end;
+
+
+procedure TPathItem.Set_Description(const aValue : string);
+
+begin
+  if (FDescription=aValue) then exit;
+  FDescription:=aValue;
+  AddKeyWord(pkDescription);
+end;
+
+
+procedure TPathItem.Set_Get(const aValue : TApiOperation);
+
+begin
+  if (FGet=aValue) then exit;
+  FreeAndNil(FGet);
+  FGet:=aValue;
+  AddKeyWord(pkGet);
+end;
+
+
+procedure TPathItem.Set_Put(const aValue : TApiOperation);
+
+begin
+  if (FPut=aValue) then exit;
+  FreeAndNil(FPut);
+  FPut:=aValue;
+  AddKeyWord(pkPut);
+end;
+
+
+procedure TPathItem.Set_Post(const aValue : TApiOperation);
+
+begin
+  if (FPost=aValue) then exit;
+  FreeAndNil(FPost);
+  FPost:=aValue;
+  AddKeyWord(pkPost);
+end;
+
+
+procedure TPathItem.Set_Delete(const aValue : TApiOperation);
+
+begin
+  if (FDelete=aValue) then exit;
+  FreeAndNil(FDelete);
+  FDelete:=aValue;
+  AddKeyWord(pkDelete);
+end;
+
+
+procedure TPathItem.Set_Options(const aValue : TApiOperation);
+
+begin
+  if (FOptions=aValue) then exit;
+  FreeAndNil(FOptions);
+  FOptions:=aValue;
+  AddKeyWord(pkOptions);
+end;
+
+
+procedure TPathItem.Set_Head(const aValue : TApiOperation);
+
+begin
+  if (FHead=aValue) then exit;
+  FreeAndNil(FHead);
+  FHead:=aValue;
+  AddKeyWord(pkHead);
+end;
+
+
+procedure TPathItem.Set_Patch(const aValue : TApiOperation);
+
+begin
+  if (FPatch=aValue) then exit;
+  FreeAndNil(FPatch);
+  FPatch:=aValue;
+  AddKeyWord(pkPatch);
+end;
+
+
+procedure TPathItem.Set_Trace(const aValue : TApiOperation);
+
+begin
+  if (FTrace=aValue) then exit;
+  FreeAndNil(FTrace);
+  FTrace:=aValue;
+  AddKeyWord(pkTrace);
+end;
+
+
+procedure TPathItem.Set_Servers(const aValue : TServerList);
+
+begin
+  if (FServers=aValue) then exit;
+  FreeAndNil(FServers);
+  FServers:=aValue;
+  AddKeyWord(pkServers);
+end;
+
+
+procedure TPathItem.Set_Parameters(const aValue : TParameterOrReferenceList);
+
+begin
+  if (FParameters=aValue) then exit;
+  FreeAndNil(FParameters);
+  FParameters:=aValue;
+  AddKeyWord(pkParameters);
+end;
+
+
+procedure TPathItem.AddKeyword(aKeyword : TPathItemKeyword);
+
+begin
+  Include(FKeywords,aKeyword);
+end;
+
+
+procedure TPathItem.RemoveKeyword(aKeyword : TPathItemKeyword);
+
+begin
+  Exclude(FKeywords,aKeyword);
+end;
+
+
+function TPathItem.HasKeyWord(aKeyword: TPathItemKeyword): Boolean;
+
+begin
+  Result:=aKeyword in FKeywords;
+end;
+
+function TPathItem.GetOperation(aKeyword: TPathItemOperationKeyword
+  ): TAPIOperation;
+begin
+  Case aKeyword of
+    pkGet : Result:=FGet;
+    pkPut : Result:=FPut;
+    pkPost : Result:=FPost;
+    pkDelete : Result:=FDelete;
+    pkOptions : Result:=FOptions;
+    pkHead : Result:=FHead;
+    pkPatch : Result:=FPatch;
+    pkTrace : Result:=FTrace;
+  else
+    Result:=Nil;
+  end;
+end;
+
+
+destructor TPathItem.destroy;
+
+begin
+  FreeAndNil(FGet);
+  FreeAndNil(FPut);
+  FreeAndNil(FPost);
+  FreeAndNil(FDelete);
+  FreeAndNil(FOptions);
+  FreeAndNil(FHead);
+  FreeAndNil(FPatch);
+  FreeAndNil(FTrace);
+  FreeAndNil(FServers);
+  FreeAndNil(FParameters);
+  Inherited;
+end;
+
+
+
+function TPathItemOrReference.GetReference : TReference;
+
+begin
+  if Not Assigned(FReference) then
+    FReference:=TReference.Create(Self,'reference');
+  Result:=FReference;
+end;
+
+
+destructor TPathItemOrReference.destroy;
+
+begin
+  FreeAndNil(FReference);
+  Inherited;
+end;
+
+
+function TPathItemOrReference.HasReference : Boolean;
+
+begin
+  Result:=Assigned(FReference);
+end;
+
+
+function TPathItemOrReferenceMap.GetObject(const aName : TJSONStringType) : TPathItemOrReference;
+
+begin
+  Result:=TPathItemOrReference(GetObjectByName(aName));
+end;
+
+
+constructor TPathItemOrReferenceMap.Create(aParent: TBaseOpenAPIObject; aPathComponent: TJSONStringType);
+
+begin
+  Inherited Create(aParent,aPathComponent,TPathItemOrReference);
+end;
+
+
+function TPathItemOrReferenceMap.AddItem(const aName : TJSONStringType) : TPathItemOrReference;
+
+begin
+  Result:=CreateNew(aName) as TPathItemOrReference;
+  //Add(aName,Result);
+end;
+
+
+function TApiOperation.Get_Tags : TStrings;
+
+begin
+  if Not assigned(FTags) then
+    begin
+    FTags:=TStringList.Create;
+    AddKeyWord(okTags);
+    end;
+  Result:=FTags;
+end;
+
+
+function TApiOperation.Get_ExternalDocs : TExternalDocumentation;
+
+begin
+  if Not assigned(FExternalDocs) then
+    begin
+    FExternalDocs:=TExternalDocumentation.Create(Self,'externalDocs');
+    AddKeyWord(okExternalDocs);
+    end;
+  Result:=FExternalDocs;
+end;
+
+
+function TApiOperation.Get_Parameters : TParameterOrReferenceList;
+
+begin
+  if Not assigned(FParameters) then
+    begin
+    FParameters:=TParameterOrReferenceList.Create;
+    AddKeyWord(okParameters);
+    end;
+  Result:=FParameters;
+end;
+
+
+function TApiOperation.Get_RequestBody : TRequestBodyOrReference;
+
+begin
+  if Not assigned(FRequestBody) then
+    begin
+    FRequestBody:=TRequestBodyOrReference.Create(Self,'requestBody');
+    AddKeyWord(okRequestBody);
+    end;
+  Result:=FRequestBody;
+end;
+
+
+function TApiOperation.Get_Responses : TResponses;
+
+begin
+  if Not assigned(FResponses) then
+    begin
+    FResponses:=TResponses.Create(Self,'responses');
+    AddKeyWord(okResponses);
+    end;
+  Result:=FResponses;
+end;
+
+
+function TApiOperation.Get_Callbacks : TCallBackOrReferenceMap;
+
+begin
+  if Not assigned(FCallbacks) then
+    begin
+    FCallbacks:=TCallBackOrReferenceMap.Create(Self,'callbacks');
+    AddKeyWord(okCallbacks);
+    end;
+  Result:=FCallbacks;
+end;
+
+
+function TApiOperation.Get_Security : TSecurityRequirementList;
+
+begin
+  if Not assigned(FSecurity) then
+    begin
+    FSecurity:=TSecurityRequirementList.Create;
+    AddKeyWord(okSecurity);
+    end;
+  Result:=FSecurity;
+end;
+
+
+function TApiOperation.Get_Servers : TServerList;
+
+begin
+  if Not assigned(FServers) then
+    begin
+    FServers:=TServerList.Create;
+    AddKeyWord(okServers);
+    end;
+  Result:=FServers;
+end;
+
+
+procedure TApiOperation.Set_Tags(const aValue : TStrings);
+
+begin
+  if (FTags=aValue) then exit;
+  FreeAndNil(FTags);
+  FTags:=aValue;
+  AddKeyWord(okTags);
+end;
+
+
+procedure TApiOperation.Set_Summary(const aValue : string);
+
+begin
+  if (FSummary=aValue) then exit;
+  FSummary:=aValue;
+  AddKeyWord(okSummary);
+end;
+
+
+procedure TApiOperation.Set_Description(const aValue : string);
+
+begin
+  if (FDescription=aValue) then exit;
+  FDescription:=aValue;
+  AddKeyWord(okDescription);
+end;
+
+
+procedure TApiOperation.Set_ExternalDocs(const aValue : TExternalDocumentation);
+
+begin
+  if (FExternalDocs=aValue) then exit;
+  FreeAndNil(FExternalDocs);
+  FExternalDocs:=aValue;
+  AddKeyWord(okExternalDocs);
+end;
+
+
+procedure TApiOperation.Set_OperationId(const aValue : string);
+
+begin
+  if (FOperationId=aValue) then exit;
+  FOperationId:=aValue;
+  AddKeyWord(okOperationId);
+end;
+
+
+procedure TApiOperation.Set_Parameters(const aValue : TParameterOrReferenceList);
+
+begin
+  if (FParameters=aValue) then exit;
+  FreeAndNil(FParameters);
+  FParameters:=aValue;
+  AddKeyWord(okParameters);
+end;
+
+
+procedure TApiOperation.Set_RequestBody(const aValue : TRequestBodyOrReference);
+
+begin
+  if (FRequestBody=aValue) then exit;
+  FreeAndNil(FRequestBody);
+  FRequestBody:=aValue;
+  AddKeyWord(okRequestBody);
+end;
+
+
+procedure TApiOperation.Set_Responses(const aValue : TResponses);
+
+begin
+  if (FResponses=aValue) then exit;
+  FreeAndNil(FResponses);
+  FResponses:=aValue;
+  AddKeyWord(okResponses);
+end;
+
+
+procedure TApiOperation.Set_Callbacks(const aValue : TCallBackOrReferenceMap);
+
+begin
+  if (FCallbacks=aValue) then exit;
+  FreeAndNil(FCallbacks);
+  FCallbacks:=aValue;
+  AddKeyWord(okCallbacks);
+end;
+
+
+procedure TApiOperation.Set_Deprecated(const aValue : Boolean);
+
+begin
+  if (FDeprecated=aValue) then exit;
+  FDeprecated:=aValue;
+  AddKeyWord(okDeprecated);
+end;
+
+
+procedure TApiOperation.Set_Security(const aValue : TSecurityRequirementList);
+
+begin
+  if (FSecurity=aValue) then exit;
+  FreeAndNil(FSecurity);
+  FSecurity:=aValue;
+  AddKeyWord(okSecurity);
+end;
+
+
+procedure TApiOperation.Set_Servers(const aValue : TServerList);
+
+begin
+  if (FServers=aValue) then exit;
+  FreeAndNil(FServers);
+  FServers:=aValue;
+  AddKeyWord(okServers);
+end;
+
+
+procedure TApiOperation.AddKeyword(aKeyword : TApiOperationKeyword);
+
+begin
+  Include(FKeywords,aKeyword);
+end;
+
+
+procedure TApiOperation.RemoveKeyword(aKeyword : TApiOperationKeyword);
+
+begin
+  Exclude(FKeywords,aKeyword);
+end;
+
+
+Function TApiOperation.HasKeyword(aKeyword : TApiOperationKeyword) : Boolean;
+
+begin
+  Result:=aKeyword in FKeywords;
+end;
+
+
+destructor TApiOperation.destroy;
+
+begin
+  FreeAndNil(FTags);
+  FreeAndNil(FExternalDocs);
+  FreeAndNil(FParameters);
+  FreeAndNil(FRequestBody);
+  FreeAndNil(FResponses);
+  FreeAndNil(FCallbacks);
+  FreeAndNil(FSecurity);
+  FreeAndNil(FServers);
+  Inherited;
+end;
+
+
+
+procedure TExternalDocumentation.Set_Description(const aValue : string);
+
+begin
+  if (FDescription=aValue) then exit;
+  FDescription:=aValue;
+  AddKeyWord(edkDescription);
+end;
+
+
+procedure TExternalDocumentation.Set_Url(const aValue : string);
+
+begin
+  if (FUrl=aValue) then exit;
+  FUrl:=aValue;
+  AddKeyWord(edkUrl);
+end;
+
+
+procedure TExternalDocumentation.AddKeyword(aKeyword : TExternalDocumentationKeyword);
+
+begin
+  Include(FKeywords,aKeyword);
+end;
+
+
+procedure TExternalDocumentation.RemoveKeyword(aKeyword : TExternalDocumentationKeyword);
+
+begin
+  Exclude(FKeywords,aKeyword);
+end;
+
+
+Function TExternalDocumentation.HasKeyword(aKeyword : TExternalDocumentationKeyword) : Boolean;
+
+begin
+  Result:=aKeyword in FKeywords;
+end;
+
+
+destructor TExternalDocumentation.destroy;
+
+begin
+  Inherited;
+end;
+
+
+function TParameterOrHeader.Get_Schema : TJSONSchema;
+
+begin
+  if Not assigned(FSchema) then
+    begin
+    FSchema:=TJSONSchema.Create();
+    AddKeyWord(pakSchema);
+    end;
+  Result:=FSchema;
+end;
+
+
+function TParameterOrHeader.Get_Examples : TExampleOrReferenceMap;
+
+begin
+  if Not assigned(FExamples) then
+    begin
+    FExamples:=TExampleOrReferenceMap.Create(Self,'examples');
+    AddKeyWord(pakExamples);
+    end;
+  Result:=FExamples;
+end;
+
+
+function TParameterOrHeader.Get_Content : TMediaTypeMap;
+
+begin
+  if Not assigned(FContent) then
+    begin
+    FContent:=TMediaTypeMap.Create(Self,'content');
+    AddKeyWord(pakContent);
+    end;
+  Result:=FContent;
+end;
+
+
+procedure TParameterOrHeader.Set_Name(const aValue : string);
+
+begin
+  if (FName=aValue) then exit;
+  FName:=aValue;
+  AddKeyWord(pakName);
+end;
+
+
+procedure TParameterOrHeader.Set_In_(const aValue : string);
+
+begin
+  if (FIn_=aValue) then exit;
+  FIn_:=aValue;
+  AddKeyWord(pakIn);
+end;
+
+
+procedure TParameterOrHeader.Set_Description(const aValue : string);
+
+begin
+  if (FDescription=aValue) then exit;
+  FDescription:=aValue;
+  AddKeyWord(pakDescription);
+end;
+
+
+procedure TParameterOrHeader.Set_Required(const aValue : Boolean);
+
+begin
+  if (FRequired=aValue) then exit;
+  FRequired:=aValue;
+  AddKeyWord(pakRequired);
+end;
+
+
+procedure TParameterOrHeader.Set_Deprecated(const aValue : Boolean);
+
+begin
+  if (FDeprecated=aValue) then exit;
+  FDeprecated:=aValue;
+  AddKeyWord(pakDeprecated);
+end;
+
+
+procedure TParameterOrHeader.Set_AllowEmptyValue(const aValue : Boolean);
+
+begin
+  if (FAllowEmptyValue=aValue) then exit;
+  FAllowEmptyValue:=aValue;
+  AddKeyWord(pakAllowEmptyValue);
+end;
+
+
+procedure TParameterOrHeader.Set_Style(const aValue : string);
+
+begin
+  if (FStyle=aValue) then exit;
+  FStyle:=aValue;
+  AddKeyWord(pakStyle);
+end;
+
+
+procedure TParameterOrHeader.Set_Explode(const aValue : Boolean);
+
+begin
+  if (FExplode=aValue) then exit;
+  FExplode:=aValue;
+  AddKeyWord(pakExplode);
+end;
+
+
+procedure TParameterOrHeader.Set_AllowReserved(const aValue : Boolean);
+
+begin
+  if (FAllowReserved=aValue) then exit;
+  FAllowReserved:=aValue;
+  AddKeyWord(pakAllowReserved);
+end;
+
+
+procedure TParameterOrHeader.Set_Schema(const aValue : TJSONSchema);
+
+begin
+  if (FSchema=aValue) then exit;
+  FreeAndNil(FSchema);
+  FSchema:=aValue;
+  AddKeyWord(pakSchema);
+end;
+
+
+procedure TParameterOrHeader.Set_Example(const aValue : TJSONData);
+
+begin
+  if (FExample=aValue) then exit;
+  FreeAndNil(FExample);
+  FExample:=aValue;
+  AddKeyWord(pakExample);
+end;
+
+
+procedure TParameterOrHeader.Set_Examples(const aValue : TExampleOrReferenceMap);
+
+begin
+  if (FExamples=aValue) then exit;
+  FreeAndNil(FExamples);
+  FExamples:=aValue;
+  AddKeyWord(pakExamples);
+end;
+
+
+procedure TParameterOrHeader.Set_Content(const aValue : TMediaTypeMap);
+
+begin
+  if (FContent=aValue) then exit;
+  FreeAndNil(FContent);
+  FContent:=aValue;
+  AddKeyWord(pakContent);
+end;
+
+
+procedure TParameterOrHeader.AddKeyword(aKeyword : TParameterKeyword);
+
+begin
+  Include(FKeywords,aKeyword);
+end;
+
+
+procedure TParameterOrHeader.RemoveKeyword(aKeyword : TParameterKeyword);
+
+begin
+  Exclude(FKeywords,aKeyword);
+end;
+
+
+Function TParameterOrHeader.HasKeyword(aKeyword : TParameterKeyword) : Boolean;
+
+begin
+  Result:=aKeyword in FKeywords;
+end;
+
+
+destructor TParameterOrHeader.destroy;
+
+begin
+  FreeAndNil(FSchema);
+  FreeAndNil(FExample);
+  FreeAndNil(FExamples);
+  FreeAndNil(FContent);
+  Inherited;
+end;
+
+
+function TParameterOrReference.GetReference : TReference;
+
+begin
+  if Not Assigned(FReference) then
+    FReference:=TReference.Create(Self,'reference');
+  Result:=FReference;
+end;
+
+
+destructor TParameterOrReference.destroy;
+
+begin
+  FreeAndNil(FReference);
+  Inherited;
+end;
+
+
+function TParameterOrReference.HasReference : Boolean;
+
+begin
+  Result:=Assigned(FReference);
+end;
+
+
+function TParameterOrReferenceMap.GetObject(const aName : TJSONStringType) : TParameterOrReference;
+
+begin
+  Result:=TParameterOrReference(GetObjectByName(aName));
+end;
+
+
+constructor TParameterOrReferenceMap.Create(aParent: TBaseOpenAPIObject; const aPathComponent: TJSONStringType);
+
+begin
+  Inherited Create(aParent,aPathComponent,TParameterOrReference);
+end;
+
+
+function TParameterOrReferenceMap.AddItem(const aName : TJSONStringType) : TParameterOrReference;
+
+begin
+  Result:=CreateNew(aName) as TParameterOrReference;
+  // Add(aName,Result);
+end;
+
+
+procedure TParameterStyle.Set_Matrix(const aValue : string);
+
+begin
+  if (FMatrix=aValue) then exit;
+  FMatrix:=aValue;
+  AddKeyWord(pskMatrix);
+end;
+
+
+procedure TParameterStyle.Set_Label_(const aValue : string);
+
+begin
+  if (FLabel_=aValue) then exit;
+  FLabel_:=aValue;
+  AddKeyWord(pskLabel);
+end;
+
+
+procedure TParameterStyle.Set_Form(const aValue : string);
+
+begin
+  if (FForm=aValue) then exit;
+  FForm:=aValue;
+  AddKeyWord(pskForm);
+end;
+
+
+procedure TParameterStyle.Set_Simple(const aValue : string);
+
+begin
+  if (FSimple=aValue) then exit;
+  FSimple:=aValue;
+  AddKeyWord(pskSimple);
+end;
+
+
+procedure TParameterStyle.Set_SpaceDelimited(const aValue : string);
+
+begin
+  if (FSpaceDelimited=aValue) then exit;
+  FSpaceDelimited:=aValue;
+  AddKeyWord(pskSpaceDelimited);
+end;
+
+
+procedure TParameterStyle.Set_PipeDelimited(const aValue : string);
+
+begin
+  if (FPipeDelimited=aValue) then exit;
+  FPipeDelimited:=aValue;
+  AddKeyWord(pskPipeDelimited);
+end;
+
+
+procedure TParameterStyle.Set_DeepObject(const aValue : string);
+
+begin
+  if (FDeepObject=aValue) then exit;
+  FDeepObject:=aValue;
+  AddKeyWord(pskDeepObject);
+end;
+
+
+procedure TParameterStyle.AddKeyword(aKeyword : TParameterStyleKeyword);
+
+begin
+  Include(FKeywords,aKeyword);
+end;
+
+
+procedure TParameterStyle.RemoveKeyword(aKeyword : TParameterStyleKeyword);
+
+begin
+  Exclude(FKeywords,aKeyword);
+end;
+
+
+Function TParameterStyle.HasKeyword(aKeyword : TParameterStyleKeyword) : Boolean;
+
+begin
+  Result:=aKeyword in FKeywords;
+end;
+
+
+destructor TParameterStyle.destroy;
+
+begin
+  Inherited;
+end;
+
+
+function TRequestBody.Get_Content : TMediaTypeMap;
+
+begin
+  if Not assigned(FContent) then
+    begin
+    FContent:=TMediaTypeMap.Create(Self,'content');
+    AddKeyWord(rbkContent);
+    end;
+  Result:=FContent;
+end;
+
+
+procedure TRequestBody.Set_Description(const aValue : string);
+
+begin
+  if (FDescription=aValue) then exit;
+  FDescription:=aValue;
+  AddKeyWord(rbkDescription);
+end;
+
+
+procedure TRequestBody.Set_Content(const aValue : TMediaTypeMap);
+
+begin
+  if (FContent=aValue) then exit;
+  FreeAndNil(FContent);
+  FContent:=aValue;
+  AddKeyWord(rbkContent);
+end;
+
+
+procedure TRequestBody.Set_Required(const aValue : Boolean);
+
+begin
+  if (FRequired=aValue) then exit;
+  FRequired:=aValue;
+  AddKeyWord(rbkRequired);
+end;
+
+
+procedure TRequestBody.AddKeyword(aKeyword : TRequestBodyKeyword);
+
+begin
+  Include(FKeywords,aKeyword);
+end;
+
+
+procedure TRequestBody.RemoveKeyword(aKeyword : TRequestBodyKeyword);
+
+begin
+  Exclude(FKeywords,aKeyword);
+end;
+
+
+Function TRequestBody.HasKeyword(aKeyword : TRequestBodyKeyword) : Boolean;
+
+begin
+  Result:=aKeyword in FKeywords;
+end;
+
+
+destructor TRequestBody.destroy;
+
+begin
+  FreeAndNil(FContent);
+  Inherited;
+end;
+
+function TRequestBodyOrReference.GetReference : TReference;
+
+begin
+  if Not Assigned(FReference) then
+    FReference:=TReference.Create(Self,'reference');
+  Result:=FReference;
+end;
+
+
+destructor TRequestBodyOrReference.destroy;
+
+begin
+  FreeAndNil(FReference);
+  Inherited;
+end;
+
+
+function TRequestBodyOrReference.HasReference : Boolean;
+
+begin
+  Result:=Assigned(FReference);
+end;
+
+
+function TRequestBodyOrReferenceMap.GetObject(const aName : TJSONStringType) : TRequestBodyOrReference;
+
+begin
+  Result:=TRequestBodyOrReference(GetObjectByName(aName));
+end;
+
+
+constructor TRequestBodyOrReferenceMap.Create(aParent: TBaseOpenAPIObject; const aPathComponent: TJSONStringType);
+
+begin
+  Inherited Create(aParent,aPathComponent,TRequestBodyOrReference);
+end;
+
+
+function TRequestBodyOrReferenceMap.AddItem(const aName : TJSONStringType) : TRequestBodyOrReference;
+
+begin
+  Result:=CreateNew(aName) as TRequestBodyOrReference;
+//  Add(aName,Result);
+end;
+
+
+function TMediaType.Get_Schema : TJSONSchema;
+
+begin
+  if Not assigned(FSchema) then
+    begin
+    FSchema:=TJSONSchema.Create();
+    AddKeyWord(mtkSchema);
+    end;
+  Result:=FSchema;
+end;
+
+
+function TMediaType.Get_Examples : TExampleOrReferenceMap;
+
+begin
+  if Not assigned(FExamples) then
+    begin
+    FExamples:=TExampleOrReferenceMap.Create(Self,'examples');
+    AddKeyWord(mtkExamples);
+    end;
+  Result:=FExamples;
+end;
+
+
+function TMediaType.Get_Encoding : TEncodingMap;
+
+begin
+  if Not assigned(FEncoding) then
+    begin
+    FEncoding:=TEncodingMap.Create(Self,'encoding');
+    AddKeyWord(mtkEncoding);
+    end;
+  Result:=FEncoding;
+end;
+
+
+procedure TMediaType.Set_Schema(const aValue : TJSONSchema);
+
+begin
+  if (FSchema=aValue) then exit;
+  FreeAndNil(FSchema);
+  FSchema:=aValue;
+  AddKeyWord(mtkSchema);
+end;
+
+
+procedure TMediaType.Set_Example(const aValue : TJSONData);
+
+begin
+  if (FExample=aValue) then exit;
+  FreeAndNil(FExample);
+  FExample:=aValue;
+  AddKeyWord(mtkExample);
+end;
+
+
+procedure TMediaType.Set_Examples(const aValue : TExampleOrReferenceMap);
+
+begin
+  if (FExamples=aValue) then exit;
+  FreeAndNil(FExamples);
+  FExamples:=aValue;
+  AddKeyWord(mtkExamples);
+end;
+
+
+procedure TMediaType.Set_Encoding(const aValue : TEncodingMap);
+
+begin
+  if (FEncoding=aValue) then exit;
+  FreeAndNil(FEncoding);
+  FEncoding:=aValue;
+  AddKeyWord(mtkEncoding);
+end;
+
+
+procedure TMediaType.AddKeyword(aKeyword : TMediaTypeKeyword);
+
+begin
+  Include(FKeywords,aKeyword);
+end;
+
+
+procedure TMediaType.RemoveKeyword(aKeyword : TMediaTypeKeyword);
+
+begin
+  Exclude(FKeywords,aKeyword);
+end;
+
+
+Function TMediaType.HasKeyword(aKeyword : TMediaTypeKeyword) : Boolean;
+
+begin
+  Result:=aKeyword in FKeywords;
+end;
+
+
+destructor TMediaType.destroy;
+
+begin
+  FreeAndNil(FSchema);
+  FreeAndNil(FExample);
+  FreeAndNil(FExamples);
+  FreeAndNil(FEncoding);
+  Inherited;
+end;
+
+
+
+
+function TMediaTypeMap.GetObject(const aName : TJSONStringType) : TMediaType;
+
+begin
+  Result:=TMediaType(GetObjectByName(aName));
+end;
+
+
+constructor TMediaTypeMap.Create(aParent : TBaseOpenAPIObject; const aPathcomponent : TJSONStringType);
+
+begin
+  Inherited Create(aParent,aPathComponent,TMediaType);
+end;
+
+
+function TMediaTypeMap.AddItem(const aName : TJSONStringType) : TMediaType;
+
+begin
+  Result:=CreateNew(aName) as TMediaType;
+//  Add(aName,Result);
+end;
+
+
+function TEncoding.Get_Headers : THeaderOrReferenceMap;
+
+begin
+  if Not assigned(FHeaders) then
+    begin
+    FHeaders:=THeaderOrReferenceMap.Create(Self,'headers');
+    AddKeyWord(eckHeaders);
+    end;
+  Result:=FHeaders;
+end;
+
+
+procedure TEncoding.Set_ContentType(const aValue : string);
+
+begin
+  if (FContentType=aValue) then exit;
+  FContentType:=aValue;
+  AddKeyWord(eckContentType);
+end;
+
+
+procedure TEncoding.Set_Headers(const aValue : THeaderOrReferenceMap);
+
+begin
+  if (FHeaders=aValue) then exit;
+  FreeAndNil(FHeaders);
+  FHeaders:=aValue;
+  AddKeyWord(eckHeaders);
+end;
+
+
+procedure TEncoding.Set_Style(const aValue : string);
+
+begin
+  if (FStyle=aValue) then exit;
+  FStyle:=aValue;
+  AddKeyWord(eckStyle);
+end;
+
+
+procedure TEncoding.Set_Explode(const aValue : Boolean);
+
+begin
+  if (FExplode=aValue) then exit;
+  FExplode:=aValue;
+  AddKeyWord(eckExplode);
+end;
+
+
+procedure TEncoding.Set_AllowReserved(const aValue : Boolean);
+
+begin
+  if (FAllowReserved=aValue) then exit;
+  FAllowReserved:=aValue;
+  AddKeyWord(eckAllowReserved);
+end;
+
+
+procedure TEncoding.AddKeyword(aKeyword : TEncodingKeyword);
+
+begin
+  Include(FKeywords,aKeyword);
+end;
+
+
+procedure TEncoding.RemoveKeyword(aKeyword : TEncodingKeyword);
+
+begin
+  Exclude(FKeywords,aKeyword);
+end;
+
+
+Function TEncoding.HasKeyword(aKeyword : TEncodingKeyword) : Boolean;
+
+begin
+  Result:=aKeyword in FKeywords;
+end;
+
+
+destructor TEncoding.destroy;
+
+begin
+  FreeAndNil(FHeaders);
+  Inherited;
+end;
+
+
+function TEncodingMap.GetObject(const aName : TJSONStringType) : TEncoding;
+
+begin
+  Result:=TEncoding(GetObjectByName(aName));
+end;
+
+
+constructor TEncodingMap.Create(aParent : TBaseOpenAPIObject; const aPathComponent : TJSONStringType);
+
+begin
+  Inherited Create(aParent,aPathComponent,TEncoding);
+end;
+
+
+function TEncodingMap.AddItem(const aName : TJSONStringType) : TEncoding;
+
+begin
+  Result:=CreateNew(aName) as TEncoding;
+//  Add(aName,Result);
+end;
+
+{ TResponses }
+
+function TResponses.GetObject(const aName: TJSONStringType): TResponse;
+begin
+  Result:=TResponse(GetObjectByName(aName));
+end;
+
+function TResponses.GetResponseByIndex(aIndex : Integer): TResponse;
+begin
+  Result:=TResponse(NamedObjects[aIndex].Object_);
+end;
+
+
+constructor TResponses.Create(aParent: TBaseOpenAPIObject; const aPathComponent : TJSONStringType);
+begin
+  Inherited Create(aParent,aPathComponent,TResponse);
+end;
+
+function TResponses.AddItem(const aName: TJSONStringType): TResponse;
+begin
+  Result:=CreateNew(aName) as TResponse;
+//  Add(aName,Result);
+end;
+
+
+
+
+function TResponse.Get_Headers : THeaderOrReferenceMap;
+
+begin
+  if Not assigned(FHeaders) then
+    begin
+    FHeaders:=THeaderOrReferenceMap.Create(Self,'headers');
+    AddKeyWord(rkHeaders);
+    end;
+  Result:=FHeaders;
+end;
+
+
+function TResponse.Get_Content : TMediaTypeMap;
+
+begin
+  if Not assigned(FContent) then
+    begin
+    FContent:=TMediaTypeMap.Create(Self,'content');
+    AddKeyWord(rkContent);
+    end;
+  Result:=FContent;
+end;
+
+
+function TResponse.Get_Links : TLinkOrReferenceMap;
+
+begin
+  if Not assigned(FLinks) then
+    begin
+    FLinks:=TLinkOrReferenceMap.Create(Self,'links');
+    AddKeyWord(rkLinks);
+    end;
+  Result:=FLinks;
+end;
+
+
+procedure TResponse.Set_Description(const aValue : string);
+
+begin
+  if (FDescription=aValue) then exit;
+  FDescription:=aValue;
+  AddKeyWord(rkDescription);
+end;
+
+
+procedure TResponse.Set_Headers(const aValue : THeaderOrReferenceMap);
+
+begin
+  if (FHeaders=aValue) then exit;
+  FreeAndNil(FHeaders);
+  FHeaders:=aValue;
+  AddKeyWord(rkHeaders);
+end;
+
+
+procedure TResponse.Set_Content(const aValue : TMediaTypeMap);
+
+begin
+  if (FContent=aValue) then exit;
+  FreeAndNil(FContent);
+  FContent:=aValue;
+  AddKeyWord(rkContent);
+end;
+
+
+procedure TResponse.Set_Links(const aValue : TLinkOrReferenceMap);
+
+begin
+  if (FLinks=aValue) then exit;
+  FreeAndNil(FLinks);
+  FLinks:=aValue;
+  AddKeyWord(rkLinks);
+end;
+
+
+procedure TResponse.AddKeyword(aKeyword : TResponseKeyword);
+
+begin
+  Include(FKeywords,aKeyword);
+end;
+
+
+procedure TResponse.RemoveKeyword(aKeyword : TResponseKeyword);
+
+begin
+  Exclude(FKeywords,aKeyword);
+end;
+
+
+Function TResponse.HasKeyword(aKeyword : TResponseKeyword) : Boolean;
+
+begin
+  Result:=aKeyword in FKeywords;
+end;
+
+
+destructor TResponse.destroy;
+
+begin
+  FreeAndNil(FHeaders);
+  FreeAndNil(FContent);
+  FreeAndNil(FLinks);
+  Inherited;
+end;
+
+
+function TResponseOrReference.GetReference : TReference;
+
+begin
+  if Not Assigned(FReference) then
+    FReference:=TReference.Create(Self,'');
+  Result:=FReference;
+end;
+
+
+destructor TResponseOrReference.destroy;
+
+begin
+  FreeAndNil(FReference);
+  Inherited;
+end;
+
+
+function TResponseOrReference.HasReference : Boolean;
+
+begin
+  Result:=Assigned(FReference);
+end;
+
+
+function TResponseOrReferenceMap.GetObject(const aName : TJSONStringType) : TResponseOrReference;
+
+begin
+  Result:=TResponseOrReference(GetObjectByName(aName));
+end;
+
+
+constructor TResponseOrReferenceMap.Create(aParent : TBaseOpenAPIObject; const aPathComponent : TJSONStringType);
+
+begin
+  Inherited Create(aParent,aPathComponent,TResponseOrReference);
+end;
+
+
+function TResponseOrReferenceMap.AddItem(const aName : TJSONStringType) : TResponseOrReference;
+
+begin
+  Result:=CreateNew(aName) as TResponseOrReference;
+//  Add(aName,Result);
+end;
+
+
+procedure TExample.Set_Summary(const aValue : string);
+
+begin
+  if (FSummary=aValue) then exit;
+  FSummary:=aValue;
+  AddKeyWord(exkSummary);
+end;
+
+
+procedure TExample.Set_Description(const aValue : string);
+
+begin
+  if (FDescription=aValue) then exit;
+  FDescription:=aValue;
+  AddKeyWord(exkDescription);
+end;
+
+
+procedure TExample.Set_Value(const aValue : TJSONData);
+
+begin
+  if (FValue=aValue) then exit;
+  FreeAndNil(FValue);
+  FValue:=aValue;
+  AddKeyWord(exkValue);
+end;
+
+
+procedure TExample.Set_ExternalValue(const aValue : string);
+
+begin
+  if (FExternalValue=aValue) then exit;
+  FExternalValue:=aValue;
+  AddKeyWord(exkExternalValue);
+end;
+
+
+procedure TExample.AddKeyword(aKeyword : TExampleKeyword);
+
+begin
+  Include(FKeywords,aKeyword);
+end;
+
+
+procedure TExample.RemoveKeyword(aKeyword : TExampleKeyword);
+
+begin
+  Exclude(FKeywords,aKeyword);
+end;
+
+
+Function TExample.HasKeyword(aKeyword : TExampleKeyword) : Boolean;
+
+begin
+  Result:=aKeyword in FKeywords;
+end;
+
+
+destructor TExample.destroy;
+
+begin
+  FreeAndNil(FValue);
+  Inherited;
+end;
+
+
+function TExampleOrReference.GetReference : TReference;
+
+begin
+  if Not Assigned(FReference) then
+    FReference:=TReference.Create(Self,'');
+  Result:=FReference;
+end;
+
+
+destructor TExampleOrReference.destroy;
+
+begin
+  FreeAndNil(FReference);
+  Inherited;
+end;
+
+
+function TExampleOrReference.HasReference : Boolean;
+
+begin
+  Result:=Assigned(FReference);
+end;
+
+
+function TExampleOrReferenceMap.GetObject(const aName : TJSONStringType) : TExampleOrReference;
+
+begin
+  Result:=TExampleOrReference(GetObjectByName(aName));
+end;
+
+
+constructor TExampleOrReferenceMap.Create(aParent: TBaseOpenAPIObject; const aPathComponent : TJSONStringType);
+
+begin
+  Inherited Create(aParent,aPathComponent,TExampleOrReference);
+end;
+
+
+function TExampleOrReferenceMap.AddItem(const aName : TJSONStringType) : TExampleOrReference;
+
+begin
+  Result:=CreateNew(aName) as TExampleOrReference;
+//  Add(aName,Result);
+end;
+
+
+function TLink.Get_Parameters : TJSONObject;
+
+begin
+  if Not assigned(FParameters) then
+    begin
+    FParameters:=TJSONObject.Create();
+    AddKeyWord(likParameters);
+    end;
+  Result:=FParameters;
+end;
+
+
+function TLink.Get_Server : TServer;
+
+begin
+  if Not assigned(FServer) then
+    begin
+    FServer:=TServer.Create(Self,'server');
+    AddKeyWord(likServer);
+    end;
+  Result:=FServer;
+end;
+
+
+procedure TLink.Set_OperationRef(const aValue : string);
+
+begin
+  if (FOperationRef=aValue) then exit;
+  FOperationRef:=aValue;
+  AddKeyWord(likOperationRef);
+end;
+
+
+procedure TLink.Set_OperationId(const aValue : string);
+
+begin
+  if (FOperationId=aValue) then exit;
+  FOperationId:=aValue;
+  AddKeyWord(likOperationId);
+end;
+
+
+procedure TLink.Set_Parameters(const aValue : TJSONObject);
+
+begin
+  if (FParameters=aValue) then exit;
+  FreeAndNil(FParameters);
+  FParameters:=aValue;
+  AddKeyWord(likParameters);
+end;
+
+
+procedure TLink.Set_RequestBody(const aValue : TJSONData);
+
+begin
+  if (FRequestBody=aValue) then exit;
+  FreeAndNil(FRequestBody);
+  FRequestBody:=aValue;
+  AddKeyWord(likRequestBody);
+end;
+
+
+procedure TLink.Set_Description(const aValue : string);
+
+begin
+  if (FDescription=aValue) then exit;
+  FDescription:=aValue;
+  AddKeyWord(likDescription);
+end;
+
+
+procedure TLink.Set_Server(const aValue : TServer);
+
+begin
+  if (FServer=aValue) then exit;
+  FreeAndNil(FServer);
+  FServer:=aValue;
+  AddKeyWord(likServer);
+end;
+
+
+procedure TLink.AddKeyword(aKeyword : TLinkKeyword);
+
+begin
+  Include(FKeywords,aKeyword);
+end;
+
+
+procedure TLink.RemoveKeyword(aKeyword : TLinkKeyword);
+
+begin
+  Exclude(FKeywords,aKeyword);
+end;
+
+
+Function TLink.HasKeyword(aKeyword : TLinkKeyword) : Boolean;
+
+begin
+  Result:=aKeyword in FKeywords;
+end;
+
+
+destructor TLink.destroy;
+
+begin
+  FreeAndNil(FParameters);
+  FreeAndNil(FRequestBody);
+  FreeAndNil(FServer);
+  Inherited;
+end;
+
+
+function TLinkOrReference.GetReference : TReference;
+
+begin
+  if Not Assigned(FReference) then
+    FReference:=TReference.Create(Self,'');
+  Result:=FReference;
+end;
+
+
+destructor TLinkOrReference.destroy;
+
+begin
+  FreeAndNil(FReference);
+  Inherited;
+end;
+
+
+function TLinkOrReference.HasReference : Boolean;
+
+begin
+  Result:=Assigned(FReference);
+end;
+
+
+function TLinkOrReferenceMap.GetObject(const aName : TJSONStringType) : TLinkOrReference;
+
+begin
+  Result:=TLinkOrReference(GetObjectByName(aName));
+end;
+
+
+constructor TLinkOrReferenceMap.Create(aParent : TBaseOpenAPIObject; const aPathComponent : TJSONStringType);
+
+begin
+  Inherited Create(aParent,aPathComponent,TLinkOrReference);
+end;
+
+
+function TLinkOrReferenceMap.AddItem(const aName : TJSONStringType) : TLinkOrReference;
+
+begin
+  Result:=CreateNew(aName) as TLinkOrReference;
+//  Add(aName,Result);
+end;
+
+
+function TTag.Get_ExternalDocs : TExternalDocumentation;
+
+begin
+  if Not assigned(FExternalDocs) then
+    begin
+    FExternalDocs:=TExternalDocumentation.Create(Self,'externalDocs');
+    AddKeyWord(tkExternalDocs);
+    end;
+  Result:=FExternalDocs;
+end;
+
+
+procedure TTag.Set_Name(const aValue : string);
+
+begin
+  if (FName=aValue) then exit;
+  FName:=aValue;
+  AddKeyWord(tkName);
+end;
+
+
+procedure TTag.Set_Description(const aValue : string);
+
+begin
+  if (FDescription=aValue) then exit;
+  FDescription:=aValue;
+  AddKeyWord(tkDescription);
+end;
+
+
+procedure TTag.Set_ExternalDocs(const aValue : TExternalDocumentation);
+
+begin
+  if (FExternalDocs=aValue) then exit;
+  FreeAndNil(FExternalDocs);
+  FExternalDocs:=aValue;
+  AddKeyWord(tkExternalDocs);
+end;
+
+
+procedure TTag.AddKeyword(aKeyword : TTagKeyword);
+
+begin
+  Include(FKeywords,aKeyword);
+end;
+
+
+procedure TTag.RemoveKeyword(aKeyword : TTagKeyword);
+
+begin
+  Exclude(FKeywords,aKeyword);
+end;
+
+
+Function TTag.HasKeyword(aKeyword : TTagKeyword) : Boolean;
+
+begin
+  Result:=aKeyword in FKeywords;
+end;
+
+
+destructor TTag.destroy;
+
+begin
+  FreeAndNil(FExternalDocs);
+  Inherited;
+end;
+
+
+procedure TReference.Set_Ref(const aValue : string);
+
+begin
+  if (FRef=aValue) then exit;
+  FRef:=aValue;
+  AddKeyWord(rfkRef);
+end;
+
+
+procedure TReference.Set_Summary(const aValue : string);
+
+begin
+  if (FSummary=aValue) then exit;
+  FSummary:=aValue;
+  AddKeyWord(rfkSummary);
+end;
+
+
+procedure TReference.Set_Description(const aValue : string);
+
+begin
+  if (FDescription=aValue) then exit;
+  FDescription:=aValue;
+  AddKeyWord(rfkDescription);
+end;
+
+
+procedure TReference.AddKeyword(aKeyword : TReferenceKeyword);
+
+begin
+  Include(FKeywords,aKeyword);
+end;
+
+
+procedure TReference.RemoveKeyword(aKeyword : TReferenceKeyword);
+
+begin
+  Exclude(FKeywords,aKeyword);
+end;
+
+
+Function TReference.HasKeyword(aKeyword : TReferenceKeyword) : Boolean;
+
+begin
+  Result:=aKeyword in FKeywords;
+end;
+
+
+destructor TReference.destroy;
+
+begin
+  Inherited;
+end;
+
+
+
+function TSchema.Get_Discriminator : TDiscriminator;
+
+begin
+  if Not assigned(FDiscriminator) then
+    begin
+    FDiscriminator:=TDiscriminator.Create(Self,'discriminator');
+    AddKeyWord(sckDiscriminator);
+    end;
+  Result:=FDiscriminator;
+end;
+
+
+function TSchema.Get_XML : TXML;
+
+begin
+  if Not assigned(FXML) then
+    begin
+    FXML:=TXML.Create(Self,'XML');
+    AddKeyWord(sckXML);
+    end;
+  Result:=FXML;
+end;
+
+
+function TSchema.Get_ExternalDocs : TExternalDocumentation;
+
+begin
+  if Not assigned(FExternalDocs) then
+    begin
+    FExternalDocs:=TExternalDocumentation.Create(Self,'externaldocs');
+    AddKeyWord(sckExternalDocs);
+    end;
+  Result:=FExternalDocs;
+end;
+
+
+procedure TSchema.Set_Discriminator(const aValue : TDiscriminator);
+
+begin
+  if (FDiscriminator=aValue) then exit;
+  FreeAndNil(FDiscriminator);
+  FDiscriminator:=aValue;
+  AddKeyWord(sckDiscriminator);
+end;
+
+
+procedure TSchema.Set_XML(const aValue : TXML);
+
+begin
+  if (FXML=aValue) then exit;
+  FreeAndNil(FXML);
+  FXML:=aValue;
+  AddKeyWord(sckXML);
+end;
+
+
+procedure TSchema.Set_ExternalDocs(const aValue : TExternalDocumentation);
+
+begin
+  if (FExternalDocs=aValue) then exit;
+  FreeAndNil(FExternalDocs);
+  FExternalDocs:=aValue;
+  AddKeyWord(sckExternalDocs);
+end;
+
+
+procedure TSchema.Set_Example(const aValue : TJSONData);
+
+begin
+  if (FExample=aValue) then exit;
+  FreeAndNil(FExample);
+  FExample:=aValue;
+  AddKeyWord(sckExample);
+end;
+
+
+procedure TSchema.AddKeyword(aKeyword : TSchemaKeyword);
+
+begin
+  Include(FKeywords,aKeyword);
+end;
+
+
+procedure TSchema.RemoveKeyword(aKeyword : TSchemaKeyword);
+
+begin
+  Exclude(FKeywords,aKeyword);
+end;
+
+
+Function TSchema.HasKeyword(aKeyword : TSchemaKeyword) : Boolean;
+
+begin
+  Result:=aKeyword in FKeywords;
+end;
+
+
+destructor TSchema.destroy;
+
+begin
+  FreeAndNil(FDiscriminator);
+  FreeAndNil(FXML);
+  FreeAndNil(FExternalDocs);
+  FreeAndNil(FExample);
+  Inherited;
+end;
+
+
+function TDiscriminator.Get_Mapping : TStrings;
+
+begin
+  if Not assigned(FMapping) then
+    begin
+    FMapping:=TStringList.Create;
+    AddKeyWord(dikMapping);
+    end;
+  Result:=FMapping;
+end;
+
+
+procedure TDiscriminator.Set_PropertyName(const aValue : string);
+
+begin
+  if (FPropertyName=aValue) then exit;
+  FPropertyName:=aValue;
+  AddKeyWord(dikPropertyName);
+end;
+
+
+procedure TDiscriminator.Set_Mapping(const aValue : TStrings);
+
+begin
+  if (FMapping=aValue) then exit;
+  FreeAndNil(FMapping);
+  FMapping:=aValue;
+  AddKeyWord(dikMapping);
+end;
+
+
+procedure TDiscriminator.AddKeyword(aKeyword : TDiscriminatorKeyword);
+
+begin
+  Include(FKeywords,aKeyword);
+end;
+
+
+procedure TDiscriminator.RemoveKeyword(aKeyword : TDiscriminatorKeyword);
+
+begin
+  Exclude(FKeywords,aKeyword);
+end;
+
+
+Function TDiscriminator.HasKeyword(aKeyword : TDiscriminatorKeyword) : Boolean;
+
+begin
+  Result:=aKeyword in FKeywords;
+end;
+
+
+destructor TDiscriminator.destroy;
+
+begin
+  FreeAndNil(FMapping);
+  Inherited;
+end;
+
+
+procedure TXML.Set_Name(const aValue : string);
+
+begin
+  if (FName=aValue) then exit;
+  FName:=aValue;
+  AddKeyWord(xmkName);
+end;
+
+
+procedure TXML.Set_Namespace(const aValue : string);
+
+begin
+  if (FNamespace=aValue) then exit;
+  FNamespace:=aValue;
+  AddKeyWord(xmkNamespace);
+end;
+
+
+procedure TXML.Set_Prefix(const aValue : string);
+
+begin
+  if (FPrefix=aValue) then exit;
+  FPrefix:=aValue;
+  AddKeyWord(xmkPrefix);
+end;
+
+
+procedure TXML.Set_Attribute(const aValue : Boolean);
+
+begin
+  if (FAttribute=aValue) then exit;
+  FAttribute:=aValue;
+  AddKeyWord(xmkAttribute);
+end;
+
+
+procedure TXML.Set_Wrapped(const aValue : Boolean);
+
+begin
+  if (FWrapped=aValue) then exit;
+  FWrapped:=aValue;
+  AddKeyWord(xmkWrapped);
+end;
+
+
+procedure TXML.AddKeyword(aKeyword : TXMLKeyword);
+
+begin
+  Include(FKeywords,aKeyword);
+end;
+
+
+procedure TXML.RemoveKeyword(aKeyword : TXMLKeyword);
+
+begin
+  Exclude(FKeywords,aKeyword);
+end;
+
+
+Function TXML.HasKeyword(aKeyword : TXMLKeyword) : Boolean;
+
+begin
+  Result:=aKeyword in FKeywords;
+end;
+
+
+destructor TXML.destroy;
+
+begin
+  Inherited;
+end;
+
+
+function TSecurityScheme.Get_Flows : TOAuthFlows;
+
+begin
+  if Not assigned(FFlows) then
+    begin
+    FFlows:=TOAuthFlows.Create(Self,'flows');
+    AddKeyWord(sskFlows);
+    end;
+  Result:=FFlows;
+end;
+
+
+procedure TSecurityScheme.Set_Type_(const aValue : string);
+
+begin
+  if (FType_=aValue) then exit;
+  FType_:=aValue;
+  AddKeyWord(sskType);
+end;
+
+
+procedure TSecurityScheme.Set_Description(const aValue : string);
+
+begin
+  if (FDescription=aValue) then exit;
+  FDescription:=aValue;
+  AddKeyWord(sskDescription);
+end;
+
+
+procedure TSecurityScheme.Set_Name(const aValue : string);
+
+begin
+  if (FName=aValue) then exit;
+  FName:=aValue;
+  AddKeyWord(sskName);
+end;
+
+
+procedure TSecurityScheme.Set_In_(const aValue : string);
+
+begin
+  if (FIn_=aValue) then exit;
+  FIn_:=aValue;
+  AddKeyWord(sskIn);
+end;
+
+
+procedure TSecurityScheme.Set_Scheme(const aValue : string);
+
+begin
+  if (FScheme=aValue) then exit;
+  FScheme:=aValue;
+  AddKeyWord(sskScheme);
+end;
+
+
+procedure TSecurityScheme.Set_BearerFormat(const aValue : string);
+
+begin
+  if (FBearerFormat=aValue) then exit;
+  FBearerFormat:=aValue;
+  AddKeyWord(sskBearerFormat);
+end;
+
+
+procedure TSecurityScheme.Set_Flows(const aValue : TOAuthFlows);
+
+begin
+  if (FFlows=aValue) then exit;
+  FreeAndNil(FFlows);
+  FFlows:=aValue;
+  AddKeyWord(sskFlows);
+end;
+
+
+procedure TSecurityScheme.Set_OpenIdConnectUrl(const aValue : string);
+
+begin
+  if (FOpenIdConnectUrl=aValue) then exit;
+  FOpenIdConnectUrl:=aValue;
+  AddKeyWord(sskOpenIdConnectUrl);
+end;
+
+
+procedure TSecurityScheme.AddKeyword(aKeyword : TSecuritySchemeKeyword);
+
+begin
+  Include(FKeywords,aKeyword);
+end;
+
+
+procedure TSecurityScheme.RemoveKeyword(aKeyword : TSecuritySchemeKeyword);
+
+begin
+  Exclude(FKeywords,aKeyword);
+end;
+
+
+Function TSecurityScheme.HasKeyword(aKeyword : TSecuritySchemeKeyword) : Boolean;
+
+begin
+  Result:=aKeyword in FKeywords;
+end;
+
+
+destructor TSecurityScheme.destroy;
+
+begin
+  FreeAndNil(FFlows);
+  Inherited;
+end;
+
+
+function TSecuritySchemeOrReference.GetReference : TReference;
+
+begin
+  if Not Assigned(FReference) then
+    FReference:=TReference.Create(Self,'');
+  Result:=FReference;
+end;
+
+
+destructor TSecuritySchemeOrReference.destroy;
+
+begin
+  FreeAndNil(FReference);
+  Inherited;
+end;
+
+
+function TSecuritySchemeOrReference.HasReference : Boolean;
+
+begin
+  Result:=Assigned(FReference);
+end;
+
+
+function TSecuritySchemeOrReferenceMap.GetObject(const aName : TJSONStringType) : TSecuritySchemeOrReference;
+
+begin
+  Result:=TSecuritySchemeOrReference(GetObjectByName(aName));
+end;
+
+
+constructor TSecuritySchemeOrReferenceMap.Create(aParent : TBaseOpenAPIObject; const aPathComponent : TJSONStringType);
+
+begin
+  Inherited Create(aParent,aPathComponent,TSecuritySchemeOrReference);
+end;
+
+
+function TSecuritySchemeOrReferenceMap.AddItem(const aName : TJSONStringType) : TSecuritySchemeOrReference;
+
+begin
+  Result:=CreateNew(aName) as TSecuritySchemeOrReference;
+//  Add(aName,Result);
+end;
+
+
+function TOAuthFlows.Get_Implicit : TOAuthFlow;
+
+begin
+  if Not assigned(FImplicit) then
+    begin
+    FImplicit:=TOAuthFlow.Create(Self,'implicit');
+    AddKeyWord(ofskImplicit);
+    end;
+  Result:=FImplicit;
+end;
+
+
+function TOAuthFlows.Get_Password : TOAuthFlow;
+
+begin
+  if Not assigned(FPassword) then
+    begin
+    FPassword:=TOAuthFlow.Create(Self,'password');
+    AddKeyWord(ofskPassword);
+    end;
+  Result:=FPassword;
+end;
+
+
+function TOAuthFlows.Get_ClientCredentials : TOAuthFlow;
+
+begin
+  if Not assigned(FClientCredentials) then
+    begin
+    FClientCredentials:=TOAuthFlow.Create(Self,'clientCredentials');
+    AddKeyWord(ofskClientCredentials);
+    end;
+  Result:=FClientCredentials;
+end;
+
+
+function TOAuthFlows.Get_ClientAuthorizationCode : TOAuthFlow;
+
+begin
+  if Not assigned(FClientAuthorizationCode) then
+    begin
+    FClientAuthorizationCode:=TOAuthFlow.Create(Self,'clientAuthorizationCode');
+    AddKeyWord(ofskClientAuthorizationCode);
+    end;
+  Result:=FClientAuthorizationCode;
+end;
+
+
+procedure TOAuthFlows.Set_Implicit(const aValue : TOAuthFlow);
+
+begin
+  if (FImplicit=aValue) then exit;
+  FreeAndNil(FImplicit);
+  FImplicit:=aValue;
+  AddKeyWord(ofskImplicit);
+end;
+
+
+procedure TOAuthFlows.Set_Password(const aValue : TOAuthFlow);
+
+begin
+  if (FPassword=aValue) then exit;
+  FreeAndNil(FPassword);
+  FPassword:=aValue;
+  AddKeyWord(ofskPassword);
+end;
+
+
+procedure TOAuthFlows.Set_ClientCredentials(const aValue : TOAuthFlow);
+
+begin
+  if (FClientCredentials=aValue) then exit;
+  FreeAndNil(FClientCredentials);
+  FClientCredentials:=aValue;
+  AddKeyWord(ofskClientCredentials);
+end;
+
+
+procedure TOAuthFlows.Set_ClientAuthorizationCode(const aValue : TOAuthFlow);
+
+begin
+  if (FClientAuthorizationCode=aValue) then exit;
+  FreeAndNil(FClientAuthorizationCode);
+  FClientAuthorizationCode:=aValue;
+  AddKeyWord(ofskClientAuthorizationCode);
+end;
+
+
+procedure TOAuthFlows.AddKeyword(aKeyword : TOAuthFlowsKeyword);
+
+begin
+  Include(FKeywords,aKeyword);
+end;
+
+
+procedure TOAuthFlows.RemoveKeyword(aKeyword : TOAuthFlowsKeyword);
+
+begin
+  Exclude(FKeywords,aKeyword);
+end;
+
+
+Function TOAuthFlows.HasKeyword(aKeyword : TOAuthFlowsKeyword) : Boolean;
+
+begin
+  Result:=aKeyword in FKeywords;
+end;
+
+
+destructor TOAuthFlows.destroy;
+
+begin
+  FreeAndNil(FImplicit);
+  FreeAndNil(FPassword);
+  FreeAndNil(FClientCredentials);
+  FreeAndNil(FClientAuthorizationCode);
+  Inherited;
+end;
+
+
+function TOauthFlow.Get_Scopes : TStrings;
+
+begin
+  if Not assigned(FScopes) then
+    begin
+    FScopes:=TStringList.Create();
+    AddKeyWord(ofkScopes);
+    end;
+  Result:=FScopes;
+end;
+
+
+procedure TOauthFlow.Set_AuthorizationUrl(const aValue : string);
+
+begin
+  if (FAuthorizationUrl=aValue) then exit;
+  FAuthorizationUrl:=aValue;
+  AddKeyWord(ofkAuthorizationUrl);
+end;
+
+
+procedure TOauthFlow.Set_TokenURL(const aValue : string);
+
+begin
+  if (FTokenURL=aValue) then exit;
+  FTokenURL:=aValue;
+  AddKeyWord(ofkTokenURL);
+end;
+
+
+procedure TOauthFlow.Set_RefreshURL(const aValue : string);
+
+begin
+  if (FRefreshURL=aValue) then exit;
+  FRefreshURL:=aValue;
+  AddKeyWord(ofkRefreshURL);
+end;
+
+
+procedure TOauthFlow.Set_Scopes(const aValue : TStrings);
+
+begin
+  if (FScopes=aValue) then exit;
+  FreeAndNil(FScopes);
+  FScopes:=aValue;
+  AddKeyWord(ofkScopes);
+end;
+
+
+procedure TOauthFlow.AddKeyword(aKeyword : TOauthFlowKeyword);
+
+begin
+  Include(FKeywords,aKeyword);
+end;
+
+
+procedure TOauthFlow.RemoveKeyword(aKeyword : TOauthFlowKeyword);
+
+begin
+  Exclude(FKeywords,aKeyword);
+end;
+
+
+Function TOauthFlow.HasKeyword(aKeyword : TOauthFlowKeyword) : Boolean;
+
+begin
+  Result:=aKeyword in FKeywords;
+end;
+
+
+destructor TOauthFlow.destroy;
+
+begin
+  FreeAndNil(FScopes);
+  Inherited;
+end;
+
+
+
+
+function THeaderOrReference.GetReference : TReference;
+
+begin
+  if Not Assigned(FReference) then
+    FReference:=TReference.Create(Self,'');
+  Result:=FReference;
+end;
+
+
+destructor THeaderOrReference.destroy;
+
+begin
+  FreeAndNil(FReference);
+  Inherited;
+end;
+
+
+function THeaderOrReference.HasReference : Boolean;
+
+begin
+  Result:=Assigned(FReference);
+end;
+
+
+function THeaderOrReferenceMap.GetObject(const aName : TJSONStringType) : THeaderOrReference;
+
+begin
+  Result:=THeaderOrReference(GetObjectByName(aName));
+end;
+
+
+constructor THeaderOrReferenceMap.Create(aParent : TBaseOpenAPIObject; const aPathComponent : TJSONStringType);
+
+begin
+  Inherited Create(aParent,aPathComponent,THeaderOrReference);
+end;
+
+
+function THeaderOrReferenceMap.AddItem(const aName : TJSONStringType) : THeaderOrReference;
+
+begin
+  Result:=CreateNew(aName) as THeaderOrReference;
+//  Add(aName,Result);
+end;
+
+
+
+function TCallbackOrReference.GetReference : TReference;
+
+begin
+  if Not Assigned(FReference) then
+    FReference:=TReference.Create(Self,'');
+  Result:=FReference;
+end;
+
+
+destructor TCallbackOrReference.destroy;
+
+begin
+  FreeAndNil(FReference);
+  Inherited;
+end;
+
+
+function TCallbackOrReference.HasReference : Boolean;
+
+begin
+  Result:=Assigned(FReference);
+end;
+
+
+function TCallbackOrReferenceMap.GetObject(const aName : TJSONStringType) : TCallbackOrReference;
+
+begin
+  Result:=TCallbackOrReference(GetObjectByName(aName));
+end;
+
+
+constructor TCallbackOrReferenceMap.Create(aParent: TBaseOpenAPIObject; const aPathComponent : TJSONStringType);
+
+begin
+  Inherited Create(aParent,aPathComponent,TCallbackOrReference);
+end;
+
+
+function TCallbackOrReferenceMap.AddItem(const aName : TJSONStringType) : TCallbackOrReference;
+
+begin
+  Result:=CreateNew(aName) as TCallbackOrReference;
+//  Add(aName,Result);
+end;
+
+{ TNamedStringList }
+
+function TNamedStringList.CreateNew(const aName: TJSONStringType): TObject;
+begin
+  Result:=TStringList.Create;
+end;
+
+function TSecurityRequirement.GetRequirements(aName : TJSONStringType): TStrings;
+begin
+  Result:=TStrings(FList.GetObjectByName(aName))
+end;
+
+function TSecurityRequirement.GetCount: Integer;
+begin
+  Result:=FList.Count;
+end;
+
+function TSecurityRequirement.GetList(aIndex : Integer): TStrings;
+begin
+  Result:=FList.NamedObjects[aIndex].Object_ as TStrings;
+end;
+
+function TSecurityRequirement.GetName(aIndex : Integer): String;
+begin
+  Result:=FList.Names[aIndex];
+end;
+
+constructor TSecurityRequirement.Create(aParent : TBaseOpenAPIObject; const aPathComponent : TJSONStringType);
+begin
+  Inherited Create(aParent,aPathComponent);
+  FList:=TNamedStringList.Create(aParent,aPathComponent,TStringList);
+end;
+
+destructor TSecurityRequirement.destroy;
+begin
+  FreeAndNil(FList);
+  Inherited;
+end;
+
+function TSecurityRequirement.AddItem(const AName: TJSONStringType): TStrings;
+begin
+  Result:=TStringList.Create();
+  Flist.Add(aName,Result);
+end;
+
+
+function TSecurityRequirementList.GetObj(aIndex : Integer): TSecurityRequirement;
+
+begin
+  Result:=TSecurityRequirement(Items[aIndex]);
+end;
+
+
+procedure TSecurityRequirementList.SetObj(aIndex : Integer; aValue : TSecurityRequirement);
+
+begin
+  Items[aIndex]:=aValue;
+end;
+
+
+function TSecurityRequirementList.ToArray : TSecurityRequirementArray;
+
+var
+  I : Integer;
+
+begin
+  Result:=[];
+  SetLength(Result,Count);
+  For I:=0 to Count-1 do
+    Result[I]:=GetObj(I);
+end;
+
+procedure TSecurityRequirementList.AddSecurity(aSecurity: TSecurityRequirement);
+begin
+  Add(aSecurity);
+end;
+
+function TSecurityRequirementList.AddSecurity(aParent: TBaseOpenAPIObject): TSecurityRequirement;
+begin
+  Result:=TSecurityRequirement.Create(aParent,Format('[%d]',[count]));
+  AddSecurity(Result);
+end;
+
+{ TBaseOpenAPIObject }
+
+function TBaseOpenAPIObject.CreateChildrenList: TBaseOpenAPIObjectList;
+begin
+  Result:=TBaseOpenAPIObjectList.Create(False);
+end;
+
+procedure TBaseOpenAPIObject.AddChild(aChild: TBaseOpenAPIObject);
+begin
+  if not Assigned(FChildren) then
+    FChildren:=CreateChildrenList;
+  FChildren.Add(aChild);
+end;
+
+procedure TBaseOpenAPIObject.RemoveChild(aChild: TBaseOpenAPIObject);
+begin
+  if Assigned(FChildren) then
+    FChildren.Remove(aChild);
+end;
+
+procedure TBaseOpenAPIObject.SetPathComponent(const aValue: TJSONStringType);
+begin
+  FPathComponent:=aValue;
+end;
+
+constructor TBaseOpenAPIObject.create(aParent: TBaseOpenAPIObject; aPathComponent : TJSONStringType);
+begin
+  FParent:=aParent;
+  FPathComponent:=aPathComponent;
+  if assigned(FParent) then
+    FParent.AddChild(Self);
+end;
+
+destructor TBaseOpenAPIObject.destroy;
+
+begin
+  if Assigned(FParent) then
+     FParent.RemoveChild(Self);
+  FreeAndNil(FChildren);
+  inherited destroy;
+end;
+
+function TBaseOpenAPIObject.GetChildByPathComponent(const aName: TJSONStringType): TBaseOpenAPIObject;
+
+var
+  I : Integer;
+begin
+  Result:=Nil;
+  if Not Assigned(FChildren) then
+    exit;
+  I:=FChildren.Count-1;
+  While (I>=0) and (FChildren[I].PathComponent<>aName) do
+    Dec(I);
+  if I>=0 then
+    Result:=FChildren[I];
+end;
+
+function TBaseOpenAPIObject.Find(const aPath: TJSONStringType): TBaseOpenAPIObject;
+
+var
+  Child,Sub : TJSONStringType;
+  P : Integer;
+
+begin
+  if aPath='' then
+    Exit(Self);
+  P:=Pos('/',aPath);
+  If P=0 then
+    P:=Length(aPath)+1;
+  Child:=Copy(aPath,1,P-1);
+  Sub:=Copy(aPath,P+1,Length(aPath)-P);
+  Result:=GetChildByPathComponent(Child);
+  if Assigned(Result) then
+    Result:=Result.Find(Sub);
+end;
+
+function TBaseOpenAPIObject.PathComponent: TJSONStringType;
+begin
+  Result:=FPathComponent;
+end;
+
+function TBaseOpenAPIObject.Path: TJSONStringType;
+
+var
+  O : TBaseOpenAPIObject;
+
+begin
+  Result:=EncodeJSONPointer(PathComponent);
+  O:=Parent;
+  While Assigned(O) do
+    begin
+    if (O.PathComponent<>'') then
+      Result:=O.PathComponent+'/'+Result;
+    O:=O.Parent;
+    end;
+end;
+
+{ TBaseOpenAPIObjectList }
+
+function TBaseOpenAPIObjectList.GetObject(aIndex : Integer): TBaseOpenAPIObject;
+begin
+  Result:=Items[aIndex] as TBaseOpenAPIObject;
+end;
+
+
+end.
+

+ 1392 - 0
packages/fcl-openapi/src/fpopenapi.pascaltypes.pp

@@ -0,0 +1,1392 @@
+{
+    This file is part of the Free Component Library (FCL)
+    Copyright (c) 2024 by Michael Van Canneyt ([email protected])
+
+    Data Structures to generate pascal code based on OpenAPI data
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+unit fpopenapi.pascaltypes;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses
+{$IFDEF FPC_DOTTEDUNITS}
+  System.Classes, System.SysUtils, System.Types, System.Contnrs,
+{$ELSE}  
+  Classes, SysUtils, Types, contnrs,
+{$ENDIF}
+  fpjson.schema.types,
+  fpjson.schema.schema,
+  fpjson.schema.pascaltypes,
+  fpopenapi.objects,
+  fpopenapi.types;
+
+const
+  ptAPIComponent = ptSchemaStruct;
+
+type
+  EGenAPI = Class(Exception);
+
+  TAPIService = Class;
+  TAPIServiceMethod = Class;
+  TAPIData = class;
+
+  TAPIProperty = class(TPascalPropertyData);
+
+  { TAPITypeData }
+
+  TAPITypeData = Class(TPascalTypeData)
+  private
+    FIndex: Integer;
+  protected
+    function CreateProperty(const aAPIName, aPascalName: string): TPascalPropertyData; override;
+  public
+    function AddProperty(const aApiName, aPascalName: String): TAPIProperty; reintroduce;
+    // Index in openAPI #components
+    Property Index : Integer Read FIndex;
+  end;
+
+  { TAPIServiceMethod }
+
+  { TAPIServiceMethodParam }
+  TParamLocation = (plQuery,plPath);
+
+  TAPIServiceMethodParam = Class(TObject)
+  private
+    FArgType: TPropertyType;
+    FDefaultValue: String;
+    FName: String;
+    FOriginalName: String;
+    FParameter: TParameter;
+    FTypeName: String;
+    function GetAsStringValue: String;
+    function Getlocation: TParamLocation;
+  Public
+    Constructor create(aArgType : TPropertyType; aOriginalName : String; aName : String; aTypeName : String; aParam : TParameter);
+    // Argument type
+    Property ArgType : TPropertyType Read FArgType;
+    // Assigned pascal name
+    Property Name : String Read FName;
+    // Original openAPI name. Can be empty
+    Property OriginalName : String Read FOriginalName;
+    // Pascal type name
+    Property TypeName : String Read FTypeName;
+    // The OpenAPI parameter
+    Property Parameter : TParameter Read FParameter;
+    // Location of this parameter
+    Property Location : TParamLocation Read Getlocation;
+    // Pascal expression to return the parameter value as a string
+    Property AsStringValue : String Read GetAsStringValue;
+    // Pascal expression with default value for this parameter
+    Property DefaultValue : String Read FDefaultValue Write FDefaultValue;
+  end;
+
+
+  TAPIServiceMethod = Class(TObject)
+  private
+    FBodyType: String;
+    FMethodName: String;
+    FOperation: TApiOperation;
+    FResultCallbackType: String;
+    FResultClassType: String;
+    FResultDtoType: String;
+    FResultType: String;
+    FService: TAPIService;
+    FPath : TPathItem;
+    FParams : TFPObjectList;
+    function GetParam(aIndex : Integer): TAPIServiceMethodParam;
+    function GetParamCount: Integer;
+  protected
+    // override this if you want to subclass the parameter
+    function CreateParam(const aType: TPascaltype; const aOriginalName, aName, aTypeName: String; aParam: TParameter     ): TAPIServiceMethodParam; virtual;
+    Procedure SortParams;
+  Public
+    Constructor create (aOperation : TApiOperation; aPath : TPathItem; aService : TAPIService; const aMethod : String);
+    Destructor Destroy; override;
+    // Add a parameter
+    function AddParam(const aType: TPascalType; const aOriginalName, aName, aTypeName: String; aParam: TParameter
+      ): TAPIServiceMethodParam;
+    // Find parameter methods by name.
+    Function ParamByNAme(aOriginalName : String) : TAPIServiceMethodParam;
+    // Does this class have parameters with location 'path'
+    function HasPathParam: Boolean;
+    // Does this class have parameters with location 'query'
+    Function HasQueryParam : Boolean;
+    // Does this method have parameters with default values ?
+    Function HasOptionalParams : Boolean;
+
+    // Pascal type of request body. May be empty.
+    Property RequestBodyType : String Read FBodyType Write FBodyType;
+    // Result type. Can be empty
+    Property ResultType : String Read FResultType Write FResultType;
+    // Component result class type.
+    Property ResultClassType : String Read FResultClassType Write FResultClassType;
+    // Component result Dto type
+    Property ResultDtoType : String Read FResultDtoType Write FResultDtoType;
+    // Callback type for result.
+    Property ResultCallBackType : String Read FResultCallbackType write FResultCallBackType;
+    // OpenAPI Operation for this method.
+    Property Operation : TApiOperation Read FOperation;
+    // Pascal name for the method.
+    Property MethodName : String Read FMethodName;
+    // Service this method belongs to.
+    Property Service : TAPIService Read FService;
+    // OpenAPI Path of this method.
+    Property Path : TPathItem Read FPath;
+    // indexed access to parameters
+    Property Param[aIndex : Integer] : TAPIServiceMethodParam Read GetParam;
+    // Number of parameters.
+    Property ParamCount: Integer Read GetParamCount;
+  end;
+
+  TAPIService = Class(TObject)
+  private
+    FMethods : TFPObjectList;
+    FNeedsAuthentication: Boolean;
+    FServiceImplementationClassName: String;
+    FServiceInterfaceName: string;
+    FServiceName: string;
+    FServiceParentInterface: String;
+    FServiceUUID: string;
+    function GetMethod(aIndex : Integer): TAPIServiceMethod;
+    function GetMethodCount: Integer;
+    function GetServiceImplementationClassName: String;
+    function GetServiceInterfaceName: string;
+    function GetServiceUUID: string;
+  protected
+    // Override this if you wish to create a descendant of TAPIserviceMethod
+    function CreateMethod(aOperation: TAPIOperation; aPath: TPathItem; const aName: String): TAPIserviceMethod; virtual;
+    // Sort the methods on their name
+    procedure SortMethods;
+  public
+    constructor create(const aServiceName : string);
+    destructor destroy; override;
+    // Add a method to the list of methods.
+    Function AddMethod(const aName : String; aOperation : TAPIOperation; aPath : TPathItem) : TAPIserviceMethod;
+    // Does this service need authentication ?
+    Property NeedsAuthentication : Boolean read FNeedsAuthentication Write FNeedsAuthentication;
+    // Pascal name of the service
+    Property ServiceName : string Read FServiceName;
+    // Interface name of the service.
+    Property ServiceInterfaceName : string Read GetServiceInterfaceName Write FServiceInterfaceName;
+    // Parent interface for the service interface
+    Property ServiceParentInterface : String Read FServiceParentInterface Write FServiceParentInterface;
+    // Service interface UUID
+    Property ServiceUUID : string Read GetServiceUUID Write FServiceUUID;
+    // Service interface implementation Class Name
+    Property ServiceImplementationClassName : String Read GetServiceImplementationClassName Write FServiceImplementationClassName;
+    // Indexed access to methods.
+    Property Methods[aIndex : Integer]: TAPIServiceMethod Read GetMethod;
+    // Number of methods.
+    Property MethodCount : Integer Read GetMethodCount;
+  end;
+
+  { TAPIData }
+
+  TAPIData = Class(TSchemaData)
+  Private
+    FInterfaceArrayType: String;
+    FServiceNamePrefix: String;
+    FServiceNameSuffix: String;
+    FServiceParentInterface: String;
+    FServices : TFPObjectList;
+    FServiceOperationMap : TFPStringHashTable;
+    FAPI : TOpenAPI;
+    FVoidResultCallbackType: String;
+    function AllowOperation(aKeyword: TPathItemOperationKeyword; aOperation: TAPIOperation): boolean;
+    function GetAPITypeCount: Integer;
+    function GetService(aIndex : Integer): TAPIService;
+    function GetServiceCount: Integer;
+    function GetTypeData(aIndex : Integer): TAPITypeData;
+    function GetVoidResultCallbackType: String;
+  Protected
+    //
+    // Type management
+    //
+    procedure FinishAutoCreatedType(aName: string; aType: TPascalTypeData; lElementTypeData: TPascalTypeData); override;
+    // Called after a new type is created.
+    procedure ConfigType(aType: TAPITypeData); virtual;
+    // Find requested name type in API types, based on openAPI name.
+    function RawToNameType(const aName: string; aNameType: TNameType): string; virtual;
+    // Check whether a type needs to be serialized (i.e. is sent to REST service)
+    Function NeedsSerialize(aData : TAPITypeData) : Boolean; virtual;
+    // Check whether a type needs to be de-serialized (i.e. is received from the REST service)
+    Function NeedsDeSerialize(aData : TAPITypeData) : Boolean; virtual;
+    // Is the request body application/json or no request body
+    function IsRequestBodyApplicationJSON(aOperation: TAPIOperation): Boolean;
+    // Is the response content application/json or no response content
+    function IsResponseContentApplicationJSON(aOperation: TAPIOperation): boolean;
+   //
+    // Service/Method management
+    //
+    // Generate the name of the service, based on URL/Operation. Takes into account the mapping.
+    function GenerateServiceName(const aUrl : String; const aPath: TPathItem; aOperation: TAPIOperation): String;virtual;
+    // Create a new service definition. Override this if you want to subclass it.
+    function CreateService(const aName: String): TAPIService; virtual;
+    // Add a service
+    function AddService(const aName: String) : TAPIService;
+    // Configure a service
+    procedure ConfigService(const aService: TAPIService); virtual;
+    // Generate the name of the method, based on URL/Operation. Takes into account the mapping.
+    function GenerateServiceMethodName(const aUrl : String; const aPath: TPathItem; aOperation: TAPIOperation): String; virtual;
+    // Return the request body type. The application/json content type is used.
+    function GetMethodRequestBodyType(aMethod: TAPIServiceMethod): string; virtual;
+    // Return the method result type
+    function GetMethodResultType(aMethod: TAPIServiceMethod; aNameType: TNameType): String; virtual;
+    // Return the method result callback name
+    function GenerateMethodResultCallBackName(aMethod: TAPIServiceMethod): String; virtual;
+    // Configure the service method. Called after it is created.
+    procedure ConfigureServiceMethod(aService: TAPIService; aMethod: TAPIServiceMethod); virtual;
+    // Add a parameter to a method.
+    function AddServiceMethodParam(aService: TAPIservice; aMethod: TAPIServiceMethod; Idx: Integer; aParam: TParameterOrReference   ): TAPIServiceMethodParam; virtual;
+    // Check the input of various operations of a OpenAPI path item. Used in determining the need for serialization
+    function CheckOperationsInput(aPath: TPathItem; aData: TAPITypeData): Boolean;
+    // Check the output of various operations of a OpenAPI path item. Used in determining the need for deserialization
+    function CheckOperationsOutput(aPath: TPathItem; aData: TAPITypeData): Boolean;
+    // Check input/output for serialization
+    procedure CheckInputOutput;
+  Public
+    // Create. API must be alive while the data is kept alive.
+    constructor Create(aAPI : TOpenAPI); reintroduce;
+    // Destroy
+    destructor Destroy; override;
+    // Create default type maps (integer,string etc.)
+    Procedure CreateDefaultTypeMaps; virtual;
+    // Create default API type maps (#components in openapi)
+    Procedure CreateDefaultAPITypeMaps;
+    // Create service defs from paths. Call RecordMethodNameMap first)
+    Procedure CreateServiceDefs; virtual;
+    // Get schema element typename of aRef. For components, return requested name
+    function GetRefSchemaTypeName(const aRef: String; aNameType : TNameType): string; virtual;
+    // Create a new API type. You can override this to return a descendent class
+    function CreatePascalType(aIndex: integer; aPascalType : TPascaltype; const aAPIName, aPascalName: String; aSchema: TJSONSchema): TAPITypeData; override;
+    // Is the schema an API component ?
+    Function IsAPIComponent(aSchema : TJSONSchema) : Boolean;
+    // Is the schema an array of API components ?
+    Function IsAPIComponentArray(aSchema : TJSONSchema) : Boolean;
+    // Get the specified type name of a schema
+    function GetSchemaTypeName(aSchema : TJSONSchema; aNameType : TNameType) : String;
+    // Apply the UUIDs to the API types. Call after CreateDefaultAPITypeMaps
+    procedure ApplyUUIDMap(aMap: TStrings);
+    {
+      Store the service/maps for operations. Call before CreateServiceDefs
+      an entry is either
+      operationID=ServiceName[.MethodName]
+      or
+      HTTPMethod.Path=ServiceName[.MethodName]
+    }
+    procedure RecordMethodNameMap(aMap: TStrings);
+    // Index of service with given ServiceName. Return -1 if not found.
+    function IndexOfService(const aName : String) : Integer;
+    // Find service with given ServiceName. Can return Nil
+    function FindService(const aName : String) : TAPIService;
+    // Find service with given ServiceName. Raise exception if not found
+    function GetServiceByName(const aName : String) : TAPIService;
+    // Indexed access to services
+    Property Services[aIndex :Integer] : TAPIService Read GetService;
+    // Number of generated services
+    Property ServiceCount : Integer Read GetServiceCount;
+    // Return index of named API type (name as in OpenApi). Return -1 if not found.
+    function IndexOfAPIType(const aName: String): integer;
+    // Find API type by name (name as known in OpenApi). Return nil if not found.
+    function FindApiType(const aName: String): TAPITypeData;
+    // Find API type by name (name as known in OpenApi). Raise exception if not found.
+    function GetAPIType(const aName: String): TAPITypeData;
+    // #components Types by name
+    Property ApiNamedTypes[aName : String] : TAPITypeData Read GetApiType;
+    // #components Types by index
+    Property APITypes[aIndex : Integer] : TAPITypeData Read GetTypeData;
+    // #components Type count
+    Property APITypeCount : Integer Read GetAPITypeCount;
+    // The api we generate code for.
+    Property API : TOpenAPI Read FAPI;
+    // Prefix to use when generating service names (will still have I prepended for interface definition)
+    Property ServiceNamePrefix : String Read FServiceNamePrefix Write FServiceNamePrefix;
+    // Suffix to use when generating service names (will still have I prepended for interface definition)
+    // By default, this is 'Service'
+    Property ServiceNameSuffix : String Read FServiceNameSuffix Write FServiceNameSuffix;
+    // Parent interface for services. Applied to all services
+    Property ServiceParentInterface : String Read FServiceParentInterface Write FServiceParentInterface;
+    // Void result type callback name
+    Property VoidResultCallbackType : String Read GetVoidResultCallbackType Write FVoidResultCallbackType;
+    // Name of generic Interface that implements an array
+    Property InterfaceArrayType : String Read FInterfaceArrayType Write FInterfaceArrayType;
+  end;
+
+implementation
+
+{$IFDEF FPC_DOTTEDUNITS}
+uses System.StrUtils;
+{$ELSE}
+uses strutils;
+{$ENDIF}
+
+function PrettyPrint(S : String) : String;
+
+begin
+  Result:=S;
+  if Length(Result)>0 then
+    Result[1]:=UpCase(Result[1]);
+end;
+
+{ TAPITypeData }
+
+
+function CompareServiceName(Item1, Item2: Pointer): Integer;
+
+var
+  lService1 : TAPIService absolute Item1;
+  lService2 : TAPIService absolute Item2;
+
+begin
+  Result:=CompareText(lService1.ServiceName,lService2.ServiceName);
+end;
+
+function CompareMethodName(Item1, Item2: Pointer): Integer;
+
+var
+  lMethod1 : TAPIServiceMethod absolute Item1;
+  lMethod2 : TAPIServiceMethod absolute Item2;
+
+begin
+  Result:=CompareText(lMethod1.MethodName,lMethod2.MethodName);
+end;
+
+function CompareParamName(Item1, Item2: Pointer): Integer;
+
+var
+  lParam1 : TAPIServiceMethodParam absolute Item1;
+  lParam2 : TAPIServiceMethodParam absolute Item2;
+begin
+  Result:=CompareText(lParam1.Name,lParam2.Name);
+end;
+
+
+{ TAPIServiceMethodParam }
+
+function TAPIServiceMethodParam.Getlocation: TParamLocation;
+begin
+  if FParameter.In_='query' then
+    Result:=plQuery
+  else
+    Result:=plPath;
+end;
+
+function TAPIServiceMethodParam.GetAsStringValue: String;
+
+var
+  lType : TSchemaSimpleType;
+
+begin
+  lType:=TAPITypeData.ExtractFirstType(FParameter.Schema);
+  case lType of
+    sstInteger : Result:=Format('IntToStr(%s)',[Name]); // Also handles int64
+    sstString :  Result:=Name;
+    sstNumber : Result:=Format('FloatToStr(%s,cRestFormatSettings)',[Name]);
+    sstBoolean : Result:=Format('cRESTBooleans[%s]',[Name]);
+  else
+    Result:=Name;
+  end;
+end;
+
+constructor TAPIServiceMethodParam.create(aArgType: TPropertyType; aOriginalName: String; aName: String; aTypeName: String;
+  aParam: TParameter);
+begin
+  FArgType:=aArgType;
+  FOriginalName:=aOriginalName;
+  FName:=aName;
+  FTypeName:=aTypeName;
+  FParameter:=aParam;
+end;
+
+{ TAPIService }
+
+function TAPIService.GetMethod(aIndex : Integer): TAPIServiceMethod;
+begin
+  Result:=TAPIServiceMethod(FMethods[aIndex]);
+end;
+
+function TAPIService.GetMethodCount: Integer;
+begin
+  Result:=FMethods.Count;
+end;
+
+function TAPIService.GetServiceImplementationClassName: String;
+begin
+  Result:=FServiceImplementationClassName;
+  if Result='' then
+    Result:='T'+ServiceName;
+end;
+
+function TAPIService.GetServiceInterfaceName: string;
+begin
+  Result:=FServiceInterfaceName;
+  if Result='' then
+    Result:='I'+ServiceName;
+end;
+
+function TAPIService.GetServiceUUID: string;
+begin
+  if FServiceUUID='' then
+    FServiceUUID:=TGUID.NewGuid.ToString(False);
+  Result:=FServiceUUID;
+end;
+
+function TAPIService.CreateMethod(aOperation: TAPIOperation; aPath: TPathItem; const aName: String): TAPIserviceMethod;
+begin
+  Result:=TAPIserviceMethod.Create(aOperation,aPath,Self,aName);
+end;
+
+procedure TAPIService.SortMethods;
+begin
+  FMethods.Sort(@CompareMethodName);
+end;
+
+constructor TAPIService.create(const aServiceName: string);
+begin
+  FMethods:=TFPObjectList.Create(True);
+  FServiceName:=aServiceName;
+  FNeedsAuthentication:=True;
+end;
+
+destructor TAPIService.destroy;
+begin
+  FreeAndNil(FMethods);
+  inherited destroy;
+end;
+
+function TAPIService.AddMethod(const aName: String; aOperation: TAPIOperation; aPath : TPathItem): TAPIserviceMethod;
+begin
+  Result:=CreateMethod(aOperation,aPath,aName);
+  FMethods.Add(Result);
+end;
+
+{ TAPIServiceMethod }
+
+function TAPIServiceMethod.GetParam(aIndex : Integer): TAPIServiceMethodParam;
+begin
+  Result:=TAPIServiceMethodParam(FParams[aIndex]);
+end;
+
+function TAPIServiceMethod.GetParamCount: Integer;
+begin
+  Result:=FParams.Count;
+end;
+
+procedure TAPIServiceMethod.SortParams;
+begin
+   FParams.Sort(@CompareParamName);
+end;
+
+constructor TAPIServiceMethod.create(aOperation: TApiOperation;
+  aPath: TPathItem; aService: TAPIService; const aMethod: String);
+begin
+  FOperation:=aOperation;
+  FService:=aService;
+  FMethodName:=aMethod;
+  FPath:=aPath;
+  FParams:=TFPObjectList.Create(True);
+end;
+
+destructor TAPIServiceMethod.Destroy;
+begin
+  FreeAndNil(FParams);
+  inherited Destroy;
+end;
+
+function TAPIServiceMethod.CreateParam(const aType : TPascaltype; const aOriginalName,aName, aTypeName: String; aParam: TParameter): TAPIServiceMethodParam;
+
+begin
+  Result:=TAPIServiceMethodParam.Create(aType,aOriginalName,aName,aTypeName,aParam);
+end;
+
+function TAPIServiceMethod.AddParam(const aType : TPascalType; const aOriginalName,aName, aTypeName: String; aParam: TParameter): TAPIServiceMethodParam;
+
+begin
+  Result:=CreateParam(aType,aOriginalName,aName,aTypeName,aParam);
+  FParams.Add(Result);
+end;
+
+function TAPIServiceMethod.ParamByNAme(aOriginalName: String): TAPIServiceMethodParam;
+
+var
+  Idx : Integer;
+
+begin
+  Idx:=ParamCount-1;
+  While (Idx>=0) and Not SameText(Param[Idx].OriginalName,aOriginalName) do
+    Dec(Idx);
+  if Idx=-1 then
+    Result:=Nil
+  else
+    Result:=Param[Idx];
+end;
+
+function TAPIServiceMethod.HasPathParam: Boolean;
+
+var
+  I : Integer;
+
+begin
+  Result:=False;
+  For I:=0 to ParamCount-1 do
+    if Param[i].Location=plPath then
+      Exit(True);
+end;
+
+function TAPIServiceMethod.HasQueryParam: Boolean;
+
+var
+  I : Integer;
+
+begin
+  Result:=False;
+  For I:=0 to ParamCount-1 do
+    if Param[i].Location=plQuery then
+      Exit(True);
+end;
+
+function TAPIServiceMethod.HasOptionalParams: Boolean;
+var
+  I : Integer;
+
+begin
+  Result:=False;
+  For I:=0 to ParamCount-1 do
+    if (Param[i].DefaultValue<>'') then
+      Exit(True);
+end;
+
+{ TAPIData }
+
+function TAPIData.GetTypeData(aIndex : Integer): TAPITypeData;
+
+begin
+  Result:=TAPITypeData(Inherited Types[aIndex]);
+end;
+
+function TAPIData.GetVoidResultCallbackType: String;
+begin
+  Result:=FVoidResultCallbackType;
+  if Result='' then
+    Result:='TVoidResultCallBack';
+end;
+
+function TAPIData.CreatePascalType(aIndex: integer; aPascalType: TPascaltype; const aAPIName, aPascalName: String;
+  aSchema: TJSONSchema): TAPITypeData;
+begin
+  Result:=TAPITypeData.Create(aIndex,aPascalType,aAPIName,aPascalName,aSchema);
+end;
+
+function TAPIData.GetAPITypeCount: Integer;
+
+begin
+  Result:=TypeCount;
+end;
+
+function TAPIData.GetService(aIndex : Integer): TAPIService;
+
+begin
+  Result:=TAPIService(FServices[aIndex]);
+end;
+
+function TAPIData.GetServiceCount: Integer;
+
+begin
+  Result:=FServices.Count;
+end;
+
+function TAPIData.IndexOfAPIType(const aName : String): integer;
+
+begin
+  Result:=IndexOfSchemaType(aName);
+end;
+
+function TAPIData.FindApiType(const aName: String): TAPITypeData;
+
+var
+  Idx : Integer;
+
+begin
+  Result:=Nil;
+  Idx:=IndexOfApiType(aName);
+  if Idx<>-1 then
+    Result:=APITypes[Idx];
+end;
+
+function TAPIData.GetAPIType(const aName : String): TAPITypeData;
+
+begin
+  Result:=FindAPIType(aName);
+  if Result=Nil then
+    Raise EListError.CreateFmt('Unknown type: %s',[aName]);
+end;
+
+function TAPIData.CreateService(const aName: String): TAPIService;
+
+begin
+  Result:=TAPIService.Create(aName);
+end;
+
+procedure TAPIData.ConfigService(const aService : TAPIService);
+
+begin
+  aService.ServiceParentInterface:=Self.ServiceParentInterface;
+end;
+
+function TAPIData.AddService(const aName: String): TAPIService;
+
+begin
+  Result:=CreateService(aName);
+  FServices.Add(Result);
+end;
+
+constructor TAPIData.Create(aAPI: TOpenAPI);
+
+begin
+  Inherited Create;
+  FServices:=TFPObjectList.Create(True);
+  FServiceOperationMap:=TFPStringHashTable.Create;
+  FAPI:=aAPI;
+  FServiceNameSuffix:='Service';
+  FServiceNamePrefix:='';
+end;
+
+destructor TAPIData.Destroy;
+
+begin
+  FreeAndNil(FServices);
+  FreeAndNil(FServiceOperationMap);
+  inherited Destroy;
+end;
+
+procedure TAPIData.CreateDefaultTypeMaps;
+
+begin
+  DefineStandardPascalTypes;
+end;
+
+
+procedure TAPIData.ConfigType(aType :TAPITypeData);
+
+
+begin
+  aType.InterfaceName:=EscapeKeyWord(InterfaceTypePrefix+aType.SchemaName);
+  aType.InterfaceUUID:=TGUID.NewGUID.ToString(False);
+end;
+
+procedure TAPIData.ApplyUUIDMap(aMap : TStrings);
+
+var
+  I : Integer;
+  N,V : String;
+  lData : TAPITypeData;
+  lService : TAPIService;
+
+begin
+  if aMap.Count=0 then exit;
+  For I:=0 to aMap.Count-1 do
+    begin
+    aMap.GetNameValue(I,N,V);
+    lData:=FindApiType(N);
+    if assigned(lData) then
+      lData.InterfaceUUID:=V
+    else
+      begin
+      lService:=FindService(N);
+      if assigned(lService) then
+        lService.ServiceUUID:=V;
+      end;
+    end;
+end;
+
+procedure TAPIData.RecordMethodNameMap(aMap: TStrings);
+
+var
+  I : Integer;
+  N,V : String;
+
+begin
+  if aMap.Count=0 then exit;
+  For I:=0 to aMap.Count-1 do
+    begin
+    aMap.GetNameValue(I,N,V);
+    FServiceOperationMap.Add(N,V);
+    end;
+end;
+
+function TAPIData.IndexOfService(const aName: String): Integer;
+
+begin
+  Result:=FServices.Count-1;
+  While (Result>=0) and not SameText(aName,GetService(Result).ServiceName) do
+    Dec(Result);
+end;
+
+function TAPIData.FindService(const aName: String): TAPIService;
+
+var
+  Idx : Integer;
+
+begin
+  Result:=nil;
+  Idx:=IndexOfService(aName);
+  if Idx>=0 then
+    Result:=GetService(Idx);
+end;
+
+function TAPIData.GetServiceByName(const aName: String): TAPIService;
+
+begin
+  Result:=FindService(aName);
+  if Result=Nil then
+    Raise EGenAPI.CreateFmt('Unknown service: %s',[aName]);
+end;
+
+procedure TAPIData.CheckInputOutput;
+
+var
+  I: Integer;
+  lData : TAPITypeData;
+  lSerTypes : TSerializeTypes;
+
+begin
+  for I:=0 to TypeCount-1 do
+    begin
+    lSerTypes:=[];
+    lData:=APITypes[i];
+    if NeedsSerialize(lData) then
+      Include(lSerTypes,stSerialize);
+    if NeedsDeserialize(lData) then
+      Include(lSerTypes,stDeSerialize);
+    lData.SerializeTypes:=lSerTypes;
+    DoLog(etInfo,'%s needs serialize: %s, deserialize: %s',[lData.SchemaName,BoolToStr(stSerialize in lSerTypes,True),BoolToStr(stDeSerialize in lSerTypes,True)]);
+    end;
+end;
+
+procedure TAPIData.CreateDefaultAPITypeMaps;
+
+  Procedure AddProperties(aType : TAPITypeData);
+
+  var
+    I : Integer;
+
+  begin
+    for I:=0 to aType.Schema.Properties.Count-1 do
+      AddTypeProperty(aType,aType.Schema.Properties[i]);
+    aType.SortProperties;
+  end;
+
+var
+  I : Integer;
+  lName,lType : String;
+  lSchema : TJsonSchema;
+  lData : TAPITypeData;
+
+begin
+  For I:=0 to FAPI.Components.Schemas.Count-1 Do
+    begin
+    lName:=FAPI.Components.Schemas.Names[I];
+    lSchema:=FAPI.Components.Schemas.Schemas[lName];
+    if sstObject in lSchema.Validations.Types then
+      begin
+      lType:=EscapeKeyWord(ObjectTypePrefix+lName+ObjectTypeSuffix);
+      lData:=CreatePascalType(I,ptSchemaStruct,lName,lType,lSchema);
+      ConfigType(lData);
+      AddType(lName,lData);
+      AddToTypeMap(lName,lData);
+      end;
+    end;
+  // We do this here, so all API type references can be resolved
+  For I:=0 to APITypeCount-1 do
+    AddProperties(APITypes[i]);
+  // Finally, sort
+  CheckDependencies;
+  SortTypes;
+  CheckInputOutput;
+end;
+
+function TAPIData.GenerateServiceName(const aUrl: String; const aPath: TPathItem;
+  aOperation: TAPIOperation): String;
+
+  function CleanIdentifier(S : String) : String;
+
+  begin
+    Result:=StringReplace(S,' ','',[rfReplaceAll])
+  end;
+{
+  the maps contain ServiceName.MethodName.
+  We use ServiceName if there is an entry in the map.
+  if there is no entry in the map and there is 1 tag, we take the name of the tag.
+  if there is no tag, we take the first component of the URL path.
+}
+
+var
+  S,lTag,lFullName : String;
+  lStrings : TStringDynArray;
+
+begin
+  Result:='';
+  if (aOperation.Tags.Count=1) then
+    lTag:=ServiceNamePrefix+CleanIdentifier(aOperation.Tags[0])+ServiceNameSuffix
+  else
+    lTag:='';
+  if aOperation.OperationID<>'' then
+    lFullName:=FServiceOperationMap.Items[aOperation.OperationID]
+  else if LTag<>'' then
+    lFullName:=lTag+'.'+aOperation.OperationID
+  else
+    lFullName:=FServiceOperationMap.Items[aOperation.PathComponent+'.'+aURL];
+  if lFullName='' then
+    begin
+    lStrings:=SplitString(aURL,'/');
+    // First non-empty
+    For S in lStrings do
+      if (Result='') and (S<>'') then
+        Result:=S;
+    Result:=ServiceNamePrefix+PrettyPrint(Result)+ServiceNameSuffix;
+    end
+  else
+    begin
+    lStrings:=SplitString(lFullName,'.');
+    Result:=LStrings[0];
+    end;
+  if (aOperation.OperationID<>'') and (lFullName='') then
+    begin
+    S:=aOperation.OperationID;
+    DoLog(etWarning,'No mapping for %s: (Tag= "%s"), Generated: %s=%s.%s',[S,lTag,S,Result,S]);
+    end;
+end;
+
+function TAPIData.GenerateServiceMethodName(const aUrl: String;
+  const aPath: TPathItem; aOperation: TAPIOperation): String;
+
+(*
+  the maps contain ServiceName[.MethodName]
+  1. if there is a method name in either map: we use that.
+  2. if there is no method name in either map:
+     a. if there is an operation ID we use it as the method name.
+     b. if there is no operation ID, we use the operation HTTP method together with the url except the first path component.
+        Parameters are reduced to their names.
+        get /users/contacts/{Id} -> servicename "users" method "get_contacts_Id"
+*)
+
+var
+  S,lFullName : String;
+  lStrings : TStringDynArray;
+  I,J : Integer;
+
+begin
+  Result:='';
+  if aOperation.OperationID<>'' then
+    lFullName:=FServiceOperationMap.Items[aOperation.OperationID]
+  else
+    lFullName:=FServiceOperationMap.Items[aOperation.PathComponent+'.'+aURL];
+  if lFullName='' then
+    begin
+    Result:=aOperation.OperationID;
+    if Result='' then
+      begin
+      lStrings:=SplitString(aURL,'/');
+      Result:=aOperation.PathComponent;
+      for I:=1 to Length(lStrings)-1 do
+        begin
+        S:=lStrings[i];
+        S:=StringReplace(S,'{','',[rfReplaceAll]);
+        S:=StringReplace(S,'}','',[rfReplaceAll]);
+        For J:=1 to Length(S)-1 do
+          if not (Upcase(S[J]) in ['A'..'Z','0'..'9','_']) then
+        Result:=Result+'_'+S;
+        end;
+      end;
+    end
+  else
+    begin
+    lStrings:=SplitString(lFullName,'.');
+    Result:=LStrings[1];
+    end;
+  Result:=PrettyPrint(Result);
+end;
+
+function TAPIData.AddServiceMethodParam(aService: TAPIservice; aMethod : TAPIServiceMethod; Idx : Integer; aParam : TParameterOrReference) : TAPIServiceMethodParam;
+
+var
+  lOriginalName,lName,lTypeName : string;
+  lTypeData : TPascaltypeData;
+  lType : TPascalType;
+
+begin
+  if aParam.HasReference then
+    begin
+    lTypeName:=GetRefSchemaTypeName(aParam.Reference.Ref,ntPascal);
+    lName:='';
+    lOriginalName:='';
+    lType:=ptSchemaStruct;
+    end
+  else
+    begin
+    lTypeData:=GetSchemaTypeData(Nil,aParam.Schema,False);
+    lTypeName:=lTypeData.GetTypeName(ntPascal);
+    lType:=lTypeData.Pascaltype;
+    lOriginalName:=aParam.Name;
+    lName:='a'+PrettyPrint(lOriginalName);
+    end;
+  if lName='' then
+    lName:=Format('aParam%d',[Idx]);
+
+  Result:=aMethod.AddParam(lType,lOriginalName,lName,lTypeName,aParam);
+  if aParam.Schema.MetaData.HasKeywordData(jskDefault) then
+    begin
+    Result.DefaultValue:=aParam.Schema.MetaData.DefaultValue.AsString;
+    if lType=ptString then
+      Result.DefaultValue:=''''+StringReplace(Result.DefaultValue,'''','''''',[rfReplaceAll])+'''';
+    end;
+end;
+
+function TAPIData.IsResponseContentApplicationJSON(aOperation : TAPIOperation) : boolean;
+
+var
+  lResponse : TResponse;
+  lMedia : TMediaType;
+
+begin
+  if aOperation.Responses.Count=0 then
+    Result:=True
+  else
+    begin
+    lResponse:=aOperation.Responses.ResponseByindex[0];
+    lMedia:=lResponse.Content.MediaTypes['application/json'];
+    Result:=lMedia<>nil;
+    end;
+end;
+
+function TAPIData.GenerateMethodResultCallBackName(aMethod : TAPIServiceMethod) : String;
+
+var
+  lResponse: TResponse;
+  lMedia : TMediaType;
+
+begin
+  if AMethod.Operation.Responses.Count=0 then
+    Result:=VoidResultCallbackType
+  else
+    begin
+    lResponse:=AMethod.Operation.Responses.ResponseByindex[0];
+    lMedia:=lResponse.Content.MediaTypes['application/json'];
+    if (lMedia.Schema.Ref<>'') then
+      Result:=Format('%sResultCallBack',[GetRefSchemaTypeName(lMedia.Schema.Ref,ntPascal)])
+    else if (lMedia.Schema.Validations.Types=[]) then
+      Result:=VoidResultCallbackType
+    else
+      Result:=GetSchemaTypeName(lMedia.Schema,ntPascal);
+    end;
+end;
+
+function TAPIData.GetMethodResultType(aMethod : TAPIServiceMethod; aNameType : TNameType) : String;
+
+var
+  lResponse: TResponse;
+  lMedia : TMediaType;
+
+begin
+  Result:='Boolean';
+  if AMethod.Operation.Responses.Count>0 then
+    begin
+    lResponse:=AMethod.Operation.Responses.ResponseByindex[0];
+    lMedia:=lResponse.Content.MediaTypes['application/json'];
+    if (lMedia.Schema.Ref<>'') then
+      Result:=GetRefSchemaTypeName(lMedia.Schema.Ref,aNameType)
+    else if (lMedia.Schema.Validations.Types<>[]) then
+      Result:=GetSchemaTypeName(lMedia.Schema,aNameType)
+    end;
+end;
+
+function TAPIData.IsRequestBodyApplicationJSON(aOperation : TAPIOperation) : Boolean;
+
+var
+  lMedia : TMediaType;
+begin
+  Result:=False;
+  if Not aOperation.HasKeyWord(okRequestBody) then
+    exit(True);
+  if aOperation.RequestBody.HasReference then
+    // We have a definition
+    Result:=GetRefSchemaTypeName(aOperation.RequestBody.Reference.Ref,ntPascal)<>''
+  else
+    begin
+    lMedia:=aOperation.RequestBody.Content['application/json'];
+    Result:=lMedia<>Nil;
+    end;
+end;
+
+function TAPIData.GetMethodRequestBodyType(aMethod : TAPIServiceMethod) : string;
+
+var
+  lMedia : TMediaType;
+
+begin
+  Result:='';
+  if Not aMethod.Operation.HasKeyWord(okRequestBody) then
+    exit;
+  if aMethod.Operation.RequestBody.HasReference then
+    Result:=GetRefSchemaTypeName(aMethod.Operation.RequestBody.Reference.Ref,ntInterface)
+  else
+    begin
+    lMedia:=aMethod.Operation.RequestBody.Content['application/json'];
+    if (lMedia.Schema.Ref<>'') then
+      Result:=GetRefSchemaTypeName(lMedia.Schema.Ref,ntInterface)
+    else if (lMedia.Schema.Validations.Types<>[]) then
+      Result:=GetSchemaTypeName(lMedia.Schema,ntInterface);
+    end;
+end;
+
+
+
+procedure TAPIData.ConfigureServiceMethod(aService : TAPIService; aMethod : TAPIServiceMethod);
+
+begin
+  aMethod.ResultCallBackType:=GenerateMethodResultCallBackName(aMethod);
+  aMethod.ResultType:=GetMethodResultType(aMethod,ntInterface);
+  aMethod.ResultClassType:=GetMethodResultType(aMethod,ntImplementation);
+  aMethod.ResultDtoType:=GetMethodResultType(aMethod,ntPascal);
+  aMethod.RequestBodyType:=GetMethodRequestBodyType(aMethod);
+end;
+
+
+function TAPIData.AllowOperation(aKeyword: TPathItemOperationKeyword; aOperation: TAPIOperation): boolean;
+
+begin
+  Result:=True;
+  Result:=IsResponseContentApplicationJSON(aOperation);
+  if (aKeyword in [pkPost,pkPut,pkPatch]) then
+    Result:=IsRequestBodyApplicationJSON(aOperation);
+end;
+
+procedure TAPIData.CreateServiceDefs;
+
+var
+  I,J : Integer;
+  lPath: TPathItem;
+  lURL : String;
+  lOperation : TAPIOperation;
+  lKeyword : TPathItemOperationKeyword;
+  lServiceName,lMethodName : String;
+  lService : TAPIService;
+  lMethod : TAPIServiceMethod;
+  lMap : String;
+
+begin
+  for I:=0 to FAPI.Paths.Count-1 do
+    begin
+    lPath:=FAPI.Paths.PathByIndex[I];
+    lURL:=FAPI.Paths.Names[I];
+    for lKeyword in TPathItemOperationKeyword do
+      begin
+      lOperation:=lPath.GetOperation(lKeyword);
+      if assigned(lOperation) and AllowOperation(lKeyword,lOperation) then
+        begin
+        lServiceName:=GenerateServiceName(lUrl,lPath,lOperation);
+        lService:=FindService(lServiceName);
+        if lService=Nil then
+          begin
+          lService:=AddService(lServiceName);
+          ConfigService(lService);
+          end;
+        lMethodName:=GenerateServiceMethodName(lUrl,lPath,lOperation);
+        lMethod:=lService.AddMethod(lMethodName,lOperation,lPath);
+        ConfigureServiceMethod(lService,lMethod);
+        if lOperation.HasKeyWord(okParameters) then
+          for J:=0 to lOperation.Parameters.Count-1 do
+            AddServiceMethodParam(lService,lMethod,j,lOperation.Parameters[j]);
+        if lOperation.OperationId='' then
+          lMap:=lOperation.PathComponent+'.'+lPath.PathComponent
+        else
+          lMap:=lOperation.OperationID;
+        doLog(etInfo,'Map %s on %s.%s',[lMap,lService.ServiceName,lMethod.MethodName]);
+        end;
+      end;
+    end;
+  FServices.Sort(@CompareServiceName);
+  For I:=0 to ServiceCount-1 do
+    begin
+    Services[i].SortMethods;
+    For J:=0 to Services[i].MethodCount-1 do
+      Services[i].Methods[J].SortParams;
+    end;
+end;
+
+
+function TAPIData.IsAPIComponent(aSchema: TJSONSchema): Boolean;
+begin
+  Result:=(aSchema.Ref<>'') and (GetRefSchemaTypeName(aSchema.Ref,ntSchema)<>'');
+end;
+
+function TAPIData.IsAPIComponentArray(aSchema: TJSONSchema): Boolean;
+begin
+  Result:=GetSchemaType(aSchema)=sstArray;
+  if Result then
+    Result:=(aSchema.Items.Count>0) and IsAPIComponent(aSchema.Items[0]);
+end;
+
+function TAPIData.GetRefSchemaTypeName(const aRef: String; aNameType: TNameType): string;
+
+const
+  ComponentsRef = '#/components/schemas/';
+
+var
+  lLen : Integer;
+  lName : string;
+
+begin
+  if Pos(ComponentsRef,aRef)=1 then
+    begin
+    lLen:=Length(ComponentsRef);
+    lName:=Copy(aRef,lLen+1,Length(aRef)-lLen);
+    if aNameType=ntSchema then
+      Result:=lName
+    else
+      Result:=RawToNameType(lName,aNameType);
+    end
+  else
+    Result:='';
+end;
+
+function TAPIData.CheckOperationsInput(aPath : TPathItem; aData: TAPITypeData): Boolean;
+
+  function CheckOperation(aOperation : TAPIOperation)  : Boolean;
+
+  var
+    lRef,lName : String;
+    lMediaType : TMediaType;
+    lInputType : TAPITypeData;
+
+  begin
+    Result:=False;
+    if aOperation=Nil then
+      exit;
+    if not aOperation.HasKeyWord(okRequestBody) then
+      exit;
+    if aOperation.RequestBody.HasReference then
+      lRef:=aOperation.RequestBody.Reference.ref
+    else
+      begin
+      if not aOperation.RequestBody.HasKeyWord(rbkContent) then
+        exit;
+      lMediaType:=aOperation.RequestBody.Content.MediaTypes['application/json'];
+      if assigned(lMediaType) and assigned(lMediaType.Schema) then
+        lRef:=lMediaType.Schema.Ref
+      end;
+    if lRef<>'' then
+      begin
+      lRef:=GetRefSchemaTypeName(lRef,ntSchema);
+      lName:=aData.SchemaName;
+      if lRef=lName then
+        Exit(True);
+      lInputType:=GetAPIType(lRef);
+      if Assigned(lInputType) and (lInputType.DependsOn(aData,True)<>dtNone) then
+        Exit(True);
+      end;
+  end;
+
+var
+  aKeyword : TPathItemOperationKeyword;
+
+begin
+  Result:=False;
+  For aKeyword in TPathItemOperationKeyword do
+    if CheckOperation(aPath.GetOperation(aKeyword)) then
+      Exit(True);
+end;
+
+function TAPIData.CheckOperationsOutput(aPath : TPathItem; aData: TAPITypeData): Boolean;
+
+  function CheckResponse(aResponse : TResponse) : Boolean;
+
+  var
+    lMediaType : TMediaType;
+    lName,lRef : String;
+    lInputType : TAPITypeData;
+
+  begin
+    Result:=False;
+    lMediaType:=aResponse.Content.MediaTypes['application/json'];
+    if Not (assigned(lMediaType) and assigned(lMediaType.Schema)) then
+      exit;
+    lRef:=lMediaType.Schema.Ref;
+    if lRef='' then
+      exit;
+    lRef:=GetRefSchemaTypeName(lRef,ntSchema);
+    lName:=aData.SchemaName;
+    if lRef=lName then
+      Exit(True);
+    lInputType:=GetAPIType(lRef);
+    if Assigned(lInputType) and (lInputType.DependsOn(aData,True)<>dtNone) then
+      Exit(True);
+  end;
+
+  function CheckOperation(aOperation : TAPIOperation)  : Boolean;
+
+  var
+    I : Integer;
+
+  begin
+    Result:=False;
+    if not Assigned(aOperation) then
+      exit;
+    if not aOperation.HasKeyWord(okResponses) then
+      exit;
+    For I:=0 to aOperation.Responses.Count-1 do
+      If CheckResponse(aOperation.Responses.ResponseByIndex[I]) then
+        Exit(True);
+  end;
+
+var
+  aKeyword : TPathItemOperationKeyword;
+
+begin
+  Result:=False;
+  For aKeyword in TPathItemOperationKeyword do
+    if CheckOperation(aPath.GetOperation(aKeyword)) then
+      Exit(True);
+end;
+
+
+function TAPIData.NeedsSerialize(aData: TAPITypeData): Boolean;
+
+var
+  lRef,lName : String;
+  Itm : TPathItem;
+  lParam: TParameterOrReference;
+  lParamType : TAPITypeData;
+  I,J : Integer;
+
+begin
+  Result:=False;
+  lName:=aData.SchemaName;
+  For I:=0 to FAPI.Paths.Count-1 do
+    begin
+    Itm:=FAPI.Paths.PathByIndex[I];
+    for J:=0 to Itm.Parameters.Count-1 do
+      begin
+      lParam:=itm.Parameters[j];
+      if (lParam.HasReference) then
+        lRef:=lParam.Reference.ref
+      else if Assigned(lParam.Schema) then
+        lRef:=lParam.Schema.Ref;
+      if lRef<>'' then
+        begin
+        lRef:=GetRefSchemaTypeName(lRef,ntSchema);
+        if lRef=lName then
+          Exit(True);
+        lParamType:=GetAPIType(lRef);
+        if Assigned(lParamType) and (lParamType.DependsOn(aData,True)<>dtNone) then
+          Exit(True);
+        end;
+      end;
+    If CheckOperationsInput(Itm,aData) then
+      exit(True);
+    end;
+end;
+
+function TAPIData.NeedsDeSerialize(aData: TAPITypeData): Boolean;
+var
+  Itm : TPathItem;
+  I : Integer;
+
+begin
+  Result:=False;
+  For I:=0 to FAPI.Paths.Count-1 do
+    begin
+    Itm:=FAPI.Paths.PathByIndex[I];
+    if CheckOperationsOutput(Itm,aData) then
+      Exit(True);
+    end;
+end;
+
+function TAPIData.RawToNameType(const aName : string; aNameType: TNameType) : string;
+
+var
+  lType : TAPITypeData;
+
+begin
+  lType:=FindApiType(aName);
+  if Assigned(lType) then
+    Result:=lType.GetTypeName(aNameType)
+  else
+    Result:=aName;
+end;
+
+
+procedure TAPIData.FinishAutoCreatedType(aName: string; aType: TPascalTypeData; lElementTypeData: TPascalTypeData);
+
+begin
+  if aType.Pascaltype=ptArray then
+    begin
+    aType.InterfaceName:=Format('%s<%s>',[InterfaceArrayType,lElementTypeData.InterfaceName]);
+    end;
+  Inherited;
+end;
+
+function TAPIData.GetSchemaTypeName(aSchema: TJSONSchema; aNameType: TNameType): String;
+
+var
+{
+  lTmp,elType : String;
+  lType : TPascalType;
+  }
+  lData : TPascalTypeData;
+
+begin
+  lData:=GetSchemaTypeData(Nil,aSchema,False);
+  if assigned(lData) then
+    Result:=lData.GetTypeName(aNameType)
+  else
+    Raise Exception.CreateFmt('No name for schema %s',[aSchema.Name]);
+(*
+     lType:=SchemaTypeToPascalType(aSchema,Result);
+
+     if lType in [ptInteger,ptInt64,ptBoolean,ptFloat32,ptFloat64,ptString] then
+       begin
+       lTmp:=Self.TypeMap[Result];
+       if lTmp<>'' then
+         Result:=lTmp;
+       end
+     else if lType=ptArray then
+       begin
+       if aNameType=ntInterface then
+         begin
+         ElType:=GetSchemaTypeName(aSchema.Items[0],aNametype);
+         Result:=Format(InterfaceArrayType,[elType])
+         end
+       else
+         if DelphiTypes then
+           Result:='TArray<'+GetSchemaTypeName(aSchema.Items[0],aNametype)+'>'
+         else
+           Result:='Array of '+GetSchemaTypeName(aSchema.Items[0],aNametype);
+       end;
+     end;
+*)
+end;
+
+
+function TAPITypeData.CreateProperty(const aAPIName, aPascalName: string): TPascalPropertyData;
+begin
+  Result:=TAPIProperty.Create(aAPIName,aPascalName);
+end;
+
+function TAPITypeData.AddProperty(const aApiName, aPascalName: String): TAPIProperty;
+begin
+  Result:=(Inherited AddProperty(aApiName,aPascalName)) as TAPIProperty;
+end;
+
+end.
+

+ 2166 - 0
packages/fcl-openapi/src/fpopenapi.reader.pp

@@ -0,0 +1,2166 @@
+{
+    This file is part of the Free Component Library (FCL)
+    Copyright (c) 2024 by Michael Van Canneyt ([email protected])
+
+    Classes for reading a OpenAPI document.
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+
+unit fpopenapi.reader;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses 
+  {$IFDEF FPC_DOTTEDUNITS}
+  System.SysUtils, System.Classes, System.Contnrs, FpJson.Data, FpJson.Scanner, 
+  {$ELSE}
+  sysutils, classes, contnrs, fpjson, jsonscanner, 
+  {$ENDIF}
+  fpopenapi.types, fpopenapi.objects, fpjson.schema.schema;
+
+Type
+  EOpenAPIReader = Class(EOpenAPi);
+  TJSONTokens = set of TJSONToken;
+
+  { TOpenAPIReader }
+  TCreateAndReadObjectFunc = Function(aParent : TBaseOpenAPIObject;aName : TJSONStringType) : TBaseOpenAPIObject of object;
+  TReadObjectProc = Procedure(aObject : TBaseOpenAPIObject; aCheckBracket: Boolean=True) of object;
+  TOpenAPIReader = Class(TComponent)
+  Private
+    FScanner : TJSONScanner;
+    procedure InvalidToken(aToken: TJSONToken);
+    function StringToJSONNumber(S: RawByteString): TJSONNumber;
+    procedure ReadJSONArray(aArray: TJSONArray);
+    function ReadParameterOrReferenceObject(aParent: TBaseOpenAPIObject; aName : TJSONStringType): TBaseOpenAPIObject;
+    function ReadSecurityRequirementObject(aParent: TBaseOpenAPIObject; aName : TJSONStringType): TBaseOpenAPIObject;
+    function ReadServerObject(aParent: TBaseOpenAPIObject; aName : TJSONStringType): TBaseOpenAPIObject;
+    function ReadTagObject(aParent: TBaseOpenAPIObject; aName : TJSONStringType): TBaseOpenAPIObject;
+    // Untyped callbacks
+    procedure ReadServerVariableUntyped(aObj: TBaseOpenAPIObject; aCheckBracket: Boolean);
+    procedure ReadPathItemOrReferenceUnTyped(aObj: TBaseOpenAPIObject; aCheckBracket: Boolean);
+    procedure ReadParameterOrReferenceUntyped(aObj: TBaseOpenAPIObject; aCheckBracket: Boolean);
+    procedure ReadRequestBodyOrReferenceUnTyped(aObj: TBaseOpenAPIObject; aCheckBracket: Boolean);
+    procedure ReadMediaTypeUnTyped(aObj: TBaseOpenAPIObject; aCheckBracket: Boolean);
+    procedure ReadEncodingUntyped(aObj: TBaseOpenAPIObject; aCheckBracket: Boolean);
+    procedure ReadResponseOrReferenceUnTyped(aObj: TBaseOpenAPIObject; aCheckBracket: Boolean);
+    procedure ReadExampleOrReferenceUnTyped(aObj: TBaseOpenAPIObject; aCheckBracket: Boolean);
+    procedure ReadLinkOrReferenceUntyped(aObj: TBaseOpenAPIObject; aCheckBracket: Boolean);
+    procedure ReadHeaderOrReferenceUnTyped(aObj: TBaseOpenAPIObject; aCheckBracket: Boolean);
+    procedure ReadSecuritySchemeOrReferenceUnTyped(aObj: TBaseOpenAPIObject; aCheckBracket: Boolean);
+    procedure ReadCallbackOrReferenceUnTyped(aObj: TBaseOpenAPIObject; aCheckBracket: Boolean);
+  Protected
+    function CurPosAsString: String;
+    function TokensToString(aTokens: TJSONTokens): String;
+    Function GetToken : TJSONToken;
+    Procedure CheckToken(aExpected,aActual : TJSONToken);
+    Procedure CheckToken(aExpected : TJSONTokens; aActual : TJSONToken);
+    procedure CheckNextToken(aExpected : TJSONToken);
+    function CheckNextToken(aExpected : TJSONTokens) : TJSONToken;
+    Function GetTokenString : TJSONStringType;
+    Function ReadString : TJSONStringType;
+    Function ReadBoolean : Boolean;
+    Function ReadJSONData : TJSONData;
+    function ReadJSONData(aToken: TJSONToken): TJSONData;
+    procedure ReadJSONObject(aObject: TJSONObject; aCheckOpening: Boolean=True);
+    procedure HandleParamOrHeader(aObj: TParameterOrHeader; aName : String);
+    procedure DoReadObject(aObj: TParameterOrHeader; aCheckBracket: Boolean);
+    Function ReadObjectArray(aList : TFPObjectList; aGetObject : TCreateAndReadObjectFunc) : integer;overload;
+    function ReadMapObject(aList: TNamedOpenAPIObjectList; aObjectReader : TReadObjectProc; aCheckBracket: Boolean=True): integer;
+    Function ReadObject(aList : TStrings) : integer;
+    // objects
+    Procedure ReadOpenAPI(aObj : TOpenAPI; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadInfo(aObj : TInfo; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadContact(aObj : TContact; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadLicense(aObj : TLicense; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadServer(aObj : TServer; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadServerList(aObj : TServerList); virtual; overload;
+    Procedure ReadPathsList(aObj : TPathsList; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadServerVariable(aObj : TServerVariable; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadServerVariableMap(aObj : TServerVariableMap; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadJSONSchemaMap(aObj : TJSONSchemaMap; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadJSONSchema(aObj : TJSONSchema; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadComponents(aObj : TComponents; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadPathItem(aObj : TPathItem; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadPathItemOrReference(aObj : TPathItemOrReference; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadPathItemOrReferenceMap(aObj : TPathItemOrReferenceMap; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadApiOperation(aObj : TApiOperation; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadExternalDocumentation(aObj : TExternalDocumentation; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadParameter(aObj : TParameter; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadParameterOrReference(aObj : TParameterOrReference; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadParameterOrReferenceList(aObj : TParameterOrReferenceList); virtual; overload;
+    Procedure ReadParameterOrReferenceMap(aObj : TParameterOrReferenceMap; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadParameterStyle(aObj : TParameterStyle; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadRequestBody(aObj : TRequestBody; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadRequestBodyOrReference(aObj : TRequestBodyOrReference; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadRequestBodyOrReferenceMap(aObj : TRequestBodyOrReferenceMap; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadMediaType(aObj : TMediaType; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadMediaTypeMap(aObj : TMediaTypeMap; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadEncoding(aObj : TEncoding; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadEncodingMap(aObj : TEncodingMap; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadResponses(aObj : TResponses; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadResponse(aObj : TResponse; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadResponseOrReference(aObj : TResponseOrReference; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadResponseOrReferenceMap(aObj : TResponseOrReferenceMap; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadExample(aObj : TExample; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadExampleOrReference(aObj : TExampleOrReference; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadExampleOrReferenceMap(aObj : TExampleOrReferenceMap; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadLink(aObj : TLink; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadLinkOrReference(aObj : TLinkOrReference; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadLinkOrReferenceMap(aObj : TLinkOrReferenceMap; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadTag(aObj : TTag; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadReference(aObj : TReference; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadSchema(aObj : TSchema; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadDiscriminator(aObj : TDiscriminator; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadXML(aObj : TXML; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadSecurityScheme(aObj : TSecurityScheme; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadSecuritySchemeOrReference(aObj : TSecuritySchemeOrReference; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadSecuritySchemeOrReferenceMap(aObj : TSecuritySchemeOrReferenceMap; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadOAuthFlows(aObj : TOAuthFlows; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadOAuthFlow(aObj : TOauthFlow; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadHeader(aObj : THeader; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadHeaderOrReference(aObj : THeaderOrReference; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadHeaderOrReferenceMap(aObj : THeaderOrReferenceMap; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadCallbackOrReference(aObj : TCallbackOrReference; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadCallbackOrReferenceMap(aObj : TCallbackOrReferenceMap; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadSecurityRequirement(aObj : TSecurityRequirement; aCheckBracket : Boolean = True); virtual; overload;
+    Procedure ReadSecurityRequirementList(aObj : TSecurityRequirementList); virtual; overload;
+    Procedure ReadTagList(aObj : TTagList); virtual; overload;
+ Public
+   procedure ReadFromScanner(aOpenAPI: TOpenAPI; AScanner: TJSONScanner);
+   procedure ReadFromFile(aOpenAPI: TOpenAPI; const AFilename: String);
+   procedure ReadFromStream(aOpenAPI: TOpenAPI; AStream: TStream);
+   procedure ReadFromString(aOpenAPI: TOpenAPI; const AString: TJSONStringType);
+ end;
+
+implementation
+
+uses fpjson.schema.reader, fpjson.schema.consts;
+
+
+function TOpenAPIReader.GetToken: TJSONToken;
+
+const
+  IgnoredTokens = [tkWhitespace,tkComment];
+
+begin
+  repeat
+    Result:=FScanner.FetchToken;
+  until Not (Result in IgnoredTokens);
+end;
+
+function TOpenAPIReader.CurPosAsString: String;
+
+begin
+  Result:=Format('%d:%d',[FScanner.CurRow,FScanner.CurColumn]);
+end;
+
+procedure TOpenAPIReader.InvalidToken(aToken: TJSONToken);
+
+begin
+  raise EOpenAPIReader.CreateFmt(SErrInvalidToken, [CurPosAsString, TokenInfos[aToken]]);
+end;
+
+procedure TOpenAPIReader.CheckToken(aExpected, aActual: TJSONToken);
+begin
+  if aExpected<>aActual then
+    raise EOpenAPIReader.CreateFmt(SErrUnexpectedToken, [CurPosAsString, TokenInfos[aExpected], TokenInfos[aActual]]);
+end;
+
+procedure TOpenAPIReader.CheckToken(aExpected: TJSONTokens; aActual: TJSONToken);
+begin
+  if not (aActual in aExpected) then
+    raise EOpenAPIReader.CreateFmt(SErrUnexpectedTokenNotInSet, [TokensToString(aExpected), TokenInfos[aActual]]);
+end;
+
+function TOpenAPIReader.TokensToString(aTokens : TJSONTokens) : String;
+
+var
+  T : TJSONToken;
+  S : String;
+
+begin
+  S:='';
+  For T in aTokens do
+    begin
+    if (S<>'') then
+      S:=S+', ';
+    S:=S+'"'+TokenInfos[T]+'"';
+    end;
+  Result:=S;
+end;
+
+
+procedure TOpenAPIReader.CheckNextToken(aExpected: TJSONToken);
+begin
+  CheckToken(aExpected,GetToken);
+end;
+
+function TOpenAPIReader.CheckNextToken(aExpected: TJSONTokens): TJSONToken;
+begin
+  Result:=GetToken;
+  CheckToken(aExpected,Result);
+end;
+
+function TOpenAPIReader.GetTokenString: TJSONStringType;
+begin
+  Result:=FScanner.CurTokenString;
+end;
+
+function TOpenAPIReader.ReadString: TJSONStringType;
+var
+  aToken: TJSONToken;
+begin
+  aToken:=GetToken;
+  CheckToken(tkString,aToken);
+  Result:=GetTokenString;
+end;
+
+function TOpenAPIReader.ReadBoolean: Boolean;
+var
+  aToken : TJSONToken;
+
+begin
+  aToken:=GetToken;
+  CheckToken([tkTrue,tkFalse],aToken);
+  Result:=aToken=tkTrue;
+end;
+
+function TOpenAPIReader.ReadJSONData: TJSONData;
+
+begin
+  Result:=ReadJSONData(GetToken);
+end;
+
+
+function TOpenAPIReader.StringToJSONNumber(S : RawByteString): TJSONNumber;
+
+var
+  I : integer;
+  I64 : Int64;
+  Q : QWord;
+  F : TJSONFloat;
+
+begin
+  if TryStrToInt(S,I) then
+    Exit(TJSONIntegerNumber.Create(I));
+  if TryStrToInt64(S,I64) then
+    Exit(TJSONInt64Number.Create(I64));
+  if TryStrToQWord(S,Q) then
+    Exit(TJSONQWordNumber.Create(Q));
+  Val(S,F,I);
+  If (I<>0) then
+    EConvertError.CreateFmt(SErrInvalidNumber,[S]);
+  Result:=TJSONFloatNumber.Create(F);
+end;
+
+
+function TOpenAPIReader.ReadJSONData(aToken : TJSONToken): TJSONData;
+
+begin
+  Result:=nil;
+  try
+    case aToken of
+      tkNull : Result:=TJSONNull.Create;
+      tkNumber : Result:=StringToJSONNumber(GetTokenString);
+      tkTrue,
+      tkFalse : Result:=TJSONBoolean.Create(aToken=tkTrue);
+      tkString : Result:=TJSONString.Create(GetTokenString);
+      tkCurlyBraceOpen :
+        begin
+        Result:=TJSONObject.Create;
+        ReadJSONObject(TJSONObject(Result),False);
+        end;
+      tkSquaredBraceOpen :
+        begin
+        Result:=TJSONArray.Create;
+        ReadJSONArray(TJSONArray(Result));
+        end
+    else
+      InvalidToken(aToken);
+    end;
+  except
+    Result.Free;
+    Raise;
+  end;
+end;
+
+procedure TOpenAPIReader.ReadJSONArray(aArray: TJSONArray);
+// On entry, we're on [
+
+var
+  aToken : TJSONToken;
+
+begin
+  Repeat
+    aToken:=GetToken;
+    if Not (aToken in [tkComma,tkSquaredBraceClose]) then
+      aArray.Add(ReadJSONData(aToken));
+  until (aToken in [tkSquaredBraceClose,tkEOF]);
+  CheckToken(tkSquaredBraceClose,aToken);
+end;
+
+procedure TOpenAPIReader.ReadJSONObject(aObject : TJSONObject; aCheckOpening: Boolean = True);
+
+var
+  aToken : TJSONToken;
+  aName : TJSONStringtype;
+
+begin
+  if aCheckOpening then
+    CheckNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aObject.Add(aNAme,ReadJSONData);
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+      aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+procedure TOpenAPIReader.HandleParamOrHeader(aObj: TParameterOrHeader; aName: String);
+
+var
+  aKeyWord : TParameterKeyword;
+
+begin
+  aKeyword:=TParameterKeyword.FromString(aName);
+  case aKeyword of
+  pakName:
+    if aObj is TParameter then
+      TParameter(aObj).Name:=Readstring
+    else
+      aObj.Extensions.Add(aName,ReadJSONData);
+  pakIn:
+    if aObj is TParameter then
+      TParameter(aObj).In_:=Readstring
+    else
+      aObj.Extensions.Add(aName,ReadJSONData);
+  pakDescription:
+    aObj.Description:=Readstring;
+  pakRequired:
+    aObj.Required:=ReadBoolean;
+  pakDeprecated:
+    aObj.Deprecated:=ReadBoolean;
+  pakAllowEmptyValue:
+    aObj.AllowEmptyValue:=ReadBoolean;
+  pakStyle:
+    aObj.Style:=Readstring;
+  pakExplode:
+    aObj.Explode:=ReadBoolean;
+  pakAllowReserved:
+    aObj.AllowReserved:=ReadBoolean;
+  pakSchema:
+    ReadJSONschema(aObj.Schema);
+  pakExample:
+    aObj.Example:=ReadJSONData;
+  pakExamples:
+    ReadExampleOrReferenceMap(aObj.Examples);
+  pakContent:
+    ReadMediaTypeMap(aObj.Content);
+  else
+    aObj.Extensions.Add(aName,ReadJSONData);
+  end;
+end;
+
+
+function TOpenAPIReader.ReadMapObject(aList: TNamedOpenAPIObjectList; aObjectReader: TReadObjectProc; aCheckBracket: Boolean
+  ): integer;
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  Itm : TObject;
+
+begin
+  Result:=0;
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    itm:=aList.CreateNew(aName);
+//    aList.Add(aName,Itm);
+    if not (Itm is TBaseOpenAPIObject) then
+       Raise EOpenAPIReader.CreateFmt('List %s created an item that is not a TOPenAPIObject',[aList.ClassName]);
+    aObjectReader(TBaseOpenAPIObject(Itm),True);
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+      aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+function TOpenAPIReader.ReadObject(aList: TStrings): integer;
+var
+  aToken: TJSONToken;
+begin
+  Result:=0;
+  CheckNextToken(tkSquaredBraceOpen);
+  aToken:=GetToken;
+  while Not (aToken in [tkEOF,tkSquaredBraceClose]) do
+    begin
+    case aToken of
+      tkComma:
+        ;
+      tkString:
+        begin
+        aList.Add(GetTokenString);
+        inc(Result);
+        end
+    else
+      InvalidToken(aToken);
+    end;
+    aToken:=GetToken;
+    end;
+end;
+
+procedure TOpenAPIReader.ReadOpenAPI(aObj: TOpenAPI; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TOpenAPIKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TOpenAPIKeyword.FromString(aName);
+    case aKeyword of
+    oakOpenApi: 
+      aObj.OpenApi:=Readstring;
+    oakInfo: 
+      ReadInfo(aObj.Info);
+    oakJSONSchemaDialect: 
+      aObj.JSONSchemaDialect:=Readstring;
+    oakServers: 
+      ReadServerList(aObj.Servers);
+    oakPaths: 
+      ReadPathsList(aObj.Paths);
+    oakWebHooks: 
+      ReadPathItemOrReferenceMap(aObj.WebHooks);
+    oakComponents: 
+      ReadComponents(aObj.Components);
+    oakSecurity: 
+      ReadSecurityRequirementList(aObj.Security);
+    oakTags: 
+      ReadTagList(aObj.Tags);
+    oakExternalDocs: 
+      ReadExternalDocumentation(aObj.ExternalDocs);
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+
+procedure TOpenAPIReader.ReadInfo(aObj: TInfo; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TInfoKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TInfoKeyword.FromString(aName);
+    case aKeyword of
+    ikTitle: 
+      aObj.Title:=Readstring;
+    ikSummary: 
+      aObj.Summary:=Readstring;
+    ikDescription: 
+      aObj.Description:=Readstring;
+    ikTermsOfService: 
+      aObj.TermsOfService:=Readstring;
+    ikContact: 
+      ReadContact(aObj.Contact);
+    ikLicense: 
+      ReadLicense(aObj.License);
+    ikVersion: 
+      aObj.Version:=Readstring;
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+
+procedure TOpenAPIReader.ReadContact(aObj: TContact; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TContactKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TContactKeyword.FromString(aName);
+    case aKeyword of
+    cokName: 
+      aObj.Name:=Readstring;
+    cokUrl: 
+      aObj.Url:=Readstring;
+    cokEmail: 
+      aObj.Email:=Readstring;
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+
+procedure TOpenAPIReader.ReadLicense(aObj: TLicense; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TLicenseKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TLicenseKeyword.FromString(aName);
+    case aKeyword of
+    lkName: 
+      aObj.Name:=Readstring;
+    lkIdentifier: 
+      aObj.Identifier:=Readstring;
+    lkUrl: 
+      aObj.Url:=Readstring;
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+procedure TOpenAPIReader.ReadServer(aObj: TServer; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TServerKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TServerKeyword.FromString(aName);
+    case aKeyword of
+    skServerUrl: 
+      aObj.Url:=Readstring;
+    skDescription: 
+      aObj.Description:=Readstring;
+    skVariables: 
+      ReadServerVariableMap(aObj.Variables);
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+
+function TOpenAPIReader.ReadServerObject(aParent: TBaseOpenAPIObject; aName: TJSONStringType): TBaseOpenAPIObject;
+
+begin
+  Result:=TServer.Create(aParent,'server');
+  try
+    ReadServer(TServer(Result),False);
+  except
+    Result.Free;
+    Raise;
+  end;
+end;
+procedure TOpenAPIReader.ReadServerList(aObj: TServerList);
+
+begin
+  ReadObjectArray(aObj,@ReadServerObject);
+end;
+
+
+procedure TOpenAPIReader.ReadPathsList(aObj: TPathsList; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  Itm: TPathItem;
+
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    Itm:=aObj.AddItem(aName);
+    ReadPathItem(Itm);
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+
+procedure TOpenAPIReader.ReadServerVariable(aObj: TServerVariable; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TServerVariableKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TServerVariableKeyword.FromString(aName);
+    case aKeyword of
+    svkEnum: 
+      ReadObject(aObj.Enum);
+    svkDefault: 
+      aObj.Default:=Readstring;
+    svkDescription: 
+      aObj.Description:=Readstring;
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+procedure TOpenAPIReader.ReadServerVariableUntyped(aObj: TBaseOpenAPIObject; aCheckBracket: Boolean);
+begin
+  ReadServerVariable(aObj as TServerVariable,aCheckBracket);
+end;
+
+procedure TOpenAPIReader.ReadServerVariableMap(aObj: TServerVariableMap; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+
+begin
+  ReadMapObject(aObj,@ReadServerVariableUntyped,aCheckBracket);
+end;
+
+procedure TOpenAPIReader.ReadJSONSchemaMap(aObj: TJSONSchemaMap; aCheckBracket: Boolean);
+var
+  atoken : TJSONToken;
+  aName : String;
+  Schema : TJSONSchema;
+  R : TJSONSchemaReader;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    Schema:=aObj.Add(aName);
+    CheckNextToken(tkColon);
+    R:=TJSONSchemaReader.Create(Nil);
+    try
+      R.ReadFromScanner(Schema,FScanner);
+    finally
+      R.Free;
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+procedure TOpenAPIReader.ReadJSONSchema(aObj: TJSONSchema; aCheckBracket: Boolean);
+
+var
+  R : TJSONSchemaReader;
+begin
+  R:=TJSONSchemaReader.Create(Nil);
+  try
+    R.ReadFromScanner(aObj,FScanner);
+  finally
+    R.Free;
+  end;
+end;
+
+
+procedure TOpenAPIReader.ReadComponents(aObj: TComponents; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TComponentsKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TComponentsKeyword.FromString(aName);
+    case aKeyword of
+    ckSchemas: 
+      ReadJSONSchemaMap(aObj.Schemas);
+    ckResponses: 
+      ReadResponseOrReferenceMap(aObj.Responses);
+    ckParameters: 
+      ReadParameterOrReferenceMap(aObj.Parameters);
+    ckExamples: 
+      ReadExampleOrReferenceMap(aObj.Examples);
+    ckRequestBodies: 
+      ReadRequestBodyOrReferenceMap(aObj.RequestBodies);
+    ckHeaders: 
+      ReadHeaderOrReferenceMap(aObj.Headers);
+    ckSecuritySchemes: 
+      ReadSecuritySchemeOrReferenceMap(aObj.SecuritySchemes);
+    ckLinks: 
+      ReadLinkOrReferenceMap(aObj.Links);
+    ckCallbacks: 
+      ReadLinkOrReferenceMap(aObj.Callbacks);
+    ckPathItems: 
+      ReadPathItemOrReferenceMap(aObj.PathItems);
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+
+procedure TOpenAPIReader.ReadPathItem(aObj: TPathItem; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TPathItemKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TPathItemKeyword.FromString(aName);
+    case aKeyword of
+    pkRef: 
+      aObj.Ref:=Readstring;
+    pkSummary: 
+      aObj.Summary:=Readstring;
+    pkDescription: 
+      aObj.Description:=Readstring;
+    pkGet: 
+      ReadApiOperation(aObj.Get);
+    pkPut: 
+      ReadApiOperation(aObj.Put);
+    pkPost: 
+      ReadApiOperation(aObj.Post);
+    pkDelete: 
+      ReadApiOperation(aObj.Delete);
+    pkOptions: 
+      ReadApiOperation(aObj.Options);
+    pkHead: 
+      ReadApiOperation(aObj.Head);
+    pkPatch: 
+      ReadApiOperation(aObj.Patch);
+    pkTrace: 
+      ReadApiOperation(aObj.Trace);
+    pkServers: 
+      ReadServerList(aObj.Servers);
+    pkParameters: 
+      ReadParameterOrReferenceList(aObj.Parameters);
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+
+procedure TOpenAPIReader.ReadPathItemOrReference(aObj: TPathItemOrReference; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TPathItemKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TPathItemKeyword.FromString(aName);
+    case aKeyword of
+    pkRef: 
+      aObj.Ref:=Readstring;
+    pkSummary: 
+      aObj.Summary:=Readstring;
+    pkDescription: 
+      aObj.Description:=Readstring;
+    pkGet: 
+      ReadApiOperation(aObj.Get);
+    pkPut: 
+      ReadApiOperation(aObj.Put);
+    pkPost: 
+      ReadApiOperation(aObj.Post);
+    pkDelete: 
+      ReadApiOperation(aObj.Delete);
+    pkOptions: 
+      ReadApiOperation(aObj.Options);
+    pkHead: 
+      ReadApiOperation(aObj.Head);
+    pkPatch: 
+      ReadApiOperation(aObj.Patch);
+    pkTrace: 
+      ReadApiOperation(aObj.Trace);
+    pkServers: 
+      ReadServerList(aObj.Servers);
+    pkParameters: 
+      ReadParameterOrReferenceList(aObj.Parameters);
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+procedure TOpenAPIReader.ReadPathItemOrReferenceUnTyped(aObj: TBaseOpenAPIObject; aCheckBracket: Boolean);
+
+begin
+  ReadPathItemOrReference(aObj as TPathItemOrReference,aCheckBracket);
+end;
+
+procedure TOpenAPIReader.ReadPathItemOrReferenceMap(aObj: TPathItemOrReferenceMap; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+
+begin
+  ReadMapObject(aObj,@ReadPathItemOrReferenceUnTyped,aCheckBracket);
+end;
+
+
+procedure TOpenAPIReader.ReadApiOperation(aObj: TApiOperation; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TApiOperationKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TApiOperationKeyword.FromString(aName);
+    case aKeyword of
+    okTags: 
+      ReadObject(aObj.Tags);
+    okSummary: 
+      aObj.Summary:=Readstring;
+    okDescription: 
+      aObj.Description:=Readstring;
+    okExternalDocs: 
+      ReadExternalDocumentation(aObj.ExternalDocs);
+    okOperationId: 
+      aObj.OperationId:=Readstring;
+    okParameters: 
+      ReadParameterOrReferenceList(aObj.Parameters);
+    okRequestBody: 
+      ReadRequestBody(aObj.RequestBody);
+    okResponses: 
+      ReadResponses(aObj.Responses);
+    okCallbacks: 
+      ReadCallBackOrReferenceMap(aObj.Callbacks);
+    okDeprecated: 
+      aObj.Deprecated:=ReadBoolean;
+    okSecurity: 
+      ReadSecurityRequirementList(aObj.Security);
+    okServers: 
+      ReadServerList(aObj.Servers);
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+
+procedure TOpenAPIReader.ReadExternalDocumentation(aObj: TExternalDocumentation; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TExternalDocumentationKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TExternalDocumentationKeyword.FromString(aName);
+    case aKeyword of
+    edkDescription: 
+      aObj.Description:=Readstring;
+    edkUrl: 
+      aObj.Url:=Readstring;
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+
+procedure TOpenAPIReader.ReadParameter(aObj: TParameter; aCheckBracket: Boolean);
+
+begin
+  DoReadObject(aObj,aCheckBracket);
+end;
+
+procedure TOpenAPIReader.DoReadObject(aObj: TParameterOrHeader; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    HandleParamOrHeader(aObj,aName);
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+
+function TOpenAPIReader.ReadObjectArray(aList: TFPObjectList; aGetObject : TCreateAndReadObjectFunc): integer;
+var
+  Item: TBaseOpenAPIObject;
+  aToken: TJSONToken;
+
+begin
+  Result:=0;
+  CheckNextToken(tkSquaredBraceOpen);
+  aToken:=GetToken;
+  while not (aToken in [tkEOF,tkSquaredBraceClose]) do
+    begin
+    case aToken of
+      tkComma:
+        ;
+      tkCurlyBraceOpen:
+        begin
+        Item:=aGetObject(Nil,IntToStr(Result));
+        aList.Add(Item);
+        Inc(Result);
+        end;
+    else
+      InvalidToken(aToken);
+    end;
+    aToken:=GetToken;
+    end;
+  CheckToken(tkSquaredBraceClose,aToken);
+end;
+
+
+procedure TOpenAPIReader.ReadParameterOrReference(aObj: TParameterOrReference; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TParameterKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TParameterKeyword.FromString(aName);
+    case aKeyword of
+    pakName: 
+      aObj.Name:=Readstring;
+    pakIn: 
+      aObj.In_:=Readstring;
+    pakDescription: 
+      aObj.Description:=Readstring;
+    pakRequired: 
+      aObj.Required:=ReadBoolean;
+    pakDeprecated: 
+      aObj.Deprecated:=ReadBoolean;
+    pakAllowEmptyValue: 
+      aObj.AllowEmptyValue:=ReadBoolean;
+    pakStyle: 
+      aObj.Style:=Readstring;
+    pakExplode: 
+      aObj.Explode:=ReadBoolean;
+    pakAllowReserved: 
+      aObj.AllowReserved:=ReadBoolean;
+    pakSchema: 
+      ReadJSONSchema(aObj.Schema);
+    pakExample: 
+      aObj.Example:=ReadJSONData;
+    pakExamples: 
+      ReadExampleOrReferenceMap(aObj.Examples);
+    pakContent: 
+      ReadMediaTypeMap(aObj.Content);
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+function TOpenAPIReader.ReadParameterOrReferenceObject(aParent: TBaseOpenAPIObject; aName: TJSONStringType): TBaseOpenAPIObject;
+
+begin
+  Result:=TParameterOrReference.Create(aParent,aName);
+  try
+    ReadParameterOrReference(TParameterOrReference(Result),False);
+  except
+    Result.Free;
+    Raise;
+  end;
+end;
+
+procedure TOpenAPIReader.ReadParameterOrReferenceList(aObj: TParameterOrReferenceList);
+
+begin
+  ReadObjectArray(aObj,@ReadParameterOrReferenceObject);
+end;
+
+procedure TOpenAPIReader.ReadParameterOrReferenceUntyped(aObj: TBaseOpenAPIObject; aCheckBracket: Boolean);
+
+begin
+  ReadParameterOrReference(aObj as TParameterOrReference,aCheckBracket);
+end;
+
+procedure TOpenAPIReader.ReadParameterOrReferenceMap(aObj: TParameterOrReferenceMap; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+
+begin
+  ReadMapObject(aObj,@ReadParameterOrReferenceUnTyped,aCheckBracket);
+end;
+
+
+procedure TOpenAPIReader.ReadParameterStyle(aObj: TParameterStyle; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TParameterStyleKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TParameterStyleKeyword.FromString(aName);
+    case aKeyword of
+    pskMatrix: 
+      aObj.Matrix:=Readstring;
+    pskLabel: 
+      aObj.Label_:=Readstring;
+    pskForm: 
+      aObj.Form:=Readstring;
+    pskSimple: 
+      aObj.Simple:=Readstring;
+    pskSpaceDelimited: 
+      aObj.SpaceDelimited:=Readstring;
+    pskPipeDelimited: 
+      aObj.PipeDelimited:=Readstring;
+    pskDeepObject: 
+      aObj.DeepObject:=Readstring;
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+
+procedure TOpenAPIReader.ReadRequestBody(aObj: TRequestBody; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TRequestBodyKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TRequestBodyKeyword.FromString(aName);
+    case aKeyword of
+    rbkDescription: 
+      aObj.Description:=Readstring;
+    rbkContent: 
+      ReadMediaTypeMap(aObj.Content);
+    rbkRequired: 
+      aObj.Required:=ReadBoolean;
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+
+procedure TOpenAPIReader.ReadRequestBodyOrReference(aObj: TRequestBodyOrReference; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TRequestBodyKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TRequestBodyKeyword.FromString(aName);
+    case aKeyword of
+    rbkDescription: 
+      aObj.Description:=Readstring;
+    rbkContent: 
+      ReadMediaTypeMap(aObj.Content);
+    rbkRequired: 
+      aObj.Required:=ReadBoolean;
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+procedure TOpenAPIReader.ReadRequestBodyOrReferenceUnTyped(aObj: TBaseOpenAPIObject; aCheckBracket: Boolean);
+begin
+  ReadRequestBodyOrReference(aObj as TRequestBodyOrReference,aCheckBracket);
+end;
+
+procedure TOpenAPIReader.ReadRequestBodyOrReferenceMap(aObj: TRequestBodyOrReferenceMap; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+
+begin
+  ReadMapObject(aObj,@ReadRequestBodyOrReferenceUnTyped,aCheckBracket);
+end;
+
+
+procedure TOpenAPIReader.ReadMediaType(aObj: TMediaType; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TMediaTypeKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TMediaTypeKeyword.FromString(aName);
+    case aKeyword of
+    mtkSchema: 
+      ReadJSONSchema(aObj.Schema);
+    mtkExample: 
+      aObj.Example:=ReadJSONData;
+    mtkExamples: 
+      ReadExampleOrReferenceMap(aObj.Examples);
+    mtkEncoding: 
+      ReadEncodingMap(aObj.Encoding);
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+procedure TOpenAPIReader.ReadMediaTypeUnTyped(aObj: TBaseOpenAPIObject; aCheckBracket: Boolean);
+begin
+  ReadMediaType(aObj as TMediaType,aCheckBracket);
+end;
+
+procedure TOpenAPIReader.ReadMediaTypeMap(aObj: TMediaTypeMap; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+
+begin
+  ReadMapObject(aObj,@ReadMediaTypeUntyped,aCheckBracket);
+end;
+
+
+procedure TOpenAPIReader.ReadEncoding(aObj: TEncoding; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TEncodingKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TEncodingKeyword.FromString(aName);
+    case aKeyword of
+    eckContentType: 
+      aObj.ContentType:=Readstring;
+    eckHeaders: 
+      ReadHeaderOrReferenceMap(aObj.Headers);
+    eckStyle: 
+      aObj.Style:=Readstring;
+    eckExplode: 
+      aObj.Explode:=ReadBoolean;
+    eckAllowReserved: 
+      aObj.AllowReserved:=ReadBoolean;
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+procedure TOpenAPIReader.ReadEncodingUntyped(aObj: TBaseOpenAPIObject; aCheckBracket: Boolean);
+begin
+  ReadEncoding(aObj as TEncoding,aCheckBracket);
+end;
+
+procedure TOpenAPIReader.ReadEncodingMap(aObj: TEncodingMap; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+
+begin
+  ReadMapObject(aObj,@ReadEncodingUntyped,aCheckBracket);
+end;
+
+
+procedure TOpenAPIReader.ReadResponses(aObj: TResponses; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  Itm : TResponse;
+
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    Itm:=aObj.AddItem(aName);
+    ReadResponse(Itm);
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+
+procedure TOpenAPIReader.ReadResponse(aObj: TResponse; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TResponseKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TResponseKeyword.FromString(aName);
+    case aKeyword of
+    rkDescription: 
+      aObj.Description:=Readstring;
+    rkHeaders: 
+      ReadHeaderOrReferenceMap(aObj.Headers);
+    rkContent: 
+      ReadMediaTypeMap(aObj.Content);
+    rkLinks: 
+      ReadLinkOrReferenceMap(aObj.Links);
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+
+procedure TOpenAPIReader.ReadResponseOrReference(aObj: TResponseOrReference; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TResponseKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TResponseKeyword.FromString(aName);
+    case aKeyword of
+    rkDescription: 
+      aObj.Description:=Readstring;
+    rkHeaders: 
+      ReadHeaderOrReferenceMap(aObj.Headers);
+    rkContent: 
+      ReadMediaTypeMap(aObj.Content);
+    rkLinks: 
+      ReadLinkOrReferenceMap(aObj.Links);
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+procedure TOpenAPIReader.ReadResponseOrReferenceUnTyped(aObj: TBaseOpenAPIObject; aCheckBracket: Boolean);
+begin
+  ReadResponseOrReference(aObj as TResponseOrReference, aCheckBracket);
+end;
+
+procedure TOpenAPIReader.ReadResponseOrReferenceMap(aObj: TResponseOrReferenceMap; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+
+begin
+  ReadMapObject(aObj,@ReadResponseOrReferenceUnTyped,aCheckBracket);
+end;
+
+
+procedure TOpenAPIReader.ReadExample(aObj: TExample; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TExampleKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TExampleKeyword.FromString(aName);
+    case aKeyword of
+    exkSummary: 
+      aObj.Summary:=Readstring;
+    exkDescription: 
+      aObj.Description:=Readstring;
+    exkValue: 
+      aObj.Value:=ReadJSONData;
+    exkExternalValue: 
+      aObj.ExternalValue:=Readstring;
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+
+procedure TOpenAPIReader.ReadExampleOrReference(aObj: TExampleOrReference; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TExampleKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TExampleKeyword.FromString(aName);
+    case aKeyword of
+    exkSummary: 
+      aObj.Summary:=Readstring;
+    exkDescription: 
+      aObj.Description:=Readstring;
+    exkValue: 
+      aObj.Value:=ReadJSONData;
+    exkExternalValue: 
+      aObj.ExternalValue:=Readstring;
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+procedure TOpenAPIReader.ReadExampleOrReferenceUnTyped(aObj: TBaseOpenAPIObject; aCheckBracket: Boolean);
+
+begin
+  ReadExampleOrReference(aObj as TExampleOrReference,aCheckBracket);
+end;
+
+procedure TOpenAPIReader.ReadExampleOrReferenceMap(aObj: TExampleOrReferenceMap; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+
+begin
+  ReadMapObject(aObj,@ReadExampleOrReferenceUnTyped,aCheckBracket);
+end;
+
+
+procedure TOpenAPIReader.ReadLink(aObj: TLink; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TLinkKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TLinkKeyword.FromString(aName);
+    case aKeyword of
+    likOperationRef: 
+      aObj.OperationRef:=Readstring;
+    likOperationId: 
+      aObj.OperationId:=Readstring;
+    likParameters: 
+      ReadJSONObject(aObj.Parameters);
+    likRequestBody: 
+      aObj.RequestBody:=ReadJSONData;
+    likDescription: 
+      aObj.Description:=Readstring;
+    likServer: 
+      ReadServer(aObj.Server);
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+
+procedure TOpenAPIReader.ReadLinkOrReference(aObj: TLinkOrReference; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TLinkKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TLinkKeyword.FromString(aName);
+    case aKeyword of
+    likOperationRef: 
+      aObj.OperationRef:=Readstring;
+    likOperationId: 
+      aObj.OperationId:=Readstring;
+    likParameters: 
+      ReadJSONObject(aObj.Parameters);
+    likRequestBody: 
+      aObj.RequestBody:=ReadJSONData;
+    likDescription: 
+      aObj.Description:=Readstring;
+    likServer: 
+      ReadServer(aObj.Server);
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+procedure TOpenAPIReader.ReadLinkOrReferenceUntyped(aObj: TBaseOpenAPIObject; aCheckBracket: Boolean);
+
+begin
+  ReadLinkOrReference(aObj as TLinkOrReference,aCheckbracket)
+end;
+
+procedure TOpenAPIReader.ReadLinkOrReferenceMap(aObj: TLinkOrReferenceMap; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+
+begin
+  ReadMapObject(aObj,@ReadLinkOrReferenceUntyped,aCheckBracket);
+end;
+
+
+procedure TOpenAPIReader.ReadTag(aObj: TTag; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TTagKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TTagKeyword.FromString(aName);
+    case aKeyword of
+    tkName: 
+      aObj.Name:=Readstring;
+    tkDescription: 
+      aObj.Description:=Readstring;
+    tkExternalDocs: 
+      ReadExternalDocumentation(aObj.ExternalDocs);
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+
+procedure TOpenAPIReader.ReadReference(aObj: TReference; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TReferenceKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TReferenceKeyword.FromString(aName);
+    case aKeyword of
+    rfkRef: 
+      aObj.Ref:=Readstring;
+    rfkSummary: 
+      aObj.Summary:=Readstring;
+    rfkDescription: 
+      aObj.Description:=Readstring;
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+
+procedure TOpenAPIReader.ReadSchema(aObj: TSchema; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TSchemaKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TSchemaKeyword.FromString(aName);
+    case aKeyword of
+    sckDiscriminator: 
+      ReadDiscriminator(aObj.Discriminator);
+    sckXML: 
+      ReadXML(aObj.XML);
+    sckExternalDocs: 
+      ReadExternalDocumentation(aObj.ExternalDocs);
+    sckExample: 
+      aObj.Example:=ReadJSONData;
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+
+procedure TOpenAPIReader.ReadDiscriminator(aObj: TDiscriminator; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TDiscriminatorKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TDiscriminatorKeyword.FromString(aName);
+    case aKeyword of
+    dikPropertyName: 
+      aObj.PropertyName:=Readstring;
+    dikMapping: 
+      ReadObject(aObj.Mapping);
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+
+procedure TOpenAPIReader.ReadXML(aObj: TXML; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TXMLKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TXMLKeyword.FromString(aName);
+    case aKeyword of
+    xmkName: 
+      aObj.Name:=Readstring;
+    xmkNamespace: 
+      aObj.Namespace:=Readstring;
+    xmkPrefix: 
+      aObj.Prefix:=Readstring;
+    xmkAttribute: 
+      aObj.Attribute:=ReadBoolean;
+    xmkWrapped: 
+      aObj.Wrapped:=ReadBoolean;
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+
+procedure TOpenAPIReader.ReadSecurityScheme(aObj: TSecurityScheme; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TSecuritySchemeKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TSecuritySchemeKeyword.FromString(aName);
+    case aKeyword of
+    sskType: 
+      aObj.Type_:=Readstring;
+    sskDescription: 
+      aObj.Description:=Readstring;
+    sskName: 
+      aObj.Name:=Readstring;
+    sskIn: 
+      aObj.In_:=Readstring;
+    sskScheme: 
+      aObj.Scheme:=Readstring;
+    sskBearerFormat: 
+      aObj.BearerFormat:=Readstring;
+    sskFlows: 
+      ReadOAuthFlows(aObj.Flows);
+    sskOpenIdConnectUrl: 
+      aObj.OpenIdConnectUrl:=Readstring;
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+
+procedure TOpenAPIReader.ReadSecuritySchemeOrReference(aObj: TSecuritySchemeOrReference; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TSecuritySchemeKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TSecuritySchemeKeyword.FromString(aName);
+    case aKeyword of
+    sskType: 
+      aObj.Type_:=Readstring;
+    sskDescription: 
+      aObj.Description:=Readstring;
+    sskName: 
+      aObj.Name:=Readstring;
+    sskIn: 
+      aObj.In_:=Readstring;
+    sskScheme: 
+      aObj.Scheme:=Readstring;
+    sskBearerFormat: 
+      aObj.BearerFormat:=Readstring;
+    sskFlows: 
+      ReadOAuthFlows(aObj.Flows);
+    sskOpenIdConnectUrl: 
+      aObj.OpenIdConnectUrl:=Readstring;
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+procedure TOpenAPIReader.ReadSecuritySchemeOrReferenceUnTyped(aObj: TBaseOpenAPIObject; aCheckBracket: Boolean);
+
+begin
+  ReadSecuritySchemeOrReference(aObj as TSecuritySchemeOrReference,aCheckBracket);
+end;
+
+procedure TOpenAPIReader.ReadSecuritySchemeOrReferenceMap(aObj: TSecuritySchemeOrReferenceMap; aCheckBracket: Boolean);
+
+begin
+  ReadMapObject(aObj,@ReadSecuritySchemeOrReferenceUntyped,aCheckBracket);
+end;
+
+
+procedure TOpenAPIReader.ReadOAuthFlows(aObj: TOAuthFlows; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TOAuthFlowsKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TOAuthFlowsKeyword.FromString(aName);
+    case aKeyword of
+    ofskImplicit: 
+      ReadOauthFlow(aObj.Implicit);
+    ofskPassword: 
+      ReadOauthFlow(aObj.Password);
+    ofskClientCredentials: 
+      ReadOauthFlow(aObj.ClientCredentials);
+    ofskClientAuthorizationCode: 
+      ReadOauthFlow(aObj.ClientAuthorizationCode);
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+
+procedure TOpenAPIReader.ReadOAuthFlow(aObj: TOauthFlow; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  aKeyword : TOauthFlowKeyword;
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    aKeyword:=TOauthFlowKeyword.FromString(aName);
+    case aKeyword of
+    ofkAuthorizationUrl: 
+      aObj.AuthorizationUrl:=Readstring;
+    ofkTokenURL: 
+      aObj.TokenURL:=Readstring;
+    ofkRefreshURL: 
+      aObj.RefreshURL:=Readstring;
+    ofkScopes: 
+      ReadObject(aObj.Scopes);
+    else 
+      aObj.Extensions.Add(aName,ReadJSONData);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+
+procedure TOpenAPIReader.ReadHeader(aObj: THeader; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+
+begin
+  DoReadObject(aObj,aCheckBracket);
+end;
+
+
+procedure TOpenAPIReader.ReadHeaderOrReference(aObj: THeaderOrReference; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    if aName='ref' then
+      ReadReference(aObj.Reference,True)
+    else
+      HandleParamOrHeader(aObj,aName);
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+
+procedure TOpenAPIReader.ReadHeaderOrReferenceUnTyped(aObj: TBaseOpenAPIObject; aCheckBracket: Boolean);
+
+begin
+  ReadHeaderOrReference(aObj as THeaderOrReference,aCheckBracket)
+end;
+
+procedure TOpenAPIReader.ReadHeaderOrReferenceMap(aObj: THeaderOrReferenceMap; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+
+begin
+  ReadMapObject(aObj,@ReadHeaderOrReferenceUnTyped,aCheckBracket);
+end;
+
+
+
+procedure TOpenAPIReader.ReadCallbackOrReference(aObj: TCallbackOrReference; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+  itm : TPathItem;
+
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    case aName of
+      'ref' : ReadReference(aObj.Reference);
+    else 
+      Itm:=aObj.AddItem(Name);
+      ReadPathItem(Itm);
+    end;
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+procedure TOpenAPIReader.ReadCallbackOrReferenceUnTyped(aObj: TBaseOpenAPIObject; aCheckBracket: Boolean);
+begin
+  ReadCallbackOrReference(aObj as TCallbackOrReference,aCheckBracket);
+end;
+
+procedure TOpenAPIReader.ReadCallbackOrReferenceMap(aObj: TCallbackOrReferenceMap; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+
+begin
+  ReadMapObject(aObj,@ReadCallbackOrReferenceUnTyped,aCheckBracket);
+end;
+
+
+procedure TOpenAPIReader.ReadSecurityRequirement(aObj: TSecurityRequirement; aCheckBracket: Boolean);
+// On entry, we are on { token if aCheckBracket is false, before if it is true
+var
+  atoken : TJSONToken;
+  aName : String;
+
+begin
+  if aCheckBracket then
+    checkNextToken(tkCurlyBraceOpen);
+  aToken:=CheckNextToken([tkString,tkIdentifier,tkCurlyBraceClose]);
+  While not (aToken in [tkEOF,tkCurlyBraceClose]) do
+    begin
+    aName:=GetTokenString;
+    CheckNextToken(tkColon);
+    ReadObject(aObj.AddItem(aName));
+    aToken:=CheckNextToken([tkComma,tkCurlyBraceClose]);
+    if aToken=tkComma then
+       aToken:=CheckNextToken([tkString,tkIdentifier]);
+    end;
+  CheckToken(tkCurlyBraceClose,aToken);
+end;
+
+function TOpenAPIReader.ReadSecurityRequirementObject(aParent: TBaseOpenAPIObject; aName: TJSONStringType): TBaseOpenAPIObject;
+
+begin
+  Result:=TSecurityRequirement.Create(aParent,aName);
+  try
+    ReadSecurityRequirement(TSecurityRequirement(Result),False);
+  except
+    Result.Free;
+    Raise;
+  end;
+end;
+
+procedure TOpenAPIReader.ReadSecurityRequirementList(aObj: TSecurityRequirementList);
+
+begin
+  ReadObjectArray(aObj,@ReadSecurityRequirementObject);
+end;
+
+function TOpenAPIReader.ReadTagObject(aParent: TBaseOpenAPIObject; aName: TJSONStringType): TBaseOpenAPIObject;
+
+begin
+  Result:=TTag.Create(aParent,aName);
+  try
+    ReadTag(TTag(Result),False);
+  except
+    Result.Free;
+    Raise;
+  end;
+end;
+
+procedure TOpenAPIReader.ReadTagList(aObj: TTagList);
+begin
+  ReadObjectArray(aObj,@ReadTagObject);
+end;
+
+procedure TOpenAPIReader.ReadFromScanner(aOpenAPI: TOpenAPI; AScanner: TJSONScanner);
+begin
+  FScanner:=aScanner;
+  try
+    ReadOpenApi(aOpenApi);
+  finally
+    FScanner:=Nil;
+  end;
+end;
+
+procedure TOpenAPIReader.ReadFromFile(aOpenAPI: TOpenAPI; const AFilename: String);
+
+var
+  F : TFileStream;
+begin
+  F:=TFileStream.Create(aFilename,fmOpenRead or fmShareDenyWrite);
+  try
+    ReadFromStream(aOpenAPI,F);
+  finally
+    F.Free;
+  end;
+end;
+
+procedure TOpenAPIReader.ReadFromStream(aOpenAPI: TOpenAPI; AStream: TStream);
+
+var
+  S : TJSONScanner;
+
+begin
+  S:=TJSONScanner.Create(aStream,[joUTF8]);
+  try
+    ReadFromScanner(aOpenAPI,S);
+  finally
+    S.Free;
+  end;
+end;
+
+procedure TOpenAPIReader.ReadFromString(aOpenAPI: TOpenAPI; const AString: TJSONStringType);
+var
+  S: TStringStream;
+begin
+  S:=TStringStream.Create(AString);
+  try
+    ReadFromStream(aOpenAPI,S);
+  finally
+    S.Free;
+  end;
+end;
+
+end.

+ 1496 - 0
packages/fcl-openapi/src/fpopenapi.types.pp

@@ -0,0 +1,1496 @@
+{
+    This file is part of the Free Component Library (FCL)
+    Copyright (c) 2024 by Michael Van Canneyt ([email protected])
+
+    Basic OpenAPI types
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+
+unit fpopenapi.types;
+
+{$mode ObjFPC}{$H+}
+{$modeswitch typehelpers}
+
+interface
+
+uses
+  {$IFDEF FPC_DOTTEDUNITS}
+  System.SysUtils, System.Classes;
+  {$ELSE}
+  sysutils, classes;
+  {$ENDIF}
+
+Type
+  // OpenApi object
+  TOpenAPIKeyword = (oakUnknown, oakOpenApi, oakInfo, oakJSONSchemaDialect, oakServers, oakPaths,
+                     oakWebHooks, oakComponents, oakSecurity, oakTags, oakExternalDocs);
+  // Info Object
+  TInfoKeyword = (ikUnknown, ikTitle, ikSummary, ikDescription, ikTermsOfService,
+                  ikContact,ikLicense, ikVersion);
+
+  // Contact object
+  TContactKeyword = (cokUnknown, cokName,cokUrl,cokEmail);
+
+  // License Object
+  TLicenseKeyword = (lkUnknown, lkName, lkIdentifier, lkUrl);
+
+  // Server object
+  TServerKeyword = (skUnknown, skServerUrl,skDescription,skVariables);
+
+  // Server Variable object
+  TServerVariableKeyword = (svkUnknown, svkEnum,svkDefault,svkDescription);
+
+  // Components object
+  TComponentsKeyword = (ckUnknown, ckSchemas, ckResponses, ckParameters, ckExamples, ckRequestBodies, ckHeaders,
+                        ckSecuritySchemes,ckLinks,ckCallbacks,ckPathItems);
+
+  // Path item object
+  TPathItemKeyword = (pkUnknown, pkRef, pkSummary, pkDescription, pkGet, pkPut, pkPost, pkDelete, pkOptions,
+                      pkHead, pkPatch, pkTrace, pkServers, pkParameters);
+
+  TPathItemOperationKeyword = pkGet..pkTrace;
+
+  // Operation object
+  TApiOperationKeyword = (okUnknown, okTags, okSummary, okDescription, okExternalDocs, okOperationId, okParameters, okRequestBody,
+                       okResponses, okCallbacks, okDeprecated, okSecurity, okServers);
+  // External documentaton object
+  TExternalDocumentationKeyword = (edkUnknown, edkDescription, edkUrl);
+
+  // Parameter object
+  TParameterKeyword = (pakUnknown, pakName, pakIn, pakDescription, pakRequired, pakDeprecated, pakAllowEmptyValue,
+                       pakStyle, pakExplode, pakAllowReserved, pakSchema, pakExample, pakExamples,
+                       pakContent);
+
+  // ParameterStyle
+  TParameterStyleKeyword = (pskUnknown, pskMatrix, pskLabel, pskForm, pskSimple, pskSpaceDelimited, pskPipeDelimited, pskDeepObject);
+
+  // Request body object
+  TRequestBodyKeyword = (rbkUnknown, rbkDescription, rbkContent, rbkRequired);
+
+  // Media Type Object
+  TMediaTypeKeyword = (mtkUnknown, mtkSchema, mtkExample, mtkExamples, mtkEncoding);
+
+  // Encoding object
+  TEncodingKeyword = (eckUnknown, eckContentType, eckHeaders, eckStyle, eckExplode, eckAllowReserved);
+
+  // Responses Object
+  TResponsesKeyword = (rskUnknown, rskDefault);
+
+  // Response Object
+  TResponseKeyword = (rkUnknown, rkDescription, rkHeaders, rkContent, rkLinks);
+
+  // Example object
+  TExampleKeyword = (exkUnknown, exkSummary, exkDescription, exkValue, exkExternalValue);
+
+  // Link Object
+  TLinkKeyword = (likUnknown, likOperationRef, likOperationId, likParameters, likRequestBody, likDescription, likServer);
+
+  // Tag Object
+  TTagKeyword = (tkUnknown, tkName, tkDescription, tkExternalDocs);
+
+  // Reference Object
+  TReferenceKeyword = (rfkUnknown, rfkRef, rfkSummary, rfkDescription);
+
+  // Schema object
+  TSchemaKeyword = (sckUnknown, sckDiscriminator, sckXML, sckExternalDocs, sckExample);
+
+  TDiscriminatorKeyword = (dikUnknown, dikPropertyName, dikMapping);
+
+  // XML Object
+  TXMLKeyword = (xmkUnknown, xmkName, xmkNamespace, xmkPrefix, xmkAttribute, xmkWrapped);
+
+  // Security scheme object
+  TSecuritySchemeKeyword = (sskUnknown, sskType, sskDescription, sskName, sskIn, sskScheme, sskBearerFormat, sskFlows, sskOpenIdConnectUrl);
+
+  // Oauth Flows object
+  TOAuthFlowsKeyword = (ofskUnknown, ofskImplicit, ofskPassword, ofskClientCredentials, ofskClientAuthorizationCode);
+
+  // Oauth Flow object
+  TOauthFlowKeyword = (ofkUnknown, ofkAuthorizationUrl, ofkTokenURL, ofkRefreshURL, ofkScopes);
+
+  // Pseudo objects
+{  THeaderKeyword = (hekUnknown, hekHeader);
+  TCallbackKeyword = (cbkUnknown, cbkCallback);}
+  TSecurityRequirementKeyword = (srkUnknown, srkSecurityRequirement);
+
+  TOpenAPIKeywords = set of TOpenAPIKeyword;
+  TInfoKeywords = set of TInfoKeyword;
+  TContactKeywords = set of TContactKeyword;
+  TLicenseKeywords = set of TLicenseKeyword;
+  TServerKeywords = set of TServerKeyword;
+  TServerVariableKeywords = set of TServerVariableKeyword;
+  TComponentsKeywords = set of TComponentsKeyword;
+  TPathItemKeywords = set of TPathItemKeyword;
+  TOperationKeywords = set of TAPiOperationKeyword;
+  TApiOperationKeywords = TOperationKeywords;
+  TExternalDocumentationKeywords = set of TExternalDocumentationKeyword;
+  TParameterKeywords = set of TParameterKeyword;
+  TParameterStyleKeywords = set of TParameterStyleKeyword;
+  TRequestBodyKeywords = set of TRequestBodyKeyword;
+  TMediaTypeKeywords = set of TMediaTypeKeyword;
+  TEncodingKeywords = set of TEncodingKeyword;
+  TResponsesKeywords = set of TResponsesKeyword;
+  TResponseKeywords = set of TResponseKeyword;
+  TExampleKeywords = set of TExampleKeyword;
+  TLinkKeywords = set of TLinkKeyword;
+  TTagKeywords = set of TTagKeyword;
+  TReferenceKeywords = set of TReferenceKeyword;
+  TSchemaKeywords = set of TSchemaKeyword;
+  TDiscriminatorKeywords = set of TDiscriminatorKeyword;
+  TXMLKeywords = set of TXMLKeyword;
+  TSecuritySchemeKeywords = set of TSecuritySchemeKeyword;
+  TOAuthFlowsKeywords = set of TOAuthFlowsKeyword;
+  TOauthFlowKeywords = set of TOauthFlowKeyword;
+  TSecurityRequirementKeywords = set of TSecurityRequirementKeyword;
+//  THeaderKeywords = set of THeaderKeyword;
+//  TCallbackKeywords = set of TCallbackKeyword;
+
+  TOpenAPIKeywordHelper = type helper for TOpenAPIKeyword
+  Private
+    procedure SetAsString(const aValue : string);
+  public
+    function ToString : String;
+    class function fromString(const aValue : string) : TOpenAPIKeyword; static;
+    property AsString : string read toString Write SetAsString;
+  end;
+
+  TInfoKeywordHelper = type helper for TInfoKeyword
+  Private
+    procedure SetAsString(const aValue : string);
+  public
+    function ToString : String;
+    class function fromString(const aValue : string) : TInfoKeyword; static;
+    property AsString : string read toString Write SetAsString;
+  end;
+
+  TContactKeywordHelper = type helper for TContactKeyword
+  Private
+    procedure SetAsString(const aValue : string);
+  public
+    function ToString : String;
+    class function fromString(const aValue : string) : TContactKeyword; static;
+    property AsString : string read toString Write SetAsString;
+  end;
+
+  TLicenseKeywordHelper = type helper for TLicenseKeyword
+  Private
+    procedure SetAsString(const aValue : string);
+  public
+    function ToString : String;
+    class function fromString(const aValue : string) : TLicenseKeyword; static;
+    property AsString : string read toString Write SetAsString;
+  end;
+
+  TServerKeywordHelper = type helper for TServerKeyword
+  Private
+    procedure SetAsString(const aValue : string);
+  public
+    function ToString : String;
+    class function fromString(const aValue : string) : TServerKeyword; static;
+    property AsString : string read toString Write SetAsString;
+  end;
+
+  TServerVariableKeywordHelper = type helper for TServerVariableKeyword
+  Private
+    procedure SetAsString(const aValue : string);
+  public
+    function ToString : String;
+    class function fromString(const aValue : string) : TServerVariableKeyword; static;
+    property AsString : string read toString Write SetAsString;
+  end;
+
+  TComponentsKeywordHelper = type helper for TComponentsKeyword
+  Private
+    procedure SetAsString(const aValue : string);
+  public
+    function ToString : String;
+    class function fromString(const aValue : string) : TComponentsKeyword; static;
+    property AsString : string read toString Write SetAsString;
+  end;
+
+  TPathItemKeywordHelper = type helper for TPathItemKeyword
+  Private
+    procedure SetAsString(const aValue : string);
+  public
+    function ToString : String;
+    class function fromString(const aValue : string) : TPathItemKeyword; static;
+    property AsString : string read toString Write SetAsString;
+  end;
+
+  TOperationKeywordHelper = type helper for TApiOperationKeyword
+  Private
+    procedure SetAsString(const aValue : string);
+  public
+    function ToString : String;
+    class function fromString(const aValue : string) : TApiOperationKeyword; static;
+    property AsString : string read toString Write SetAsString;
+  end;
+
+  TExternalDocumentationKeywordHelper = type helper for TExternalDocumentationKeyword
+  Private
+    procedure SetAsString(const aValue : string);
+  public
+    function ToString : String;
+    class function fromString(const aValue : string) : TExternalDocumentationKeyword; static;
+    property AsString : string read toString Write SetAsString;
+  end;
+
+  TParameterKeywordHelper = type helper for TParameterKeyword
+  Private
+    procedure SetAsString(const aValue : string);
+  public
+    function ToString : String;
+    class function fromString(const aValue : string) : TParameterKeyword; static;
+    property AsString : string read toString Write SetAsString;
+  end;
+
+  TParameterStyleKeywordHelper = type helper for TParameterStyleKeyword
+  Private
+    procedure SetAsString(const aValue : string);
+  public
+    function ToString : String;
+    class function fromString(const aValue : string) : TParameterStyleKeyword; static;
+    property AsString : string read toString Write SetAsString;
+  end;
+
+  TRequestBodyKeywordHelper = type helper for TRequestBodyKeyword
+  Private
+    procedure SetAsString(const aValue : string);
+  public
+    function ToString : String;
+    class function fromString(const aValue : string) : TRequestBodyKeyword; static;
+    property AsString : string read toString Write SetAsString;
+  end;
+
+  TMediaTypeKeywordHelper = type helper for TMediaTypeKeyword
+  Private
+    procedure SetAsString(const aValue : string);
+  public
+    function ToString : String;
+    class function fromString(const aValue : string) : TMediaTypeKeyword; static;
+    property AsString : string read toString Write SetAsString;
+  end;
+
+  TEncodingKeywordHelper = type helper for TEncodingKeyword
+  Private
+    procedure SetAsString(const aValue : string);
+  public
+    function ToString : String;
+    class function fromString(const aValue : string) : TEncodingKeyword; static;
+    property AsString : string read toString Write SetAsString;
+  end;
+
+  TResponsesKeywordHelper = type helper for TResponsesKeyword
+  Private
+    procedure SetAsString(const aValue : string);
+  public
+    function ToString : String;
+    class function fromString(const aValue : string) : TResponsesKeyword; static;
+    property AsString : string read toString Write SetAsString;
+  end;
+
+  TResponseKeywordHelper = type helper for TResponseKeyword
+  Private
+    procedure SetAsString(const aValue : string);
+  public
+    function ToString : String;
+    class function fromString(const aValue : string) : TResponseKeyword; static;
+    property AsString : string read toString Write SetAsString;
+  end;
+
+  TExampleKeywordHelper = type helper for TExampleKeyword
+  Private
+    procedure SetAsString(const aValue : string);
+  public
+    function ToString : String;
+    class function fromString(const aValue : string) : TExampleKeyword; static;
+    property AsString : string read toString Write SetAsString;
+  end;
+
+  TLinkKeywordHelper = type helper for TLinkKeyword
+  Private
+    procedure SetAsString(const aValue : string);
+  public
+    function ToString : String;
+    class function fromString(const aValue : string) : TLinkKeyword; static;
+    property AsString : string read toString Write SetAsString;
+  end;
+
+  TTagKeywordHelper = type helper for TTagKeyword
+  Private
+    procedure SetAsString(const aValue : string);
+  public
+    function ToString : String;
+    class function fromString(const aValue : string) : TTagKeyword; static;
+    property AsString : string read toString Write SetAsString;
+  end;
+
+  TReferenceKeywordHelper = type helper for TReferenceKeyword
+  Private
+    procedure SetAsString(const aValue : string);
+  public
+    function ToString : String;
+    class function fromString(const aValue : string) : TReferenceKeyword; static;
+    property AsString : string read toString Write SetAsString;
+  end;
+
+  TSchemaKeywordHelper = type helper for TSchemaKeyword
+  Private
+    procedure SetAsString(const aValue : string);
+  public
+    function ToString : String;
+    class function fromString(const aValue : string) : TSchemaKeyword; static;
+    property AsString : string read toString Write SetAsString;
+  end;
+
+  TDiscriminatorKeywordHelper = type helper for TDiscriminatorKeyword
+  Private
+    procedure SetAsString(const aValue : string);
+  public
+    function ToString : String;
+    class function fromString(const aValue : string) : TDiscriminatorKeyword; static;
+    property AsString : string read toString Write SetAsString;
+  end;
+
+  TXMLKeywordHelper = type helper for TXMLKeyword
+  Private
+    procedure SetAsString(const aValue : string);
+  public
+    function ToString : String;
+    class function fromString(const aValue : string) : TXMLKeyword; static;
+    property AsString : string read toString Write SetAsString;
+  end;
+
+  TSecuritySchemeKeywordHelper = type helper for TSecuritySchemeKeyword
+  Private
+    procedure SetAsString(const aValue : string);
+  public
+    function ToString : String;
+    class function fromString(const aValue : string) : TSecuritySchemeKeyword; static;
+    property AsString : string read toString Write SetAsString;
+  end;
+
+  TOAuthFlowsKeywordHelper = type helper for TOAuthFlowsKeyword
+  Private
+    procedure SetAsString(const aValue : string);
+  public
+    function ToString : String;
+    class function fromString(const aValue : string) : TOAuthFlowsKeyword; static;
+    property AsString : string read toString Write SetAsString;
+  end;
+
+  TOauthFlowKeywordHelper = type helper for TOauthFlowKeyword
+  Private
+    procedure SetAsString(const aValue : string);
+  public
+    function ToString : String;
+    class function fromString(const aValue : string) : TOauthFlowKeyword; static;
+    property AsString : string read toString Write SetAsString;
+  end;
+
+
+implementation
+
+uses fpopenapi.consts;
+
+Const
+  OpenAPIKeywordNames : Array[TOpenAPIKeyword] of string = (
+    '?',
+    KWOpenAPIOpenApi,
+    KWOpenAPIInfo,
+    KWOpenAPIJSONSchemaDialect,
+    KWOpenAPIServers,
+    KWOpenAPIPaths,
+    KWOpenAPIWebHooks,
+    KWOpenAPIComponents,
+    KWOpenAPISecurity,
+    KWOpenAPITags,
+    KWOpenAPIExternalDocs
+  );
+
+  InfoKeywordNames : Array[TInfoKeyword] of string = (
+    '?',
+    KWInfoTitle,
+    KWInfoSummary,
+    KWInfoDescription,
+    KWInfoTermsOfService,
+    KWInfoContact,
+    KWInfoLicense,
+    KWInfoVersion
+  );
+
+  ContactKeywordNames : Array[TContactKeyword] of string = (
+    '?',
+    KWContactName,
+    KWContactUrl,
+    KWContactEmail
+  );
+
+  LicenseKeywordNames : Array[TLicenseKeyword] of string = (
+    '?',
+    KWLicenseName,
+    KWLicenseIdentifier,
+    KWLicenseUrl
+  );
+
+  ServerKeywordNames : Array[TServerKeyword] of string = (
+    '?',
+    KWServerUrl,
+    KWServerDescription,
+    KWServerVariables
+  );
+
+  ServerVariableKeywordNames : Array[TServerVariableKeyword] of string = (
+    '?',
+    KWServerVariableEnum,
+    KWServerVariableDefault,
+    KWServerVariableDescription
+  );
+
+  ComponentsKeywordNames : Array[TComponentsKeyword] of string = (
+    '?',
+    KWComponentsSchemas,
+    KWComponentsResponses,
+    KWComponentsParameters,
+    KWComponentsExamples,
+    KWComponentsRequestBodies,
+    KWComponentsHeaders,
+    KWComponentsSecuritySchemes,
+    KWComponentsLinks,
+    KWComponentsCallbacks,
+    KWComponentsPathItems
+  );
+
+  PathItemKeywordNames : Array[TPathItemKeyword] of string = (
+    '?',
+    KWPathItemRef,
+    KWPathItemSummary,
+    KWPathItemDescription,
+    KWPathItemGet,
+    KWPathItemPut,
+    KWPathItemPost,
+    KWPathItemDelete,
+    KWPathItemOptions,
+    KWPathItemHead,
+    KWPathItemPatch,
+    KWPathItemTrace,
+    KWPathItemServers,
+    KWPathItemParameters
+  );
+
+  OperationKeywordNames : Array[TAPiOperationKeyword] of string = (
+    '?',
+    KWOperationTags,
+    KWOperationSummary,
+    KWOperationDescription,
+    KWOperationExternalDocs,
+    KWOperationOperationId,
+    KWOperationParameters,
+    KWOperationRequestBody,
+    KWOperationResponses,
+    KWOperationCallbacks,
+    KWOperationDeprecated,
+    KWOperationSecurity,
+    KWOperationServers
+  );
+
+  ExternalDocsKeywordNames : Array[TExternalDocumentationKeyword] of string = (
+    '?',
+    KWExternalDocsDescription,
+    KWExternalDocsUrl
+  );
+
+  ParameterKeywordNames : Array[TParameterKeyword] of string = (
+    '?',
+    KWParameterName,
+    KWParameterIn,
+    KWParameterDescription,
+    KWParameterRequired,
+    KWParameterDeprecated,
+    KWParameterAllowEmptyValue,
+    KWParameterStyle,
+    KWParameterExplode,
+    KWParameterAllowReserved,
+    KWParameterSchema,
+    KWParameterExample,
+    KWParameterExamples,
+    KWParameterContent
+  );
+
+  ParameterStyleNames : Array[TParameterStyleKeyword] of string = (
+    '?',
+    KWParameterStyleMatrix,
+    KWParameterStyleLabel,
+    KWParameterStyleForm,
+    KWParameterStyleSimple,
+    KWParameterStyleSpaceDelimited,
+    KWParameterStylePipeDelimited,
+    KWParameterStyleDeepObject
+  );
+
+  RequestBodyKeywordNames : Array[TRequestBodyKeyword] of string = (
+    '?',
+    KWRequestBodyDescription,
+    KWRequestBodyContent,
+    KWRequestBodyRequired
+  );
+
+  MediaTypeKeywordNames : Array[TMediaTypeKeyword] of string = (
+    '?',
+    KWMediaTypeSchema,
+    KWMediaTypeExample,
+    KWMediaTypeExamples,
+    KWMediaTypeEncoding
+  );
+
+  EncodingKeywordNames : Array[TEncodingKeyword] of string = (
+    '?',
+    KWEncodingContentType,
+    KWEncodingHeaders,
+    KWEncodingStyle,
+    KWEncodingExplode,
+    KWEncodingAllowReserved
+  );
+
+  ResponsesKeywordNames : Array[TResponsesKeyword] of string = (
+    '?',
+    KWResponsesDefault
+  );
+
+  ResponseKeywordNames : Array[TResponseKeyword] of string = (
+    '?',
+    KWResponseDescription,
+    KWResponseHeaders,
+    KWResponseContent,
+    KWResponseLinks
+  );
+
+  ExampleKeywordNames : Array[TExampleKeyword] of string = (
+    '?',
+    KWExampleSummary,
+    KWExampleDescription,
+    KWExampleValue,
+    KWExampleExternalValue
+  );
+
+  LinkKeywordNames : Array[TLinkKeyword] of string = (
+    '?',
+    KWLinkOperationRef,
+    KWLinkOperationId,
+    KWLinkParameters,
+    KWLinkRequestBody,
+    KWLinkDescription,
+    KWLinkServer
+  );
+
+  TagKeywordNames : Array[TTagKeyword] of string = (
+    '?',
+    KWTagName,
+    KWTagDescription,
+    KWTagExternalDocs
+  );
+
+  ReferenceKeywordNames : Array[TReferenceKeyword] of string = (
+    '?',
+    KWReferenceRef,
+    KWReferenceSummary,
+    KWReferenceDescription
+  );
+
+  SchemaKeywordNames : Array[TSchemaKeyword] of string = (
+    '?',
+    KWSchemaDiscriminator,
+    KWSchemaXML,
+    KWSchemaExternalDocs,
+    KWSchemaExample
+  );
+
+  DiscriminatorKeywordNames : Array[TDiscriminatorKeyword] of string = (
+    '?',
+    KWDiscriminatorPropertyName,
+    KWDiscriminatorMapping
+  );
+
+  XMLKeywordNames : Array[TXMLKeyword] of string = (
+    '?',
+    KWXMLName,
+    KWXMLNamespace,
+    KWXMLPrefix,
+    KWXMLAttribute,
+    KWXMLWrapped
+  );
+
+  SecuritySchemeKeywordNames : Array[TSecuritySchemeKeyword] of string = (
+    '?',
+    KWSecuritySchemeType,
+    KWSecuritySchemeDescription,
+    KWSecuritySchemeName,
+    KWSecuritySchemeIn,
+    KWSecuritySchemeScheme,
+    KWSecuritySchemeBearerFormat,
+    KWSecuritySchemeFlows,
+    KWSecuritySchemeOpenIdConnectUrl
+  );
+
+  OAuthFlowsKeywordNames : Array[TOAuthFlowsKeyword] of string = (
+    '?',
+    KWOAuthFlowsImplicit,
+    KWOAuthFlowsPassword,
+    KWOAuthFlowsClientCredentials,
+    KWOAuthFlowsClientAuthorizationCode
+  );
+
+  OauthFlowKeywordNames : Array[TOauthFlowKeyword] of string = (
+    '?',
+    KWOauthFlowAuthorizationUrl,
+    KWOauthFlowTokenURL,
+    KWOauthFlowRefreshURL,
+    KWOauthFlowScopes
+  );
+
+procedure TOpenAPIKeywordHelper.SetAsString(const aValue : string);
+
+var
+  T : TOpenAPIKeyword;
+
+begin
+  Self:=Default(TOpenAPIKeyword);
+  For T in TOpenAPIKeyword do
+    if (T.AsString=aValue) then
+      begin
+      self:=T;
+      exit;
+      end;
+end;
+
+
+function TOpenAPIKeywordHelper.ToString : String;
+
+begin
+  Result:=OpenAPIKeywordNames[Self];
+end;
+
+
+class function TOpenAPIKeywordHelper.fromString(const aValue : string) : TOpenAPIKeyword;
+
+begin
+  Result:=Default(TOpenAPIKeyword);
+  Result.AsString:=aValue;
+end;
+
+
+procedure TInfoKeywordHelper.SetAsString(const aValue : string);
+
+var
+  T : TInfoKeyword;
+
+begin
+  Self:=Default(TInfoKeyword);
+  For T in TInfoKeyword do
+    if (T.AsString=aValue) then
+      begin
+      self:=T;
+      exit;
+      end;
+end;
+
+
+function TInfoKeywordHelper.ToString : String;
+
+begin
+  Result:=InfoKeywordNames[Self];
+end;
+
+
+class function TInfoKeywordHelper.fromString(const aValue : string) : TInfoKeyword;
+
+begin
+  Result:=Default(TInfoKeyword);
+  Result.AsString:=aValue;
+end;
+
+
+procedure TContactKeywordHelper.SetAsString(const aValue : string);
+
+var
+  T : TContactKeyword;
+
+begin
+  Self:=Default(TContactKeyword);
+  For T in TContactKeyword do
+    if (T.AsString=aValue) then
+      begin
+      self:=T;
+      exit;
+      end;
+end;
+
+
+function TContactKeywordHelper.ToString : String;
+
+begin
+  Result:=ContactKeywordNames[Self];
+end;
+
+
+class function TContactKeywordHelper.fromString(const aValue : string) : TContactKeyword;
+
+begin
+  Result:=Default(TContactKeyword);
+  Result.AsString:=aValue;
+end;
+
+
+procedure TLicenseKeywordHelper.SetAsString(const aValue : string);
+
+var
+  T : TLicenseKeyword;
+
+begin
+  Self:=Default(TLicenseKeyword);
+  For T in TLicenseKeyword do
+    if (T.AsString=aValue) then
+      begin
+      self:=T;
+      exit;
+      end;
+end;
+
+
+function TLicenseKeywordHelper.ToString : String;
+
+begin
+  Result:=LicenseKeywordNames[Self];
+end;
+
+
+class function TLicenseKeywordHelper.fromString(const aValue : string) : TLicenseKeyword;
+
+begin
+  Result:=Default(TLicenseKeyword);
+  Result.AsString:=aValue;
+end;
+
+
+procedure TServerKeywordHelper.SetAsString(const aValue : string);
+
+var
+  T : TServerKeyword;
+
+begin
+  Self:=Default(TServerKeyword);
+  For T in TServerKeyword do
+    if (T.AsString=aValue) then
+      begin
+      self:=T;
+      exit;
+      end;
+end;
+
+
+function TServerKeywordHelper.ToString : String;
+
+begin
+  Result:=ServerKeywordNames[Self];
+end;
+
+
+class function TServerKeywordHelper.fromString(const aValue : string) : TServerKeyword;
+
+begin
+  Result:=Default(TServerKeyword);
+  Result.AsString:=aValue;
+end;
+
+
+procedure TServerVariableKeywordHelper.SetAsString(const aValue : string);
+
+var
+  T : TServerVariableKeyword;
+
+begin
+  Self:=Default(TServerVariableKeyword);
+  For T in TServerVariableKeyword do
+    if (T.AsString=aValue) then
+      begin
+      self:=T;
+      exit;
+      end;
+end;
+
+
+function TServerVariableKeywordHelper.ToString : String;
+
+begin
+  Result:=ServerVariableKeywordNames[Self];
+end;
+
+
+class function TServerVariableKeywordHelper.fromString(const aValue : string) : TServerVariableKeyword;
+
+begin
+  Result:=Default(TServerVariableKeyword);
+  Result.AsString:=aValue;
+end;
+
+
+procedure TComponentsKeywordHelper.SetAsString(const aValue : string);
+
+var
+  T : TComponentsKeyword;
+
+begin
+  Self:=Default(TComponentsKeyword);
+  For T in TComponentsKeyword do
+    if (T.AsString=aValue) then
+      begin
+      self:=T;
+      exit;
+      end;
+end;
+
+
+function TComponentsKeywordHelper.ToString : String;
+
+begin
+  Result:=ComponentsKeywordNames[Self];
+end;
+
+
+class function TComponentsKeywordHelper.fromString(const aValue : string) : TComponentsKeyword;
+
+begin
+  Result:=Default(TComponentsKeyword);
+  Result.AsString:=aValue;
+end;
+
+
+procedure TPathItemKeywordHelper.SetAsString(const aValue : string);
+
+var
+  T : TPathItemKeyword;
+
+begin
+  Self:=Default(TPathItemKeyword);
+  For T in TPathItemKeyword do
+    if (T.AsString=aValue) then
+      begin
+      self:=T;
+      exit;
+      end;
+end;
+
+
+function TPathItemKeywordHelper.ToString : String;
+
+begin
+  Result:=PathItemKeywordNames[Self];
+end;
+
+
+class function TPathItemKeywordHelper.fromString(const aValue : string) : TPathItemKeyword;
+
+begin
+  Result:=Default(TPathItemKeyword);
+  Result.AsString:=aValue;
+end;
+
+
+procedure TOperationKeywordHelper.SetAsString(const aValue : string);
+
+var
+  T : TAPiOperationKeyword;
+
+begin
+  Self:=Default(TApiOperationKeyword);
+  For T in TAPiOperationKeyword do
+    if (T.AsString=aValue) then
+      begin
+      self:=T;
+      exit;
+      end;
+end;
+
+
+function TOperationKeywordHelper.ToString : String;
+
+begin
+  Result:=OperationKeywordNames[Self];
+end;
+
+
+class function TOperationKeywordHelper.fromString(const aValue : string) : TApiOperationKeyword;
+
+begin
+  Result:=Default(TAPiOperationKeyword);
+  Result.AsString:=aValue;
+end;
+
+
+procedure TExternalDocumentationKeywordHelper.SetAsString(const aValue : string);
+
+var
+  T : TExternalDocumentationKeyword;
+
+begin
+  Self:=Default(TExternalDocumentationKeyword);
+  For T in TExternalDocumentationKeyword do
+    if (T.AsString=aValue) then
+      begin
+      self:=T;
+      exit;
+      end;
+end;
+
+
+function TExternalDocumentationKeywordHelper.ToString : String;
+
+begin
+  Result:=ExternalDocsKeywordNames[Self];
+end;
+
+
+class function TExternalDocumentationKeywordHelper.fromString(const aValue : string) : TExternalDocumentationKeyword;
+
+begin
+  Result:=Default(TExternalDocumentationKeyword);
+  Result.AsString:=aValue;
+end;
+
+
+procedure TParameterKeywordHelper.SetAsString(const aValue : string);
+
+var
+  T : TParameterKeyword;
+
+begin
+  Self:=Default(TParameterKeyword);
+  For T in TParameterKeyword do
+    if (T.AsString=aValue) then
+      begin
+      self:=T;
+      exit;
+      end;
+end;
+
+
+function TParameterKeywordHelper.ToString : String;
+
+begin
+  Result:=ParameterKeywordNames[Self];
+end;
+
+
+class function TParameterKeywordHelper.fromString(const aValue : string) : TParameterKeyword;
+
+begin
+  Result:=Default(TParameterKeyword);
+  Result.AsString:=aValue;
+end;
+
+
+procedure TParameterStyleKeywordHelper.SetAsString(const aValue : string);
+
+var
+  T : TParameterStyleKeyword;
+
+begin
+  Self:=Default(TParameterStyleKeyword);
+  For T in TParameterStyleKeyword do
+    if (T.AsString=aValue) then
+      begin
+      self:=T;
+      exit;
+      end;
+end;
+
+
+function TParameterStyleKeywordHelper.ToString : String;
+
+begin
+  Result:=ParameterStyleNames[Self];
+end;
+
+
+class function TParameterStyleKeywordHelper.fromString(const aValue : string) : TParameterStyleKeyword;
+
+begin
+  Result:=Default(TParameterStyleKeyword);
+  Result.AsString:=aValue;
+end;
+
+
+procedure TRequestBodyKeywordHelper.SetAsString(const aValue : string);
+
+var
+  T : TRequestBodyKeyword;
+
+begin
+  Self:=Default(TRequestBodyKeyword);
+  For T in TRequestBodyKeyword do
+    if (T.AsString=aValue) then
+      begin
+      self:=T;
+      exit;
+      end;
+end;
+
+
+function TRequestBodyKeywordHelper.ToString : String;
+
+begin
+  Result:=RequestBodyKeywordNames[Self];
+end;
+
+
+class function TRequestBodyKeywordHelper.fromString(const aValue : string) : TRequestBodyKeyword;
+
+begin
+  Result:=Default(TRequestBodyKeyword);
+  Result.AsString:=aValue;
+end;
+
+
+procedure TMediaTypeKeywordHelper.SetAsString(const aValue : string);
+
+var
+  T : TMediaTypeKeyword;
+
+begin
+  Self:=Default(TMediaTypeKeyword);
+  For T in TMediaTypeKeyword do
+    if (T.AsString=aValue) then
+      begin
+      self:=T;
+      exit;
+      end;
+end;
+
+
+function TMediaTypeKeywordHelper.ToString : String;
+
+begin
+  Result:=MediaTypeKeywordNames[Self];
+end;
+
+
+class function TMediaTypeKeywordHelper.fromString(const aValue : string) : TMediaTypeKeyword;
+
+begin
+  Result:=Default(TMediaTypeKeyword);
+  Result.AsString:=aValue;
+end;
+
+
+procedure TEncodingKeywordHelper.SetAsString(const aValue : string);
+
+var
+  T : TEncodingKeyword;
+
+begin
+  Self:=Default(TEncodingKeyword);
+  For T in TEncodingKeyword do
+    if (T.AsString=aValue) then
+      begin
+      self:=T;
+      exit;
+      end;
+end;
+
+
+function TEncodingKeywordHelper.ToString : String;
+
+begin
+  Result:=EncodingKeywordNames[Self];
+end;
+
+
+class function TEncodingKeywordHelper.fromString(const aValue : string) : TEncodingKeyword;
+
+begin
+  Result:=Default(TEncodingKeyword);
+  Result.AsString:=aValue;
+end;
+
+
+procedure TResponsesKeywordHelper.SetAsString(const aValue : string);
+
+var
+  T : TResponsesKeyword;
+
+begin
+  Self:=Default(TResponsesKeyword);
+  For T in TResponsesKeyword do
+    if (T.AsString=aValue) then
+      begin
+      self:=T;
+      exit;
+      end;
+end;
+
+
+function TResponsesKeywordHelper.ToString : String;
+
+begin
+  Result:=ResponsesKeywordNames[Self];
+end;
+
+
+class function TResponsesKeywordHelper.fromString(const aValue : string) : TResponsesKeyword;
+
+begin
+  Result:=Default(TResponsesKeyword);
+  Result.AsString:=aValue;
+end;
+
+
+procedure TResponseKeywordHelper.SetAsString(const aValue : string);
+
+var
+  T : TResponseKeyword;
+
+begin
+  Self:=Default(TResponseKeyword);
+  For T in TResponseKeyword do
+    if (T.AsString=aValue) then
+      begin
+      self:=T;
+      exit;
+      end;
+end;
+
+
+function TResponseKeywordHelper.ToString : String;
+
+begin
+  Result:=ResponseKeywordNames[Self];
+end;
+
+
+class function TResponseKeywordHelper.fromString(const aValue : string) : TResponseKeyword;
+
+begin
+  Result:=Default(TResponseKeyword);
+  Result.AsString:=aValue;
+end;
+
+
+procedure TExampleKeywordHelper.SetAsString(const aValue : string);
+
+var
+  T : TExampleKeyword;
+
+begin
+  Self:=Default(TExampleKeyword);
+  For T in TExampleKeyword do
+    if (T.AsString=aValue) then
+      begin
+      self:=T;
+      exit;
+      end;
+end;
+
+
+function TExampleKeywordHelper.ToString : String;
+
+begin
+  Result:=ExampleKeywordNames[Self];
+end;
+
+
+class function TExampleKeywordHelper.fromString(const aValue : string) : TExampleKeyword;
+
+begin
+  Result:=Default(TExampleKeyword);
+  Result.AsString:=aValue;
+end;
+
+
+procedure TLinkKeywordHelper.SetAsString(const aValue : string);
+
+var
+  T : TLinkKeyword;
+
+begin
+  Self:=Default(TLinkKeyword);
+  For T in TLinkKeyword do
+    if (T.AsString=aValue) then
+      begin
+      self:=T;
+      exit;
+      end;
+end;
+
+
+function TLinkKeywordHelper.ToString : String;
+
+begin
+  Result:=LinkKeywordNames[Self];
+end;
+
+
+class function TLinkKeywordHelper.fromString(const aValue : string) : TLinkKeyword;
+
+begin
+  Result:=Default(TLinkKeyword);
+  Result.AsString:=aValue;
+end;
+
+
+procedure TTagKeywordHelper.SetAsString(const aValue : string);
+
+var
+  T : TTagKeyword;
+
+begin
+  Self:=Default(TTagKeyword);
+  For T in TTagKeyword do
+    if (T.AsString=aValue) then
+      begin
+      self:=T;
+      exit;
+      end;
+end;
+
+
+function TTagKeywordHelper.ToString : String;
+
+begin
+  Result:=TagKeywordNames[Self];
+end;
+
+
+class function TTagKeywordHelper.fromString(const aValue : string) : TTagKeyword;
+
+begin
+  Result:=Default(TTagKeyword);
+  Result.AsString:=aValue;
+end;
+
+
+procedure TReferenceKeywordHelper.SetAsString(const aValue : string);
+
+var
+  T : TReferenceKeyword;
+
+begin
+  Self:=Default(TReferenceKeyword);
+  For T in TReferenceKeyword do
+    if (T.AsString=aValue) then
+      begin
+      self:=T;
+      exit;
+      end;
+end;
+
+
+function TReferenceKeywordHelper.ToString : String;
+
+begin
+  Result:=ReferenceKeywordNames[Self];
+end;
+
+
+class function TReferenceKeywordHelper.fromString(const aValue : string) : TReferenceKeyword;
+
+begin
+  Result:=Default(TReferenceKeyword);
+  Result.AsString:=aValue;
+end;
+
+
+procedure TSchemaKeywordHelper.SetAsString(const aValue : string);
+
+var
+  T : TSchemaKeyword;
+
+begin
+  Self:=Default(TSchemaKeyword);
+  For T in TSchemaKeyword do
+    if (T.AsString=aValue) then
+      begin
+      self:=T;
+      exit;
+      end;
+end;
+
+
+function TSchemaKeywordHelper.ToString : String;
+
+begin
+  Result:=SchemaKeywordNames[Self];
+end;
+
+
+class function TSchemaKeywordHelper.fromString(const aValue : string) : TSchemaKeyword;
+
+begin
+  Result:=Default(TSchemaKeyword);
+  Result.AsString:=aValue;
+end;
+
+
+procedure TDiscriminatorKeywordHelper.SetAsString(const aValue : string);
+
+var
+  T : TDiscriminatorKeyword;
+
+begin
+  Self:=Default(TDiscriminatorKeyword);
+  For T in TDiscriminatorKeyword do
+    if (T.AsString=aValue) then
+      begin
+      self:=T;
+      exit;
+      end;
+end;
+
+
+function TDiscriminatorKeywordHelper.ToString : String;
+
+begin
+  Result:=DiscriminatorKeywordNames[Self];
+end;
+
+
+class function TDiscriminatorKeywordHelper.fromString(const aValue : string) : TDiscriminatorKeyword;
+
+begin
+  Result:=Default(TDiscriminatorKeyword);
+  Result.AsString:=aValue;
+end;
+
+
+procedure TXMLKeywordHelper.SetAsString(const aValue : string);
+
+var
+  T : TXMLKeyword;
+
+begin
+  Self:=Default(TXMLKeyword);
+  For T in TXMLKeyword do
+    if (T.AsString=aValue) then
+      begin
+      self:=T;
+      exit;
+      end;
+end;
+
+
+function TXMLKeywordHelper.ToString : String;
+
+begin
+  Result:=XMLKeywordNames[Self];
+end;
+
+
+class function TXMLKeywordHelper.fromString(const aValue : string) : TXMLKeyword;
+
+begin
+  Result:=Default(TXMLKeyword);
+  Result.AsString:=aValue;
+end;
+
+
+procedure TSecuritySchemeKeywordHelper.SetAsString(const aValue : string);
+
+var
+  T : TSecuritySchemeKeyword;
+
+begin
+  Self:=Default(TSecuritySchemeKeyword);
+  For T in TSecuritySchemeKeyword do
+    if (T.AsString=aValue) then
+      begin
+      self:=T;
+      exit;
+      end;
+end;
+
+
+function TSecuritySchemeKeywordHelper.ToString : String;
+
+begin
+  Result:=SecuritySchemeKeywordNames[Self];
+end;
+
+
+class function TSecuritySchemeKeywordHelper.fromString(const aValue : string) : TSecuritySchemeKeyword;
+
+begin
+  Result:=Default(TSecuritySchemeKeyword);
+  Result.AsString:=aValue;
+end;
+
+
+procedure TOAuthFlowsKeywordHelper.SetAsString(const aValue : string);
+
+var
+  T : TOAuthFlowsKeyword;
+
+begin
+  Self:=Default(TOAuthFlowsKeyword);
+  For T in TOAuthFlowsKeyword do
+    if (T.AsString=aValue) then
+      begin
+      self:=T;
+      exit;
+      end;
+end;
+
+
+function TOAuthFlowsKeywordHelper.ToString : String;
+
+begin
+  Result:=OAuthFlowsKeywordNames[Self];
+end;
+
+
+class function TOAuthFlowsKeywordHelper.fromString(const aValue : string) : TOAuthFlowsKeyword;
+
+begin
+  Result:=Default(TOAuthFlowsKeyword);
+  Result.AsString:=aValue;
+end;
+
+
+procedure TOauthFlowKeywordHelper.SetAsString(const aValue : string);
+
+var
+  T : TOauthFlowKeyword;
+
+begin
+  Self:=Default(TOauthFlowKeyword);
+  For T in TOauthFlowKeyword do
+    if (T.AsString=aValue) then
+      begin
+      self:=T;
+      exit;
+      end;
+end;
+
+
+function TOauthFlowKeywordHelper.ToString : String;
+
+begin
+  Result:=OauthFlowKeywordNames[Self];
+end;
+
+
+class function TOauthFlowKeywordHelper.fromString(const aValue : string) : TOauthFlowKeyword;
+
+begin
+  Result:=Default(TOauthFlowKeyword);
+  Result.AsString:=aValue;
+end;
+
+
+end.
+

+ 1602 - 0
packages/fcl-openapi/src/fpopenapi.writer.pp

@@ -0,0 +1,1602 @@
+{
+    This file is part of the Free Component Library (FCL)
+    Copyright (c) 2024 by Michael Van Canneyt ([email protected])
+
+    Classes for writing a OpenAPI document.
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+
+unit fpopenapi.writer;
+
+{$mode objfpc}
+{$h+}
+
+interface
+
+ uses 
+  {$IFDEF FPC_DOTTEDUNITS}
+  System.SysUtils, System.Classes, System.Contnrs, FpJson.Data, FpJson.Writer, 
+  {$ELSE}
+  sysutils, classes, contnrs, fpjson, jsonwriter, 
+  {$ENDIF}
+  fpopenapi.types, fpopenapi.objects, fpjson.schema.schema, fpjson.schema.Writer;
+
+Type
+  EOpenAPIWriter = Class(EOpenAPi);
+
+  { TOpenAPIReader }
+  TWriteObjectFunc = Procedure(aObject : TBaseOpenAPIObject) of object;
+
+  { TOpenAPIWriter }
+
+  TOpenAPIWriter = Class(TComponent)
+  Private
+    FWriter : TAbstractJSONWriter;
+    FSchemaWriter : TJSONSchemaWriter;
+    // Untyped callbacks
+    procedure WriteServerVariableUntyped(aObj: TBaseOpenAPIObject);
+    procedure WritePathItemUntyped(aObj: TBaseOpenAPIObject);
+    procedure WritePathItemOrReferenceUnTyped(aObj: TBaseOpenAPIObject);
+    procedure WriteParameterOrReferenceUntyped(aObj: TBaseOpenAPIObject);
+    procedure WriteRequestBodyOrReferenceUnTyped(aObj: TBaseOpenAPIObject);
+    procedure WriteMediaTypeUnTyped(aObj: TBaseOpenAPIObject);
+    procedure WriteEncodingUntyped(aObj: TBaseOpenAPIObject);
+    procedure WriteResponseOrReferenceUnTyped(aObj: TBaseOpenAPIObject);
+    procedure WriteExampleOrReferenceUnTyped(aObj: TBaseOpenAPIObject);
+    procedure WriteLinkOrReferenceUntyped(aObj: TBaseOpenAPIObject);
+    procedure WriteHeaderOrReferenceUnTyped(aObj: TBaseOpenAPIObject);
+    procedure WriteSecuritySchemeOrReferenceUnTyped(aObj: TBaseOpenAPIObject);
+    procedure WriteCallbackOrReferenceUnTyped(aObj: TBaseOpenAPIObject);
+    procedure WriteTagUnTyped(aObj: TBaseOpenAPIObject);
+    procedure WriteSecurityRequirementUnTyped(aObj: TBaseOpenAPIObject);
+    procedure WriteResponseUntyped(aObj: TBaseOpenAPIObject);
+//  Protected
+    // utility
+    Procedure StartObjectProp(const aName : String); inline;
+    Procedure EndObjectProp; inline;
+    Procedure StartArrayProp(const aName : String); inline;
+    Procedure EndArrayProp; inline;
+    Procedure WriteProperty(const aName : String; const aValue : String); inline;
+    Procedure WriteProperty(const aName : String; const aValue : Boolean); inline;
+    Procedure WriteProperty(const aName : String; const aValue : Integer); inline;
+    Procedure WriteProperty(const aName : String; const aValue : Int64); inline;
+    Procedure WriteProperty(const aName : String; const aValue : Double); inline;
+    Procedure WriteProperty(const aName : String; const aValue : TJSONSchema); inline;
+    Procedure WriteProperty(const aName : String; const aValue : TJSONData); inline;
+    procedure WriteStrings(const aKey : String; aList : TStrings) ;
+    procedure WriteExtensions(aObj : TJSONObject);
+    procedure WriteObjectArray(const aKey: String; aList: TFPObjectList; aWriteObject: TWriteObjectFunc); overload;
+    procedure WriteMapObject(const aKey : String; aList: TNamedOpenAPIObjectList; aObjectWriter : TWriteObjectFunc);
+    procedure WriteMapObject(aList: TNamedOpenAPIObjectList; aObjectWriter : TWriteObjectFunc);
+    // objects
+    procedure WriteOpenAPI(aObj : TOpenAPI); virtual; overload;
+    procedure WriteInfo(const aKey: string; aObj: TInfo);
+    procedure WriteInfo(aObj: TInfo); virtual; overload;
+    procedure WriteContact(const aKey: string; aObj: TContact);
+    procedure WriteContact(aObj: TContact); virtual; overload;
+    procedure WriteLicense(const aKey: string; aObj: TLicense);
+    procedure WriteLicense(aObj: TLicense); virtual; overload;
+    procedure WriteServer(aObj: TServer); virtual; overload;
+    procedure WriteServer(const aKey: string; aObj: TServer); virtual; overload;
+    procedure WriteServerList(const aKey : string; aObj : TServerList); virtual; overload;
+    procedure WritePathsList(const aKey : string; aObj : TPathsList); virtual; overload;
+    procedure WriteServerVariable(aObj : TServerVariable); virtual; overload;
+    procedure WriteServerVariableMap(const aKey: string; aObj: TServerVariableMap); virtual; overload;
+    procedure WriteJSONSchemaMap(const aKey: String; aObj: TJSONSchemaMap); virtual; overload;
+    procedure WriteComponents(aObj : TComponents); virtual; overload;
+    procedure WriteComponents(const aKey : String; aObj : TComponents);
+    procedure WritePathItem(aObj : TPathItem); virtual; overload;
+    procedure WritePathItemOrReference(aObj : TPathItemOrReference); virtual; overload;
+    procedure WritePathItemOrReferenceMap(const aKey : string; aObj : TPathItemOrReferenceMap); virtual; overload;
+    procedure WriteApiOperation(aObj: TApiOperation);
+    procedure WriteApiOperation(aKey : string; aObj : TApiOperation); virtual; overload;
+    procedure WriteExternalDocumentation(aObj : TExternalDocumentation); virtual; overload;
+    procedure WriteExternalDocumentation(const aKey : String; aObj : TExternalDocumentation); virtual; overload;
+    procedure WriteParameterOrHeader(aObj: TParameterOrHeader);
+    procedure WriteParameter(aObj : TParameter); virtual; overload;
+    procedure WriteParameterOrReference(aObj : TParameterOrReference); virtual; overload;
+    procedure WriteParameterOrReferenceList(const aKey : string; aObj : TParameterOrReferenceList); virtual; overload;
+    procedure WriteParameterOrReferenceMap(const aKey : String; aObj : TParameterOrReferenceMap); virtual; overload;
+    procedure WriteParameterStyle(aObj : TParameterStyle); virtual; overload;
+    procedure WriteRequestBody(aObj: TRequestBody); virtual; overload;
+    procedure WriteRequestBody(const aKey : string; aObj : TRequestBody);
+    procedure WriteRequestBodyOrReference(aObj : TRequestBodyOrReference); virtual; overload;
+    procedure WriteRequestBodyOrReferenceMap(const aKey : string; aObj : TRequestBodyOrReferenceMap); virtual; overload;
+    procedure WriteMediaType(aObj : TMediaType); virtual; overload;
+    procedure WriteMediaTypeMap(const aKey : String; aObj : TMediaTypeMap); virtual; overload;
+    procedure WriteEncoding(aObj : TEncoding); virtual; overload;
+    procedure WriteEncodingMap(const aKey : string; aObj : TEncodingMap); virtual; overload;
+    procedure WriteResponse(aObj : TResponse); virtual; overload;
+    procedure WriteResponses(const aKey : String; aObj : TResponses); virtual; overload;
+    procedure WriteResponseOrReference(aObj : TResponseOrReference); virtual; overload;
+    procedure WriteResponseOrReferenceMap(const aKey : String; aObj : TResponseOrReferenceMap); virtual; overload;
+    procedure WriteExample(aObj : TExample); virtual; overload;
+    procedure WriteExampleOrReference(aObj : TExampleOrReference); virtual; overload;
+    procedure WriteExampleOrReferenceMap(const aKey : String; aObj : TExampleOrReferenceMap); virtual; overload;
+    procedure WriteLink(aObj : TLink); virtual; overload;
+    procedure WriteLinkOrReference(aObj : TLinkOrReference); virtual; overload;
+    procedure WriteLinkOrReferenceMap(const aKey : string; aObj : TLinkOrReferenceMap); virtual; overload;
+    procedure WriteReference(aObj : TReference); virtual; overload;
+    procedure WriteSchema(aObj : TSchema); virtual; overload;
+    procedure WriteXML(aObj : TXML); virtual; overload;
+    procedure WriteSecurityScheme(aObj : TSecurityScheme); virtual; overload;
+    procedure WriteSecuritySchemeOrReference(aObj : TSecuritySchemeOrReference); virtual; overload;
+    procedure WriteSecuritySchemeOrReferenceMap(const aKey : string; aObj : TSecuritySchemeOrReferenceMap); virtual; overload;
+    procedure WriteOAuthFlow(aObj : TOauthFlow); virtual; overload;
+    procedure WriteOAuthFlow(const aKey : String; aObj : TOauthFlow); virtual; overload;
+    procedure WriteOAuthFlows(aObj : TOAuthFlows); virtual; overload;
+    procedure WriteHeader(aObj : THeader); virtual; overload;
+    procedure WriteHeaderOrReference(aObj : THeaderOrReference); virtual; overload;
+    procedure WriteHeaderOrReferenceMap(const aKey : string; aObj : THeaderOrReferenceMap); virtual; overload;
+    procedure WriteCallbackOrReference(aObj : TCallbackOrReference); virtual; overload;
+    procedure WriteCallbackOrReferenceMap(const aKey : string; aObj : TCallbackOrReferenceMap); virtual; overload;
+    procedure WriteCallBack(aObj: TCallBack);
+    procedure WriteDiscriminator(aObj : TDiscriminator); virtual; overload;
+    procedure WriteDiscriminator(const aKey: string; aObj: TDiscriminator);
+    procedure WriteSecurityRequirement(aObj : TSecurityRequirement); virtual; overload;
+    procedure WriteSecurityRequirement(const aKey: String; aObj: TSecurityRequirement);
+    procedure WriteSecurityRequirementList(const aKey : String; aObj : TSecurityRequirementList); virtual; overload;
+    procedure WriteTag(aObj : TTag); virtual; overload;
+    procedure WriteTagList(const aKey : string; aObj : TTagList); virtual; overload;
+    property Writer : TAbstractJSONWriter Read FWriter;
+ Public
+   procedure Write(aOpenAPI: TOpenAPI; AWriter: TAbstractJSONWriter);
+   procedure WriteToStream(aOpenAPI: TOpenAPI; AStream: TStream);
+   function WriteToJSON(aOpenAPI: TOpenAPI) : TJSONObject;
+   function WriteToString(aOpenAPI: TOpenAPI) : TJSONStringType;
+ end;
+
+implementation
+
+{ ---------------------------------------------------------------------
+  Public routines
+  ---------------------------------------------------------------------}
+
+procedure TOpenAPIWriter.Write(aOpenAPI: TOpenAPI; AWriter: TAbstractJSONWriter);
+begin
+  FWriter:=aWriter;
+  try
+    FSchemaWriter:=TJSONSchemaWriter.Create(Self);
+    WriteOpenAPI(aOpenAPI);
+  finally
+    FreeAndNil(FSchemaWriter);
+    FWriter:=Nil;
+  end;
+end;
+
+procedure TOpenAPIWriter.WriteToStream(aOpenAPI: TOpenAPI; AStream: TStream);
+
+var
+  lWriter : TJSONStreamWriter;
+
+begin
+  lWriter:=TJSONStreamWriter.Create(aStream);
+  try
+    Write(aOpenApi,lWriter);
+  finally
+    lWriter.Free;
+  end;
+
+end;
+
+function TOpenAPIWriter.WriteToJSON(aOpenAPI: TOpenAPI): TJSONObject;
+var
+  lWriter : TJSONDataWriter;
+  lData : TJSONData;
+
+begin
+  lWriter:=TJSONDataWriter.Create;
+  try
+    Write(aOpenApi,lWriter);
+    lData:=lWriter.ExtractData;
+    if lData is TJSONObject then
+      Result:=TJSONObject(lData)
+    else
+      begin
+      lData.Free;
+      Result:=nil;
+      end;
+  finally
+    lWriter.Free;
+  end;
+end;
+
+function TOpenAPIWriter.WriteToString(aOpenAPI: TOpenAPI) : TJSONStringType;
+var
+  S: TStringStream;
+begin
+  S:=TStringStream.Create('');
+  try
+    WriteToStream(aOpenAPI,S);
+    Result:=S.DataString;
+  finally
+    S.Free;
+  end;
+end;
+
+{ ---------------------------------------------------------------------
+  Utility routines
+  ---------------------------------------------------------------------}
+
+procedure TOpenAPIWriter.WriteProperty(const aName: String; const aValue: String);
+
+begin
+  Writer.WriteProperty(aName,aValue);
+end;
+
+procedure TOpenAPIWriter.WriteProperty(const aName: String; const aValue: Boolean);
+
+begin
+  Writer.WriteProperty(aName,aValue);
+end;
+
+procedure TOpenAPIWriter.WriteProperty(const aName: String; const aValue: Integer);
+
+begin
+  Writer.WriteProperty(aName,aValue);
+end;
+
+procedure TOpenAPIWriter.WriteProperty(const aName: String; const aValue: Int64);
+
+begin
+  Writer.WriteProperty(aName,aValue);
+end;
+
+procedure TOpenAPIWriter.WriteProperty(const aName: String; const aValue: Double);
+
+begin
+  Writer.WriteProperty(aName,aValue);
+end;
+
+procedure TOpenAPIWriter.WriteProperty(const aName: String; const aValue: TJSONSchema);
+
+begin
+  Writer.StartProperty(aName);
+  FSchemaWriter.Writeschema(aValue,Writer);
+  Writer.EndProperty;
+end;
+
+procedure TOpenAPIWriter.WriteProperty(const aName: String; const aValue: TJSONData);
+
+begin
+  Writer.WriteProperty(aName,aValue);
+end;
+
+procedure TOpenAPIWriter.StartObjectProp(const aName: String);
+begin
+  Writer.StartProperty(aName);
+  Writer.StartObject;
+end;
+
+procedure TOpenAPIWriter.EndObjectProp;
+
+begin
+  Writer.EndObject;
+  Writer.EndProperty;
+end;
+
+procedure TOpenAPIWriter.StartArrayProp(const aName: String);
+begin
+  Writer.StartProperty(aName);
+  Writer.StartArray;
+end;
+
+procedure TOpenAPIWriter.EndArrayProp;
+begin
+  Writer.EndArray;
+  Writer.EndProperty;
+end;
+
+procedure TOpenAPIWriter.WriteExtensions(aObj : TJSONObject);
+
+var
+  I : Integer;
+
+begin
+  For I:=0 to aObj.Count-1 do
+    WriteProperty(aObj.Names[i],aObj.Items[i]);
+end;
+
+procedure TOpenAPIWriter.WriteMapObject(aList: TNamedOpenAPIObjectList; aObjectWriter: TWriteObjectFunc);
+var
+  I : Integer;
+
+begin
+  For I:=0 to aList.Count-1 do
+    begin
+    StartObjectProp(aList.Names[i]);
+    aObjectWriter(aList.APIObjects[i]);
+    EndObjectProp;
+    end;
+end;
+
+procedure TOpenAPIWriter.WriteStrings(const aKey: String; aList: TStrings);
+
+var
+  S : String;
+
+begin
+  Writer.StartProperty(aKey);
+  Writer.StartArray;
+  For S in aList do
+    begin
+    Writer.NextElement;
+    Writer.WriteValue(S);
+    end;
+  Writer.EndArray;
+  Writer.EndProperty();
+end;
+
+procedure TOpenAPIWriter.WriteObjectArray(const aKey: String; aList: TFPObjectList; aWriteObject: TWriteObjectFunc);
+
+var
+  i : integer;
+
+begin
+  StartArrayProp(aKey);
+  for I:=0 to aList.count-1 do
+    begin
+    Writer.NextElement;
+    Writer.StartObject;
+    aWriteObject(TBaseOpenAPIObject(aList[i]));
+    Writer.EndObject;
+    end;
+  EndArrayProp;
+end;
+
+procedure TOpenAPIWriter.WriteMapObject(const aKey: String; aList: TNamedOpenAPIObjectList; aObjectWriter: TWriteObjectFunc);
+begin
+  StartObjectProp(aKey);
+  WriteMapObject(aList,aObjectWriter);
+  EndObjectProp;
+end;
+
+{ ---------------------------------------------------------------------
+  Objects
+  ---------------------------------------------------------------------}
+
+// OpenAPI
+
+procedure TOpenAPIWriter.WriteOpenAPI(aObj: TOpenAPI);
+
+var
+  lName : String;
+  lKeyword : TOpenAPIKeyword;
+
+begin
+  Writer.StartObject;
+  for lKeyword in TOPenAPIKeyword do
+    if aObj.HasKeyWord(lKeyword) then
+      begin
+      lName:=lKeyword.ToString;
+      case lKeyword of
+      oakOpenApi:
+        WriteProperty(lName,aObj.OpenApi);
+      oakInfo:
+        WriteInfo(lName, aObj.Info);
+      oakJSONSchemaDialect:
+        WriteProperty(lName,aObj.JSONSchemaDialect);
+      oakServers:
+        WriteServerList(lName,aObj.Servers);
+      oakPaths:
+        WritePathsList(lName,aObj.Paths);
+      oakWebHooks:
+        WritePathItemOrReferenceMap(lName,aObj.WebHooks);
+      oakComponents:
+        WriteComponents(lName,aObj.Components);
+      oakSecurity:
+        WriteSecurityRequirementList(lName,aObj.Security);
+      oakTags:
+        WriteTagList(lName,aObj.Tags);
+      oakExternalDocs:
+        WriteExternalDocumentation(lName,aObj.ExternalDocs);
+      end;
+    end;
+  if aObj.HasExtensions then
+    WriteExtensions(aObj.Extensions);
+  Writer.endObject;
+end;
+
+// Info
+
+procedure TOpenAPIWriter.WriteInfo(const aKey : string; aObj: TInfo);
+
+begin
+  StartObjectProp(aKey);
+  WriteInfo(aObj);
+  EndObjectProp;
+end;
+
+procedure TOpenAPIWriter.WriteInfo(aObj: TInfo);
+
+var
+  lName : String;
+  lKeyword : TInfoKeyword;
+
+begin
+  for lKeyword in TInfoKeyword do
+    if aObj.HasKeyWord(lKeyword) then
+      begin
+      lName:=lKeyword.ToString;
+      case lKeyword of
+      ikTitle:
+        WriteProperty(lName,aObj.Title);
+      ikSummary:
+        WriteProperty(lName,aObj.Summary);
+      ikDescription:
+        WriteProperty(lName,aObj.Description);
+      ikTermsOfService:
+        WriteProperty(lName,aObj.TermsOfService);
+      ikContact:
+        WriteContact(lName,aObj.Contact);
+      ikLicense:
+        WriteLicense(lName,aObj.License);
+      ikVersion:
+        WriteProperty(lName,aObj.Version);
+      end;
+      end;
+  if aObj.HasExtensions then
+    WriteExtensions(aObj.Extensions);
+end;
+
+// Contact
+
+procedure TOpenAPIWriter.WriteContact(const aKey : string; aObj: TContact);
+
+begin
+  StartObjectProp(aKey);
+  WriteContact(aObj);
+  EndObjectProp;
+end;
+
+procedure TOpenAPIWriter.WriteContact(aObj: TContact);
+
+var
+  lName : String;
+  lKeyword : TContactKeyword;
+
+begin
+  For lKeyword in TContactKeyword do
+    if aObj.HasKeyWord(lkeyword) then
+      begin
+      lName:=lKeyword.ToString;
+      case lKeyword of
+      cokName:
+        WriteProperty(lName,aObj.Name);
+      cokUrl:
+        WriteProperty(lName,aObj.Url);
+      cokEmail:
+        WriteProperty(lName,aObj.Email);
+      end;
+      end;
+  if aObj.HasExtensions then
+    WriteExtensions(aObj.Extensions);
+end;
+
+// License
+
+procedure TOpenAPIWriter.WriteLicense(const aKey : string; aObj: TLicense);
+
+begin
+  StartObjectProp(aKey);
+  WriteLicense(aObj);
+  EndObjectProp;
+end;
+
+procedure TOpenAPIWriter.WriteLicense(aObj: TLicense);
+var
+  lName : String;
+  lKeyword : TLicenseKeyword;
+begin
+  for lKeyword in TLicenseKeyword do
+    if aObj.HasKeyWord(lKeyword) then
+    begin
+    lName:=lKeyword.ToString;
+    case lKeyword of
+    lkName:
+      WriteProperty(lName,aObj.Name);
+    lkIdentifier:
+      WriteProperty(lName,aObj.Identifier);
+    lkUrl:
+      WriteProperty(lName,aObj.Url);
+    end;
+    end;
+  if aObj.HasExtensions then
+    WriteExtensions(aObj.Extensions);
+end;
+
+// Server
+
+procedure TOpenAPIWriter.WriteServer(aObj: TServer);
+
+var
+  lName : String;
+  lKeyword : TServerKeyword;
+begin
+  For lKeyword in TServerKeyword do
+    if aObj.HasKeyWord(lKeyword) then
+      begin
+      lName:=lKeyword.ToString;
+      case lKeyword of
+      skServerUrl:
+        WriteProperty(lName,aObj.Url);
+      skDescription:
+        WriteProperty(lName,aObj.Description);
+      skVariables:
+        WriteServerVariableMap(skVariables.ToString, aObj.Variables);
+      end;
+      end;
+  if aObj.HasExtensions then
+    WriteExtensions(aObj.Extensions);
+end;
+
+procedure TOpenAPIWriter.WriteServer(const aKey: string; aObj: TServer);
+begin
+  StartObjectProp(aKey);
+  WriteServer(aObj);
+  EndObjectProp;
+end;
+
+procedure TOpenAPIWriter.WriteServerList(const aKey: string; aObj: TServerList);
+
+var
+  I : Integer;
+
+begin
+  StartArrayProp(aKey);
+  For I:=0 to aObj.Count-1 do
+    begin
+    Writer.NextElement;
+    Writer.StartObject;
+    WriteServer(aObj.Servers[i]);
+    Writer.EndObject;
+    end;
+  EndArrayProp;
+end;
+
+// Server variable
+
+procedure TOpenAPIWriter.WriteServerVariable(aObj: TServerVariable);
+
+var
+  lName : String;
+  lKeyword : TServerVariableKeyword;
+
+begin
+  for lKeyword in TServerVariableKeyword do
+    if aObj.HasKeyword(lKeyword) then
+      begin
+      lName:=lKeyWord.ToString;
+      case lKeyword of
+      svkEnum:
+        WriteStrings(lName,aObj.Enum);
+      svkDefault:
+        WriteProperty(lName,aObj.Default);
+      svkDescription:
+        WriteProperty(lName,aObj.Description);
+      end;
+      end;
+  if aObj.HasExtensions then
+    WriteExtensions(aObj.Extensions);
+end;
+
+procedure TOpenAPIWriter.WriteServerVariableUntyped(aObj: TBaseOpenAPIObject);
+begin
+  WriteServerVariable(aObj as TServerVariable);
+end;
+
+procedure TOpenAPIWriter.WriteServerVariableMap(const aKey : string; aObj: TServerVariableMap);
+
+begin
+  StartObjectProp(aKey);
+  WriteMapObject(aObj,@WriteServerVariableUntyped);
+  EndObjectProp;
+end;
+
+// Components
+
+procedure TOpenAPIWriter.WriteComponents(aObj: TComponents);
+
+var
+  lName : String;
+  lKeyword : TComponentsKeyword;
+begin
+  for lKeyword in TComponentsKeyword do
+    if aObj.HasKeyWord(lKeyword) then
+      begin
+      lName:=lKeyword.ToString;
+      case lKeyword of
+      ckSchemas:
+        WriteJSONSchemaMap(lName,aObj.Schemas);
+      ckResponses:
+        WriteResponseOrReferenceMap(lName,aObj.Responses);
+      ckParameters:
+        WriteParameterOrReferenceMap(lName,aObj.Parameters);
+      ckExamples:
+        WriteExampleOrReferenceMap(lName,aObj.Examples);
+      ckRequestBodies:
+        WriteRequestBodyOrReferenceMap(lName,aObj.RequestBodies);
+      ckHeaders:
+        WriteHeaderOrReferenceMap(lName,aObj.Headers);
+      ckSecuritySchemes:
+        WriteSecuritySchemeOrReferenceMap(lName,aObj.SecuritySchemes);
+      ckLinks:
+        WriteLinkOrReferenceMap(lName,aObj.Links);
+      ckCallbacks:
+        WriteLinkOrReferenceMap(lName,aObj.Callbacks);
+      ckPathItems:
+        WritePathItemOrReferenceMap(lName,aObj.PathItems);
+      end;
+      end;
+  if aObj.HasExtensions then
+    WriteExtensions(aObj.Extensions);
+end;
+
+procedure TOpenAPIWriter.WriteComponents(const aKey: String; aObj: TComponents);
+begin
+  StartObjectProp(aKey);
+  WriteComponents(aObj);
+  EndObjectProp;
+end;
+
+procedure TOpenAPIWriter.WriteJSONSchemaMap(const aKey : String; aObj: TJSONSchemaMap);
+var
+  lName : String;
+  lSchema : TJSONSchema;
+  I : Integer;
+
+begin
+  StartObjectProp(aKey);
+  For I:=0 to aObj.Count-1 do
+    begin
+    lName:=aObj.Names[i];
+    lSchema:=aObj.NamedObjects[i].Object_ as TJSONSchema;
+    WriteProperty(lName,lSchema);
+    end;
+  EndObjectProp();
+end;
+
+// Paths
+
+procedure TOpenAPIWriter.WritePathsList(const aKey: string; aObj: TPathsList);
+
+begin
+  WriteMapObject(aKey,aObj,@WritePathItemUnTyped);
+end;
+
+procedure TOpenAPIWriter.WritePathItemUntyped(aObj: TBaseOpenAPIObject);
+
+begin
+  WritePathItem(aObj as TPathItem);
+end;
+
+procedure TOpenAPIWriter.WritePathItem(aObj: TPathItem);
+
+var
+  lName : String;
+  lKeyword : TPathItemKeyword;
+
+begin
+  for lKeyword in TPathItemKeyword do
+    if aObj.HasKeyword(lKeyword) then
+      begin
+      lName:=lKeyword.AsString;
+      case lKeyword of
+      pkRef:
+        WriteProperty(lName,aObj.Ref);
+      pkSummary:
+        WriteProperty(lName,aObj.Summary);
+      pkDescription:
+        WriteProperty(lName,aObj.Description);
+      pkGet:
+        WriteApiOperation(lName,aObj.Get);
+      pkPut:
+        WriteApiOperation(lName,aObj.Put);
+      pkPost:
+        WriteApiOperation(lName,aObj.Post);
+      pkDelete:
+        WriteApiOperation(lName,aObj.Delete);
+      pkOptions:
+        WriteApiOperation(lName,aObj.Options);
+      pkHead:
+        WriteApiOperation(lName,aObj.Head);
+      pkPatch:
+        WriteApiOperation(lName,aObj.Patch);
+      pkTrace:
+        WriteApiOperation(lName,aObj.Trace);
+      pkServers:
+        WriteServerList(lName,aObj.Servers);
+      pkParameters:
+        WriteParameterOrReferenceList(lName,aObj.Parameters);
+      end;
+      end;
+  if aObj.HasExtensions then
+    WriteExtensions(aObj.Extensions);
+end;
+
+
+procedure TOpenAPIWriter.WritePathItemOrReference(aObj: TPathItemOrReference);
+
+begin
+  if aObj.HasReference then
+    WriteReference(aObj.Reference)
+  else
+    WritePathItem(aObj);
+end;
+
+procedure TOpenAPIWriter.WritePathItemOrReferenceUnTyped(aObj: TBaseOpenAPIObject);
+
+begin
+  WritePathItemOrReference(aObj as TPathItemOrReference);
+end;
+
+procedure TOpenAPIWriter.WritePathItemOrReferenceMap(const aKey: string; aObj: TPathItemOrReferenceMap);
+
+begin
+  WriteMapObject(aKey,aObj,@WritePathItemOrReferenceUnTyped);
+end;
+
+// Operations
+
+procedure TOpenAPIWriter.WriteApiOperation(aKey: string; aObj: TApiOperation);
+
+begin
+  StartObjectProp(aKey);
+  WriteAPIoperation(aObj);
+  EndObjectProp;
+end;
+
+procedure TOpenAPIWriter.WriteApiOperation(aObj: TApiOperation);
+
+var
+  lName : String;
+  lKeyword : TApiOperationKeyword;
+
+begin
+  for lKeyword in TApiOperationKeyword do
+    if aObj.HasKeyWord(lKeyword) then
+      begin
+      lName:=lKeyWord.AsString;
+      case lKeyword of
+      okTags:
+        WriteStrings(lName,aObj.Tags);
+      okSummary:
+        WriteProperty(lName,aObj.Summary);
+      okDescription:
+        WriteProperty(lName,aObj.Description);
+      okExternalDocs:
+        WriteExternalDocumentation(lName,aObj.ExternalDocs);
+      okOperationId:
+        WriteProperty(lName,aObj.OperationId);
+      okParameters:
+        WriteParameterOrReferenceList(lName,aObj.Parameters);
+      okRequestBody:
+        WriteRequestBody(lName,aObj.RequestBody);
+      okResponses:
+        WriteResponses(lName,aObj.Responses);
+      okCallbacks:
+        WriteCallBackOrReferenceMap(lName,aObj.Callbacks);
+      okDeprecated:
+        WriteProperty(lName,aObj.Deprecated);
+      okSecurity:
+        WriteSecurityRequirementList(lName,aObj.Security);
+      okServers:
+        WriteServerList(lName,aObj.Servers);
+      end;
+      end;
+  if aObj.HasExtensions then
+    WriteExtensions(aObj.Extensions);
+end;
+
+// External docs
+
+procedure TOpenAPIWriter.WriteExternalDocumentation(const aKey: String; aObj: TExternalDocumentation);
+
+begin
+  StartObjectProp(aKey);
+  WriteExternalDocumentation(aObj);
+  EndObjectProp;
+end;
+
+procedure TOpenAPIWriter.WriteExternalDocumentation(aObj: TExternalDocumentation);
+
+var
+  lName : String;
+  lKeyword : TExternalDocumentationKeyword;
+
+begin
+  for lKeyword in TExternalDocumentationKeyword do
+    if aObj.HasKeyWord(lKeyword) then
+      begin
+      lName:=lKeyWord.AsString;
+      case lKeyword of
+      edkDescription:
+        WriteProperty(lName,aObj.Description);
+      edkUrl:
+        WriteProperty(lName,aObj.Url);
+      end;
+      end;
+  if aObj.HasExtensions then
+    WriteExtensions(aObj.Extensions);
+end;
+
+// Parameters
+
+procedure TOpenAPIWriter.WriteParameter(aObj: TParameter);
+
+begin
+  WriteParameterOrHeader(aObj);
+end;
+
+procedure TOpenAPIWriter.WriteParameterOrHeader(aObj: TParameterOrHeader);
+
+var
+  lName : string;
+  lKeyword : TParameterKeyword;
+
+begin
+  for lKeyword in TParameterKeyword do
+    if aObj.HasKeyWord(LKeyword) then
+      begin
+      lName:=lKeyword.AsString;
+      Case lKeyword of
+      pakName:
+        WriteProperty(lName,TParameter(aObj).Name);
+      pakIn:
+        WriteProperty(lName,TParameter(aObj).In_);
+      pakDescription:
+        WriteProperty(lName,aObj.Description);
+      pakRequired:
+        WriteProperty(lName,aObj.Required);
+      pakDeprecated:
+        WriteProperty(lName,aObj.Deprecated);
+      pakAllowEmptyValue:
+        WriteProperty(lName,aObj.AllowEmptyValue);
+      pakStyle:
+        WriteProperty(lName,aObj.Style);
+      pakExplode:
+        WriteProperty(lName,aObj.Explode);
+      pakAllowReserved:
+        WriteProperty(lName,aObj.AllowReserved);
+      pakSchema:
+        WriteProperty(lName,aObj.Schema);
+      pakExample:
+        WriteProperty(lName,aObj.Example);
+      pakExamples:
+        WriteExampleOrReferenceMap(lName,aObj.Examples);
+      pakContent:
+        WriteMediaTypeMap(lName,aObj.Content);
+      end;
+      end;
+  if aObj.HasExtensions then
+     WriteExtensions(aObj.Extensions);
+end;
+
+
+procedure TOpenAPIWriter.WriteParameterOrReference(aObj: TParameterOrReference);
+
+begin
+  if aObj.HasReference then
+    WriteReference(aObj.Reference)
+  else
+    WriteParameter(aObj)
+end;
+
+
+procedure TOpenAPIWriter.WriteParameterOrReferenceList(const aKey: string; aObj: TParameterOrReferenceList);
+
+begin
+  WriteObjectArray(aKey,aObj,@WriteParameterOrReferenceUntyped);
+end;
+
+procedure TOpenAPIWriter.WriteParameterOrReferenceUntyped(aObj: TBaseOpenAPIObject);
+
+begin
+  WriteParameterOrReference(aObj as TParameterOrReference);
+end;
+
+procedure TOpenAPIWriter.WriteParameterOrReferenceMap(const aKey: String; aObj: TParameterOrReferenceMap);
+
+begin
+  WriteMapObject(aKey,aObj,@WriteParameterOrReferenceUnTyped);
+end;
+
+
+procedure TOpenAPIWriter.WriteParameterStyle(aObj: TParameterStyle);
+
+var
+  lName : String;
+  lKeyword : TParameterStyleKeyword;
+
+begin
+  for lKeyword in TParameterStyleKeyword do
+    if aObj.HasKeyWord(lKeyword) then
+      begin
+      lName:=lKeyWord.AsString;
+      case lKeyword of
+      pskMatrix:
+        WriteProperty(lName,aObj.Matrix);
+      pskLabel:
+        WriteProperty(lName,aObj.Label_);
+      pskForm:
+        WriteProperty(lName,aObj.Form);
+      pskSimple:
+        WriteProperty(lName,aObj.Simple);
+      pskSpaceDelimited:
+        WriteProperty(lName,aObj.SpaceDelimited);
+      pskPipeDelimited:
+        WriteProperty(lName,aObj.PipeDelimited);
+      pskDeepObject:
+        WriteProperty(lName,aObj.DeepObject);
+      end;
+      end;
+  if aObj.HasExtensions then
+    WriteExtensions(aObj.Extensions);
+end;
+
+// Request body
+
+procedure TOpenAPIWriter.WriteRequestBody(const aKey: string; aObj: TRequestBody);
+
+begin
+  StartObjectProp(aKey);
+  WriteRequestBody(aObj);
+  EndObjectProp;
+end;
+
+procedure TOpenAPIWriter.WriteRequestBody(aObj: TRequestBody);
+
+var
+  lName : String;
+  lKeyword : TRequestBodyKeyword;
+
+begin
+  for lKeyword in TRequestBodyKeyword do
+    if aObj.HasKeyWord(lKeyword) then
+      begin
+      lName:=lKeyWord.AsString;
+      case lKeyword of
+      rbkDescription:
+        WriteProperty(lName,aObj.Description);
+      rbkContent:
+        WriteMediaTypeMap(lName,aObj.Content);
+      rbkRequired:
+        WriteProperty(lName,aObj.Required);
+      end;
+      end;
+  if aObj.HasExtensions then
+    WriteExtensions(aObj.Extensions);
+end;
+
+
+procedure TOpenAPIWriter.WriteRequestBodyOrReference(aObj: TRequestBodyOrReference);
+
+begin
+  if aObj.HasReference then
+    WriteReference(aObj.Reference)
+  else
+    WriteRequestBody(aObj);
+end;
+
+procedure TOpenAPIWriter.WriteRequestBodyOrReferenceUnTyped(aObj: TBaseOpenAPIObject);
+
+begin
+  WriteRequestBodyOrReference(aObj as TRequestBodyOrReference);
+end;
+
+procedure TOpenAPIWriter.WriteRequestBodyOrReferenceMap(const aKey: string; aObj: TRequestBodyOrReferenceMap);
+
+begin
+  WriteMapObject(aKey,aObj,@WriteRequestBodyOrReferenceUnTyped);
+end;
+
+// Media type
+
+procedure TOpenAPIWriter.WriteMediaType(aObj: TMediaType);
+
+var
+  lName : String;
+  lKeyword : TMediaTypeKeyword;
+
+begin
+  for lKeyword in TMediaTypeKeyword do
+    if aObj.HasKeyWord(lKeyword) then
+      begin
+      lName:=lKeyWord.AsString;
+      case lKeyword of
+      mtkSchema:
+        WriteProperty(lName,aObj.Schema);
+      mtkExample:
+        WriteProperty(lName,aObj.Example);
+      mtkExamples:
+        WriteExampleOrReferenceMap(lName,aObj.Examples);
+      mtkEncoding:
+        WriteEncodingMap(lName,aObj.Encoding);
+      end;
+      end;
+  if aObj.HasExtensions then
+    WriteExtensions(aObj.Extensions);
+end;
+
+procedure TOpenAPIWriter.WriteMediaTypeUnTyped(aObj: TBaseOpenAPIObject);
+begin
+  WriteMediaType(aObj as TMediaType);
+end;
+
+procedure TOpenAPIWriter.WriteMediaTypeMap(const aKey : String; aObj: TMediaTypeMap);
+
+begin
+  WriteMapObject(aKey,aObj,@WriteMediaTypeUntyped);
+end;
+
+// Encoding
+
+procedure TOpenAPIWriter.WriteEncoding(aObj: TEncoding);
+
+var
+  lName : String;
+  lKeyword : TEncodingKeyword;
+begin
+  for lKeyword in TEncodingKeyword do
+    if aObj.HasKeyWord(lKeyword) then
+      begin
+      lName:=lKeyWord.AsString;
+      case lKeyword of
+      eckContentType:
+        WriteProperty(lName,aObj.ContentType);
+      eckHeaders:
+        WriteHeaderOrReferenceMap(lName,aObj.Headers);
+      eckStyle:
+        WriteProperty(lName,aObj.Style);
+      eckExplode:
+        WriteProperty(lName,aObj.Explode);
+      eckAllowReserved:
+        WriteProperty(lName,aObj.AllowReserved);
+      end;
+      end;
+  if aObj.HasExtensions then
+    WriteExtensions(aObj.Extensions);
+end;
+
+procedure TOpenAPIWriter.WriteEncodingUntyped(aObj: TBaseOpenAPIObject);
+begin
+  WriteEncoding(aObj as TEncoding);
+end;
+
+procedure TOpenAPIWriter.WriteEncodingMap(const aKey : string; aObj: TEncodingMap);
+
+begin
+  WriteMapObject(aKey,aObj,@WriteEncodingUntyped);
+end;
+
+// Responses
+
+procedure TOpenAPIWriter.WriteResponses(const aKey: String; aObj: TResponses);
+
+begin
+  WriteMapObject(aKey, aObj, @WriteResponseUntyped)
+end;
+
+procedure TOpenAPIWriter.WriteResponseUntyped(aObj: TBaseOpenAPIObject);
+
+begin
+  WriteResponse(aObj as TResponse);
+end;
+
+procedure TOpenAPIWriter.WriteResponse(aObj: TResponse);
+
+var
+  lName : String;
+  lKeyword : TResponseKeyword;
+begin
+  for lKeyword in TResponseKeyword do
+    if aObj.HasKeyWord(lKeyword) then
+      begin
+      lName:=lKeyWord.AsString;
+      case lKeyword of
+      rkDescription:
+        WriteProperty(lName,aObj.Description);
+      rkHeaders:
+        WriteHeaderOrReferenceMap(lName,aObj.Headers);
+      rkContent:
+        WriteMediaTypeMap(lName,aObj.Content);
+      rkLinks:
+        WriteLinkOrReferenceMap(lName,aObj.Links);
+      end;
+      end;
+  if aObj.HasExtensions then
+    WriteExtensions(aObj.Extensions);
+end;
+
+
+procedure TOpenAPIWriter.WriteResponseOrReference(aObj: TResponseOrReference);
+
+begin
+  if aObj.HasReference then
+    WriteReference(aObj.Reference)
+  else
+    WriteResponse(aObj);
+end;
+
+procedure TOpenAPIWriter.WriteResponseOrReferenceUnTyped(aObj: TBaseOpenAPIObject);
+begin
+  WriteResponseOrReference(aObj as TResponseOrReference);
+end;
+
+procedure TOpenAPIWriter.WriteResponseOrReferenceMap(const aKey: String; aObj: TResponseOrReferenceMap);
+
+begin
+  WriteMapObject(aKey,aObj,@WriteResponseOrReferenceUnTyped);
+end;
+
+// Example
+
+procedure TOpenAPIWriter.WriteExample(aObj: TExample);
+
+var
+  lName : String;
+  lKeyword : TExampleKeyword;
+begin
+  for lKeyword in TExampleKeyword do
+    if aObj.HasKeyWord(lKeyword) then
+      begin
+      lName:=lKeyWord.AsString;
+      case lKeyword of
+      exkSummary:
+        WriteProperty(lName,aObj.Summary);
+      exkDescription:
+        WriteProperty(lName,aObj.Description);
+      exkValue:
+        WriteProperty(lName,aObj.Value);
+      exkExternalValue:
+        WriteProperty(lName,aObj.ExternalValue);
+      end;
+      end;
+  if aObj.HasExtensions then
+    WriteExtensions(aObj.Extensions);
+end;
+
+
+procedure TOpenAPIWriter.WriteExampleOrReference(aObj: TExampleOrReference);
+
+begin
+  if aObj.HasReference then
+    WriteReference(aObj.Reference)
+  else
+    WriteExample(aObj);
+end;
+
+procedure TOpenAPIWriter.WriteExampleOrReferenceUnTyped(aObj: TBaseOpenAPIObject);
+
+begin
+  WriteExampleOrReference(aObj as TExampleOrReference);
+end;
+
+procedure TOpenAPIWriter.WriteExampleOrReferenceMap(const aKey: String; aObj: TExampleOrReferenceMap);
+
+begin
+  WriteMapObject(aKey,aObj,@WriteExampleOrReferenceUnTyped);
+end;
+
+// Link
+
+procedure TOpenAPIWriter.WriteLink(aObj: TLink);
+
+var
+  lName : String;
+  lKeyword : TLinkKeyword;
+begin
+  for lKeyword in TLinkKeyword do
+    if aObj.HasKeyWord(lKeyword) then
+      begin
+      lName:=lKeyWord.AsString;
+      case lKeyword of
+      likOperationRef:
+        WriteProperty(lName,aObj.OperationRef);
+      likOperationId:
+        WriteProperty(lName,aObj.OperationId);
+      likParameters:
+        WriteProperty(lName,aObj.Parameters);
+      likRequestBody:
+        WriteProperty(lName,aObj.RequestBody);
+      likDescription:
+        WriteProperty(lName,aObj.Description);
+      likServer:
+        WriteServer(lName,aObj.Server);
+      end;
+      end;
+  if aObj.HasExtensions then
+    WriteExtensions(aObj.Extensions);
+end;
+
+
+procedure TOpenAPIWriter.WriteLinkOrReference(aObj: TLinkOrReference);
+
+begin
+  if aObj.HasReference then
+    WriteReference(aObj.Reference)
+  else
+    WriteLink(aObj);
+end;
+
+procedure TOpenAPIWriter.WriteLinkOrReferenceUntyped(aObj: TBaseOpenAPIObject);
+
+begin
+  WriteLinkOrReference(aObj as TLinkOrReference)
+end;
+
+procedure TOpenAPIWriter.WriteLinkOrReferenceMap(const aKey: string; aObj: TLinkOrReferenceMap);
+
+begin
+  WriteMapObject(aKey,aObj,@WriteLinkOrReferenceUntyped);
+end;
+
+// Reference
+
+procedure TOpenAPIWriter.WriteReference(aObj: TReference);
+
+var
+  lName : String;
+  lKeyword : TReferenceKeyword;
+begin
+  for lKeyword in TReferenceKeyword do
+    if aObj.HasKeyWord(lKeyword) then
+      begin
+      lName:=lKeyWord.AsString;
+      case lKeyword of
+      rfkRef:
+        WriteProperty(lName,aObj.Ref);
+      rfkSummary:
+        WriteProperty(lName,aObj.Summary);
+      rfkDescription:
+        WriteProperty(lName,aObj.Description);
+      end;
+      end;
+  if aObj.HasExtensions then
+    WriteExtensions(aObj.Extensions);
+end;
+
+// Schema
+
+procedure TOpenAPIWriter.WriteSchema(aObj: TSchema);
+
+var
+  lName : String;
+  lKeyword : TSchemaKeyword;
+
+begin
+  for lKeyword in TSchemaKeyword do
+    if aObj.HasKeyWord(lKeyword) then
+      begin
+      lName:=lKeyWord.AsString;
+      case lKeyword of
+      sckDiscriminator:
+        WriteDiscriminator(lName,aObj.Discriminator);
+      sckXML:
+        WriteXML(aObj.XML);
+      sckExternalDocs:
+        WriteExternalDocumentation(lName,aObj.ExternalDocs);
+      sckExample:
+        WriteProperty(lName,aObj.Example);
+      end;
+      end;
+  if aObj.HasExtensions then
+    WriteExtensions(aObj.Extensions);
+end;
+
+// Discriminator
+
+procedure TOpenAPIWriter.WriteDiscriminator(const aKey : string; aObj: TDiscriminator);
+
+begin
+  StartObjectProp(aKey);
+  WriteDiscriminator(aObj);
+  EndObjectProp;
+end;
+
+procedure TOpenAPIWriter.WriteDiscriminator(aObj: TDiscriminator);
+var
+  lName : String;
+  lKeyword : TDiscriminatorKeyword;
+begin
+  for lKeyword in TDiscriminatorKeyword do
+    if aObj.HasKeyWord(lKeyword) then
+      begin
+      lName:=lKeyWord.AsString;
+      case lKeyword of
+      dikPropertyName:
+        WriteProperty(lName,aObj.PropertyName);
+      dikMapping:
+        WriteStrings(lName,aObj.Mapping);
+      end;
+      end;
+  if aObj.HasExtensions then
+    WriteExtensions(aObj.Extensions);
+end;
+
+// XML
+
+procedure TOpenAPIWriter.WriteXML(aObj: TXML);
+
+var
+  lName : String;
+  lKeyword : TXMLKeyword;
+begin
+  for lKeyword in TXMLKeyword do
+    if aObj.HasKeyWord(lKeyword) then
+      begin
+      lName:=lKeyWord.AsString;
+      case lKeyword of
+      xmkName:
+        WriteProperty(lName,aObj.Name);
+      xmkNamespace:
+        WriteProperty(lName,aObj.Namespace);
+      xmkPrefix:
+        WriteProperty(lName,aObj.Prefix);
+      xmkAttribute:
+        WriteProperty(lName,aObj.Attribute);
+      xmkWrapped:
+        WriteProperty(lName,aObj.Wrapped);
+      end;
+      end;
+  if aObj.HasExtensions then
+    WriteExtensions(aObj.Extensions);
+end;
+
+// Security scheme
+
+procedure TOpenAPIWriter.WriteSecurityScheme(aObj: TSecurityScheme);
+
+var
+  lName : String;
+  lKeyword : TSecuritySchemeKeyword;
+begin
+  for lKeyword in TSecuritySchemeKeyword do
+    if aObj.HasKeyWord(lKeyword) then
+      begin
+      lName:=lKeyWord.AsString;
+      case lKeyword of
+      sskType:
+        WriteProperty(lName,aObj.Type_);
+      sskDescription:
+        WriteProperty(lName,aObj.Description);
+      sskName:
+        WriteProperty(lName,aObj.Name);
+      sskIn:
+        WriteProperty(lName,aObj.In_);
+      sskScheme:
+        WriteProperty(lName,aObj.Scheme);
+      sskBearerFormat:
+        WriteProperty(lName,aObj.BearerFormat);
+      sskFlows:
+        WriteOAuthFlows(aObj.Flows);
+      sskOpenIdConnectUrl:
+        WriteProperty(lName,aObj.OpenIdConnectUrl);
+      end;
+      end;
+  if aObj.HasExtensions then
+    WriteExtensions(aObj.Extensions);
+end;
+
+
+procedure TOpenAPIWriter.WriteSecuritySchemeOrReference(aObj: TSecuritySchemeOrReference);
+
+begin
+  if aObj.HasReference then
+    WriteReference(aObj.Reference)
+  else
+    WriteSecurityScheme(aObj);
+end;
+
+procedure TOpenAPIWriter.WriteSecuritySchemeOrReferenceUnTyped(aObj: TBaseOpenAPIObject);
+
+begin
+  WriteSecuritySchemeOrReference(aObj as TSecuritySchemeOrReference);
+end;
+
+procedure TOpenAPIWriter.WriteSecuritySchemeOrReferenceMap(const aKey: string; aObj: TSecuritySchemeOrReferenceMap);
+
+begin
+  WriteMapObject(aKey,aObj,@WriteSecuritySchemeOrReferenceUntyped);
+end;
+
+// OAuth flows
+
+procedure TOpenAPIWriter.WriteOAuthFlows(aObj: TOAuthFlows);
+
+var
+  lName : String;
+  lKeyword : TOAuthFlowsKeyword;
+begin
+  for lKeyword in TOAuthFlowsKeyword do
+    if aObj.HasKeyWord(lKeyword) then
+      begin
+      lName:=lKeyWord.AsString;
+    case lKeyword of
+    ofskImplicit:
+      WriteOauthFlow(lName,aObj.Implicit);
+    ofskPassword: 
+      WriteOauthFlow(lName,aObj.Password);
+    ofskClientCredentials: 
+      WriteOauthFlow(lName,aObj.ClientCredentials);
+    ofskClientAuthorizationCode: 
+      WriteOauthFlow(lName,aObj.ClientAuthorizationCode);
+    end;
+    end;
+  if aObj.HasExtensions then
+    WriteExtensions(aObj.Extensions);
+end;
+
+// OAuth flow
+
+procedure TOpenAPIWriter.WriteOAuthFlow(aObj: TOauthFlow);
+var
+  lName : String;
+  lKeyword : TOauthFlowKeyword;
+begin
+  for lKeyword in TOauthFlowKeyword do
+    if aObj.HasKeyWord(lKeyword) then
+      begin
+      lName:=lKeyWord.AsString;
+    case lKeyword of
+    ofkAuthorizationUrl:
+      WriteProperty(lName,aObj.AuthorizationUrl);
+    ofkTokenURL: 
+      WriteProperty(lName,aObj.TokenURL);
+    ofkRefreshURL: 
+      WriteProperty(lName,aObj.RefreshURL);
+    ofkScopes: 
+      WriteStrings(lName,aObj.Scopes);
+    end;
+    end;
+  if aObj.HasExtensions then
+    WriteExtensions(aObj.Extensions);
+end;
+
+procedure TOpenAPIWriter.WriteOAuthFlow(const aKey: String; aObj: TOauthFlow);
+begin
+  StartObjectProp(aKey);
+  WriteOauthFlow(aObj);
+  EndObjectProp;
+end;
+
+// Header
+
+procedure TOpenAPIWriter.WriteHeader(aObj: THeader);
+
+begin
+  WriteParameterOrHeader(aObj);
+end;
+
+
+procedure TOpenAPIWriter.WriteHeaderOrReference(aObj: THeaderOrReference);
+
+begin
+  if aObj.HasReference then
+    WriteReference(aObj.Reference)
+  else
+    WriteHeader(aObj)
+end;
+
+
+procedure TOpenAPIWriter.WriteHeaderOrReferenceUnTyped(aObj: TBaseOpenAPIObject);
+
+begin
+  WriteHeaderOrReference(aObj as THeaderOrReference)
+end;
+
+procedure TOpenAPIWriter.WriteHeaderOrReferenceMap(const aKey: string; aObj: THeaderOrReferenceMap);
+
+begin
+  WriteMapObject(aKey,aObj,@WriteHeaderOrReferenceUnTyped);
+end;
+
+// Callback
+
+procedure TOpenAPIWriter.WriteCallBack(aObj: TCallBack);
+
+begin
+  WriteMapObject(aObj,@WritePathItemOrReferenceUnTyped);
+end;
+
+procedure TOpenAPIWriter.WriteCallbackOrReference(aObj: TCallbackOrReference);
+
+begin
+  if aObj.HasReference then
+    WriteReference(aObj.Reference)
+  else
+    WriteCallBack(aObj);
+end;
+
+procedure TOpenAPIWriter.WriteCallbackOrReferenceUnTyped(aObj: TBaseOpenAPIObject);
+begin
+  WriteCallbackOrReference(aObj as TCallbackOrReference);
+end;
+
+procedure TOpenAPIWriter.WriteCallbackOrReferenceMap(const aKey: string; aObj: TCallbackOrReferenceMap);
+
+begin
+  WriteMapObject(aKey,aObj,@WriteCallbackOrReferenceUnTyped);
+end;
+
+// Security requirement
+
+procedure TOpenAPIWriter.WriteSecurityRequirement(aObj: TSecurityRequirement);
+
+var
+  i: Integer;
+  lName : String;
+
+begin
+  for I:=0 to aObj.Count-1 do
+    begin
+    lName:=aObj.Names[i];
+    WriteStrings(lName,aObj.Lists[i]);
+    end;
+end;
+
+procedure TOpenAPIWriter.WriteSecurityRequirement(const aKey: String; aObj: TSecurityRequirement);
+
+begin
+  StartObjectProp(aKey);
+  WriteSecurityRequirement(aObj);
+  EndObjectProp;
+end;
+
+procedure TOpenAPIWriter.WriteSecurityRequirementUnTyped(aObj: TBaseOpenAPIObject);
+
+begin
+  WriteSecurityRequirement(aObj as TSecurityRequirement);
+end;
+
+procedure TOpenAPIWriter.WriteSecurityRequirementList(const aKey: String; aObj: TSecurityRequirementList);
+
+begin
+  WriteObjectArray(aKey,aObj,@WriteSecurityRequirementUntyped);
+end;
+
+// Tag
+
+procedure TOpenAPIWriter.WriteTag(aObj: TTag);
+
+var
+  lName : String;
+  lKeyword : TTagKeyword;
+
+begin
+  for lKeyword in TTagKeyword do
+    if aObj.HasKeyWord(lKeyword) then
+      begin
+      lName:=lKeyWord.AsString;
+      case lKeyword of
+      tkName:
+        WriteProperty(lName,aObj.Name);
+      tkDescription:
+        WriteProperty(lName,aObj.Description);
+      tkExternalDocs:
+        WriteExternalDocumentation(lName,aObj.ExternalDocs);
+      end;
+      end;
+  if aObj.HasExtensions then
+    WriteExtensions(aObj.Extensions);
+end;
+
+procedure TOpenAPIWriter.WriteTagUnTyped(aObj: TBaseOpenAPIObject);
+
+begin
+  WriteTag(aObj as TTag);
+end;
+
+procedure TOpenAPIWriter.WriteTagList(const aKey : string; aObj: TTagList);
+begin
+  WriteObjectArray(aKey,aObj,@WriteTagUnTyped);
+end;
+
+end.

+ 111 - 0
packages/fcl-openapi/tests/testopenapi.lpi

@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="12"/>
+    <General>
+      <Flags>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+        <MainUnitHasScaledStatement Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <Title Value="OpenAPI testsuite"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <BuildModes>
+      <Item Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+      <UseFileFilters Value="True"/>
+    </PublishOptions>
+    <RunParams>
+      <FormatVersion Value="2"/>
+    </RunParams>
+    <RequiredPackages>
+      <Item>
+        <PackageName Value="FCL"/>
+      </Item>
+    </RequiredPackages>
+    <Units>
+      <Unit>
+        <Filename Value="testopenapi.pp"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+      <Unit>
+        <Filename Value="utOpenApi.pp"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+      <Unit>
+        <Filename Value="../src/fpopenapi.consts.pp"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+      <Unit>
+        <Filename Value="../src/fpopenapi.types.pp"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+      <Unit>
+        <Filename Value="../src/fpopenapi.objects.pp"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+      <Unit>
+        <Filename Value="utOpenApiReader.pp"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+      <Unit>
+        <Filename Value="../src/fpopenapi.reader.pp"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+      <Unit>
+        <Filename Value="utOpenAPIWriter.pp"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+      <Unit>
+        <Filename Value="../src/fpopenapi.data.ppcal.pp"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+      <Unit>
+        <Filename Value="../src/fpopenapi.ppcaltypes.pp"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+      <Unit>
+        <Filename Value="../src/fpopenapi.writer.pp"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+      <Unit>
+        <Filename Value="jsoncomparer.pp"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <Target>
+      <Filename Value="testopenapi"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <OtherUnitFiles Value="../src;../../JSONSchema/fpc/src"/>
+      <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
+    </SearchPaths>
+    <Linking>
+      <Debugging>
+        <UseHeaptrc Value="True"/>
+      </Debugging>
+    </Linking>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions>
+      <Item>
+        <Name Value="EAbort"/>
+      </Item>
+      <Item>
+        <Name Value="ECodetoolError"/>
+      </Item>
+      <Item>
+        <Name Value="EFOpenError"/>
+      </Item>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 29 - 0
packages/fcl-openapi/tests/testopenapi.pp

@@ -0,0 +1,29 @@
+program testopenapi;
+
+{$mode objfpc}{$H+}
+
+uses
+  Classes, consoletestrunner, utOpenApi, fpopenapi.consts, fpopenapi.types, fpopenapi.objects, utOpenApiReader, utOpenAPIWriter,
+  fpopenapi.reader, jsoncomparer, jsonparser;
+
+type
+
+  { TMyTestRunner }
+
+  TMyTestRunner = class(TTestRunner)
+  protected
+  // override the protected methods of TTestRunner to customize its behavior
+  end;
+
+var
+  Application: TMyTestRunner;
+
+begin
+  DefaultRunAllTests:=True;
+  DefaultFormat:=fPlain;
+  Application := TMyTestRunner.Create(nil);
+  Application.Initialize;
+  Application.Title := 'FPCUnit Console test runner';
+  Application.Run;
+  Application.Free;
+end.

+ 1095 - 0
packages/fcl-openapi/tests/utOpenAPIWriter.pp

@@ -0,0 +1,1095 @@
+unit utOpenAPIWriter;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, fpcunit, testregistry, fpjson, fpjson.schema.schema, fpopenapi.objects, fpopenapi.writer;
+
+type
+
+  { TTestOpenApiWriterBase }
+
+  TTestOpenApiWriterBase = class(TTestCase)
+  private
+    FDocument: TJSONObject;
+    FOpenAPI: TOpenAPI;
+    procedure AddSource(Const aFmt : string; aArgs : Array of const);
+    Procedure AddSource(Const aLine : string);
+    procedure AddDecl(Const aFmt : string; aArgs : Array of const);
+  protected
+    procedure SetUp; override;
+    procedure TearDown; override;
+    Procedure WriteOpenAPI;
+    procedure CheckJSON(const Msg: String; aJSON: TJSONStringType);
+    procedure TestWrite(const Msg: String; aJSON: TJSONStringType);
+  Public
+    Property OpenApi : TOpenAPI Read FOpenAPI;
+    Property Document : TJSONObject Read FDocument;
+  published
+    procedure TestHookUp;
+  end;
+
+  { TTestOpenApiWriter }
+
+  TTestOpenApiWriterOpenAPI = class(TTestOpenApiWriterBase)
+  Published
+    procedure TestEmpty;
+    Procedure TestOpenAPI;
+    Procedure TestJSONSchemaDialect;
+  end;
+
+  TTestOpenApiWriterInfo = class(TTestOpenApiWriterBase)
+  Published
+    procedure TestVersion;
+    procedure TestTitle;
+    procedure TestSummary;
+    procedure TestDescription;
+    procedure TestTermsOfService;
+    procedure TestContactEmail;
+    procedure TestContactName;
+    procedure TestContactURL;
+    procedure TestLicenseUrl;
+    procedure TestLicenseIdentifier;
+    procedure TestLicenseName;
+  end;
+
+  TTestOpenApiWriterTags = class(TTestOpenApiWriterBase)
+  Published
+    Procedure TestName;
+    Procedure TestDescription;
+    Procedure TestExternalDocs;
+    Procedure Test2Tags;
+  end;
+
+  TTestOpenApiWriterExternalDocs = class(TTestOpenApiWriterBase)
+  Published
+    procedure TestUrl;
+    procedure TestDescription;
+  end;
+
+  { TTestOpenApiWriterServers }
+
+  TTestOpenApiWriterServers = class(TTestOpenApiWriterBase)
+  Published
+    Procedure TestUrl;
+    Procedure TestDescription;
+    procedure TestVariablesDefault;
+    procedure TestVariablesDescription;
+    procedure TestVariablesEnum;
+    Procedure Test2Url;
+  end;
+
+  { TTestOpenApiWriterPaths }
+  TTestOpenApiWriterPathBase = class(TTestOpenApiWriterBase)
+  Public
+    Function AddPath(aPath : String) : TPathItem;
+  end;
+
+  TTestOpenApiWriterPaths = class(TTestOpenApiWriterPathBase)
+  Published
+    Procedure TestEmpty;
+    Procedure TestRef;
+    Procedure TestSummary;
+    Procedure TestDescription;
+    Procedure TestGetEmpty;
+    Procedure TestGetSummary;
+    Procedure TestGetDescription;
+    Procedure TestGetOperationId;
+    Procedure TestGetDeprecated;
+    Procedure TestGetExternalDocsEmpty;
+    Procedure TestGetExternalDocsURL;
+    Procedure TestGetServers;
+  end;
+
+  { TTestOpenApiWriterPathRequestBody }
+
+  TTestOpenApiWriterPathRequestBody = class(TTestOpenApiWriterPathBase)
+  Public
+    Function AddBody(aPath : String) : TRequestBody;
+  Published
+    procedure TestEmpty;
+    procedure TestDescription;
+    procedure TestRequired;
+    procedure TestContent;
+    procedure TestContentSchema;
+    procedure TestContentExample;
+    procedure TestContentExamples;
+    procedure TestContentEncodingContentType;
+    procedure TestContentEncodingExplode;
+    procedure TestContentEncodingStyle;
+    procedure TestContentEncodingAllowReserved;
+    procedure TestContentEncodingHeaders;
+  end;
+
+  { TTestOpenApiWriterPathParameters }
+
+  TTestOpenApiWriterPathParameters = class(TTestOpenApiWriterPathBase)
+  Public
+    Function AddParam(aPath : String) : TParameter;
+  Published
+    Procedure TestGetParametersEmpty;
+  end;
+
+  { TTestOpenApiWriterPathResponses }
+
+  TTestOpenApiWriterPathResponses = class(TTestOpenApiWriterPathBase)
+  Public
+    Function AddResponse(aPath : String) : TResponse;
+  Published
+    procedure TestEmpty;
+    procedure TestHeaders;
+    procedure TestDescription;
+    procedure TestContentEmpty;
+    procedure TestContentSchema;
+    procedure TestContentExample;
+    procedure TestContentExamples;
+    procedure TestContentEncodingEmpty;
+    procedure TestContentEncodingContentType;
+  end;
+
+  { TTestOpenApiWriterPathResponsesLinks }
+
+  TTestOpenApiWriterPathResponsesLinks = class(TTestOpenApiWriterPathBase)
+  Public
+    Function AddLink(aPath : String) : TLink;
+  Published
+    procedure TestEmpty;
+    Procedure TestOperatonRef;
+    Procedure TestOperatonId;
+    Procedure TestParameters;
+    Procedure TestRequestBody;
+    Procedure TestDescription;
+    Procedure TestServer;
+  end;
+
+  { TTestOpenApiWriterPathSecurity }
+
+  TTestOpenApiWriterPathSecurity = class(TTestOpenApiWriterPathBase)
+  Published
+    Procedure TestEmpty;
+    Procedure TestAPIKey;
+  end;
+
+  { TTestOpenApiWriterWebHooks }
+
+  TTestOpenApiWriterWebHooks = class(TTestOpenApiWriterBase)
+  Public
+     function AddWebHook(const aname : string) : TPathItem;
+  Published
+    procedure TestEmpty;
+    procedure TestSummary;
+    // At the moment, no more tests needed: the items are identical to path items.
+  end;
+
+  { TTestOpenApiWriterComponents }
+
+  TTestOpenApiWriterComponents = class(TTestOpenApiWriterBase)
+  Public
+     function AddComponentSchema(const aname: string): TJSONSchema;
+  Published
+    procedure TestSchemaEmpty;
+    procedure TestSchemaContentEncoding;
+  end;
+
+  { TTestOpenApiWriterSecurity }
+
+  TTestOpenApiWriterSecurity = class(TTestOpenApiWriterBase)
+  Published
+    procedure TestOne;
+  end;
+
+  (*
+
+property Components: TComponents Read Get_Components write Set_Components;
+property Security: TSecurityRequirementList Read Get_Security write Set_Security;
+
+*)
+
+implementation
+
+uses jsoncomparer;
+
+var
+  _Sources : TStrings;
+  _Decl : TStrings;
+  _LastClass : String;
+
+function  ChangeRead(S : String) : String;
+begin
+  Result:=StringReplace(S,'Write','Reade',[rfReplaceAll,rfIgnoreCase]);
+end;
+
+procedure StartSources; forward;
+
+
+Procedure AddMethod(aClassName,aTestName : string; const aJSON : String);
+
+var
+  lClass,lTest : String;
+  J,S : TJSONObject;
+  D : TJSONData;
+  P,N : String;
+
+
+begin
+  lClass:=ChangeRead(aClassName);
+  lTest:=ChangeRead(aTestName);
+  if lClass<>_LastClass then
+    begin
+    if _LastClass<>'' then
+      _Decl.Add('  end;');
+    _Decl.Add('');
+    _Decl.Add('  %s = Class(TOpenAPITestRead)',[lClass]);
+    _LastClass:=lClass;
+    end;
+  _Decl.Add('    Procedure %s;',[lTest]);
+  _Sources.Add('');
+  _Sources.Add('procedure %s.%s;',[lClass,lTest]);
+  _Sources.Add('');
+  _Sources.Add('begin');
+  _Sources.Add('  TestRead(''%s'');',[aJSON]);
+  J:=GetJSON(aJSON) as TJSONObject;
+  P:='OpenAPI';
+  S:=Nil;
+  try
+    if J.Count>0 then
+      begin
+      D:=J.Items[0];
+      if D is TJSONObject then
+        S:=TJSONObject(D);
+      N:=J.Names[0];
+      While S is TJSONObject do
+        begin
+        P:=P+'.'+N;
+        _Sources.Add('  AssertNotNull(''%s'',%s);',[P,P]);
+        if S.Count=0 then
+          begin
+          D:=Nil;
+          S:=Nil;
+          Continue;
+          end;
+        D:=S.Items[0];
+        N:=S.Names[0];
+        if (D is TJSONArray) and (TJSONArray(D).Count>0) then
+          begin
+          D:=TJSONArray(D)[0];
+          N:=N+'[0]';
+          end;
+        if D is TJSONObject then
+          S:=TJSONObject(D)
+        else
+          S:=Nil;
+        end;
+      P:=P+'.'+N;
+      if assigned(D) then
+        Case D.JSONType of
+          jtString : _Sources.Add('  AssertEquals(''%s'',''%s'',%s);',[P,D.AsString,P]);
+          jtBoolean : _Sources.Add('  AssertEquals(''%s'',%s,%s);',[P,D.AsString,P]);
+          jtNumber : _Sources.Add('  AssertEquals(''%s'',%s,%s);',[P,D.AsString,P]);
+        end;
+      end;
+  finally
+    J.Free;
+  end;
+  _Sources.Add('end;');
+  _Sources.Add('');
+end;
+
+
+procedure TTestOpenApiWriterBase.AddSource(const aFmt: string; aArgs: array of const);
+begin
+  AddSource(Format(aFmt,aArgs));
+end;
+
+procedure TTestOpenApiWriterBase.AddSource(const aLine: string);
+begin
+  _Sources.Add(aLine);
+end;
+
+procedure TTestOpenApiWriterBase.AddDecl(const aFmt: string; aArgs: array of const);
+begin
+  _Decl.Add(aFmt,aArgs);
+end;
+
+procedure TTestOpenApiWriterBase.SetUp;
+begin
+  FOpenAPI:=TOpenAPI.Create;
+  if _Decl=Nil then
+    StartSources;
+end;
+
+procedure TTestOpenApiWriterBase.TearDown;
+begin
+  FreeAndNil(FOpenAPI);
+  FreeAndNil(FDocument);
+end;
+
+procedure TTestOpenApiWriterBase.WriteOpenAPI;
+
+var
+  W : TOpenAPIWriter;
+
+begin
+  W:=TOpenAPIWriter.Create(Nil);
+  try
+    FDocument:=W.WriteToJSON(OpenAPI);
+  finally
+    W.Free;
+  end;
+end;
+
+
+procedure TTestOpenApiWriterBase.CheckJSON(const Msg: String; aJSON: TJSONStringType);
+
+var
+  Data : TJSONData;
+  Obj : TJSONObject absolute data;
+  Errors : TStrings;
+
+begin
+  Errors:=Nil;
+  Data:=GetJSON(aJSON,true) as TJSONObject;
+  try
+    AssertEquals('Json object',TJSONObject,Data.ClassType);
+    Errors:=TStringList.Create;
+    // Writeln('Comparing ',Obj.AsJSON,' === ',Document.AsJSON);
+    TJSONComparer.Compare(Obj,Document,Errors);
+    if (Errors.Count<>0) then
+      Fail(Msg+':'#10+Errors.Text);
+  finally
+    Errors.Free;
+    Data.Free;
+  end;
+end;
+
+procedure TTestOpenApiWriterBase.TestWrite(const Msg: String; aJSON: TJSONStringType);
+begin
+  AddMethod(ClassName,TestName,aJSON);
+  WriteOpenAPI;
+  CheckJSON(msg,aJSON);
+end;
+
+
+procedure TTestOpenApiWriterBase.TestHookUp;
+begin
+  AssertNotNull('have openapi',OpenAPI);
+  AssertNull('have no document',Document);
+end;
+
+procedure TTestopenApiWriterOpenApi.TestEmpty;
+begin
+  WriteOpenApi;
+  CheckJSON('Empty','{}');
+end;
+
+
+procedure TTestopenApiWriterOpenAPI.TestOpenAPI;
+begin
+  OpenAPI.OpenAPI:='123';
+  TestWrite('openapi version','{ "openapi" : "123" }');
+end;
+
+procedure TTestopenApiWriterOpenAPI.TestJSONSchemaDialect;
+begin
+  OpenAPI.JSONSchemaDialect:='123';
+  TestWrite('json schema dialect','{ "jsonSchemaDialect" : "123" }');
+end;
+
+procedure TTestopenApiWriterInfo.TestVersion;
+begin
+  OpenAPI.Info.Version:='123';
+  TestWrite('Version','{ "info" : { "version" : "123" } }');
+end;
+
+procedure TTestopenApiWriterInfo.TestTitle;
+begin
+  OpenAPI.Info.title:='123';
+  TestWrite('Title','{ "info" : { "title" : "123" } }');
+end;
+
+procedure TTestopenApiWriterInfo.TestSummary;
+begin
+  OpenAPI.Info.summary:='123';
+  TestWrite('Summary','{ "info" : { "summary" : "123" } }');
+end;
+
+procedure TTestopenApiWriterInfo.TestDescription;
+begin
+  OpenAPI.Info.Description:='123';
+  TestWrite('Description','{ "info" : { "description" : "123" } }');
+end;
+
+procedure TTestopenApiWriterInfo.TestTermsOfService;
+begin
+  OpenAPI.Info.TermsOfService:='123';
+  TestWrite('TermsOfService','{ "info" : { "termsOfService" : "123" } }');
+end;
+
+procedure TTestopenApiWriterInfo.TestContactEmail;
+begin
+  OpenAPI.Info.Contact.Email:='123';
+  TestWrite('Contact mail','{ "info" : { "contact" : { "email" : "123" } } }');
+end;
+
+procedure TTestopenApiWriterInfo.TestContactName;
+begin
+  OpenAPI.Info.Contact.Name:='123';
+  TestWrite('Contact name','{ "info" : { "contact" : { "name" : "123" } } }');
+end;
+
+procedure TTestopenApiWriterInfo.TestContactURL;
+begin
+  OpenAPI.Info.Contact.URL:='123';
+  TestWrite('Contact url','{ "info" : { "contact" : { "url" : "123" } } }');
+end;
+
+procedure TTestopenApiWriterInfo.TestLicenseUrl;
+begin
+  OpenAPI.Info.License.Url:='123';
+  TestWrite('license url','{ "info" : { "license" : { "url" : "123" } } }');
+end;
+
+procedure TTestopenApiWriterInfo.TestLicenseName;
+begin
+  OpenAPI.Info.License.Name:='123';
+  TestWrite('license name','{ "info" : { "license" : { "name" : "123" } } }');
+end;
+
+
+procedure TTestopenApiWriterInfo.TestLicenseIdentifier;
+begin
+  OpenAPI.Info.License.Identifier:='123';
+  TestWrite('license name','{ "info" : { "license" : { "identifier" : "123" } } }');
+end;
+
+procedure TTestopenApiWriterTags.TestName;
+
+var
+  T : TTag;
+
+begin
+  T:=TTag.Create(OpenAPI,'tags[0]');
+  T.Name:='123';
+  OpenAPI.Tags.Add(T);
+  TestWrite('name','{ "tags" : [ { "name" : "123" } ] }');
+end;
+
+procedure TTestopenApiWriterTags.TestDescription;
+var
+  T : TTag;
+
+begin
+  T:=TTag.Create(OpenAPI,'tags[1]');
+  T.Description:='123';
+  OpenAPI.Tags.Add(T);
+  TestWrite('description','{ "tags" : [ { "description" : "123" } ] }');
+end;
+
+procedure TTestopenApiWriterTags.TestExternalDocs;
+var
+  T : TTag;
+
+begin
+  T:=TTag.Create(OpenAPI,'tags[1]');
+  T.ExternalDocs.Url:='123';
+  OpenAPI.Tags.Add(T);
+  TestWrite('externaldocs','{ "tags" : [ { "externalDocs" : { "url" :"123" } } ] }');
+end;
+
+procedure TTestopenApiWriterTags.Test2Tags;
+var
+  T : TTag;
+
+begin
+  T:=TTag.Create(OpenAPI,'tags[0]');
+  T.Name:='123';
+  OpenAPI.Tags.Add(T);
+  T:=TTag.Create(OpenAPI,'tags[1]');
+  T.Name:='456';
+  OpenAPI.Tags.Add(T);
+  TestWrite('multi','{ "tags" : [ { "name" : "123" },  { "name" : "456" } ] }');
+end;
+
+procedure TTestopenApiWriterExternalDocs.TestUrl;
+
+begin
+  OpenAPI.ExternalDocs.Url:='123';
+  TestWrite('Url','{ "externalDocs" : { "url" :"123" } }');
+end;
+
+procedure TTestopenApiWriterExternalDocs.TestDescription;
+begin
+  OpenAPI.ExternalDocs.Description:='123';
+  TestWrite('description','{ "externalDocs" : { "description" :"123" } }');
+end;
+
+{ TTestOpenApiWriterServers }
+
+procedure TTestOpenApiWriterServers.TestUrl;
+
+var
+  Server : TServer;
+
+begin
+  Server:=TServer.Create(OpenAPI,'servers[0]');
+  Server.Url:='123';
+  OpenAPI.Servers.Add(Server);
+  TestWrite('url','{ "servers" : [ { "url" :"123" } ] }');
+end;
+
+procedure TTestOpenApiWriterServers.TestDescription;
+
+var
+  Server : TServer;
+
+begin
+  Server:=TServer.Create(OpenAPI,'servers[0]');
+  Server.description:='123';
+  OpenAPI.Servers.Add(Server);
+  TestWrite('url','{ "servers" : [ { "description" :"123" } ] }');
+end;
+
+procedure TTestOpenApiWriterServers.TestVariablesDefault;
+var
+  Server : TServer;
+  ServerVar : TServerVariable;
+begin
+  Server:=TServer.Create(OpenAPI,'servers[0]');
+  ServerVar:=Server.Variables.AddItem('user');
+  ServerVar.Default:='123';
+  OpenAPI.Servers.Add(Server);
+  TestWrite('var.default','{ "servers" : [ { "variables" : { "user": { "default": "123" } } } ] }');
+end;
+
+procedure TTestOpenApiWriterServers.TestVariablesDescription;
+var
+  Server : TServer;
+  ServerVar : TServerVariable;
+begin
+  Server:=TServer.Create(OpenAPI,'servers[0]');
+  ServerVar:=Server.Variables.AddItem('user');
+  ServerVar.Description:='123';
+  OpenAPI.Servers.Add(Server);
+  TestWrite('var.description','{ "servers" : [ { "variables" : { "user": { "description": "123" } } } ] }');
+end;
+
+procedure TTestOpenApiWriterServers.TestVariablesEnum;
+var
+  Server : TServer;
+  ServerVar : TServerVariable;
+begin
+  Server:=TServer.Create(OpenAPI,'servers[0]');
+  ServerVar:=Server.Variables.AddItem('user');
+  ServerVar.Enum.Add('123');
+  ServerVar.Enum.Add('456');
+  OpenAPI.Servers.Add(Server);
+  TestWrite('var.enum','{ "servers" : [ { "variables" : { "user": { "enum": [ "123", "456" ] } } } ] }');
+end;
+
+procedure TTestOpenApiWriterServers.Test2Url;
+var
+  Server : TServer;
+
+begin
+  Server:=TServer.Create(OpenAPI,'servers[0]');
+  Server.Url:='123';
+  OpenAPI.Servers.Add(Server);
+  Server:=TServer.Create(OpenAPI,'servers[0]');
+  Server.Url:='456';
+  OpenAPI.Servers.Add(Server);
+  TestWrite('url','{ "servers" : [ { "url" :"123" }, { "url" :"456" } ] }');
+end;
+
+{ TTestOpenApiWriterPaths }
+
+function TTestOpenApiWriterPathBase.AddPath(aPath: String): TPathItem;
+begin
+  Result:=OpenAPI.Paths.AddItem(aPath);
+end;
+
+procedure TTestOpenApiWriterPaths.TestEmpty;
+
+var
+  P : TPathItem;
+begin
+  P:=AddPath('api');
+  AssertNotNull('Have path',P);
+  TestWrite('Path','{ "paths" : { "api" : {} } }');
+end;
+
+procedure TTestOpenApiWriterPaths.TestRef;
+var
+  P : TPathItem;
+begin
+  P:=AddPath('api');
+  P.Ref:='abc';
+  TestWrite('Path ref','{ "paths" : { "api" : { "$ref": "abc"} } }');
+end;
+
+procedure TTestOpenApiWriterPaths.TestSummary;
+var
+  P : TPathItem;
+begin
+  P:=AddPath('api');
+  P.Summary:='abc';
+  TestWrite('Path summary','{ "paths" : { "api" : { "summary": "abc"} } }');
+end;
+
+procedure TTestOpenApiWriterPaths.TestDescription;
+var
+  P : TPathItem;
+begin
+  P:=AddPath('api');
+  P.description:='abc';
+  TestWrite('Path description','{ "paths" : { "api" : { "description": "abc"} } }');
+end;
+
+procedure TTestOpenApiWriterPaths.TestGetServers;
+var
+  P : TPathItem;
+  S : TServer;
+begin
+  P:=AddPath('api');
+  S:=TServer.Create(P,'servers[0]');
+  P.Servers.Add(S);
+  TestWrite('Path description','{ "paths" : { "api" : { "servers": [ {} ] } } }');
+end;
+
+procedure TTestOpenApiWriterPaths.TestGetEmpty;
+var
+  P : TPathItem;
+begin
+  P:=AddPath('api');
+  AssertEquals('Empty','',P.Get.Summary);
+  TestWrite('Path get','{ "paths" : { "api" : { "get": { } } } }');
+end;
+
+procedure TTestOpenApiWriterPaths.TestGetSummary;
+var
+  P : TPathItem;
+begin
+  P:=AddPath('api');
+  P.Get.Summary:='123';
+  TestWrite('Path get summary','{ "paths" : { "api" : { "get": { "summary" : "123" } } } }');
+end;
+
+procedure TTestOpenApiWriterPaths.TestGetDescription;
+var
+  P : TPathItem;
+begin
+  P:=AddPath('api');
+  P.Get.Description:='123';
+  TestWrite('Path get description','{ "paths" : { "api" : { "get": { "description" : "123" } } } }');
+end;
+
+procedure TTestOpenApiWriterPaths.TestGetOperationId;
+var
+  P : TPathItem;
+begin
+  P:=AddPath('api');
+  P.Get.operationId:='123';
+  TestWrite('Path get operationId','{ "paths" : { "api" : { "get": { "operationId" : "123" } } } }');
+end;
+
+procedure TTestOpenApiWriterPaths.TestGetDeprecated;
+var
+  P : TPathItem;
+begin
+  P:=AddPath('api');
+  P.Get.Deprecated:=True;
+  TestWrite('Path get operationId','{ "paths" : { "api" : { "get": { "deprecated" : true } } } }');
+end;
+
+procedure TTestOpenApiWriterPaths.TestGetExternalDocsEmpty;
+var
+  P : TPathItem;
+begin
+  P:=AddPath('api');
+  AssertNotNull('Get creates',P.Get.ExternalDocs);
+  TestWrite('Path get operationId','{ "paths" : { "api" : { "get": { "externalDocs" : {  } } } } }');
+end;
+
+procedure TTestOpenApiWriterPaths.TestGetExternalDocsURL;
+var
+  P : TPathItem;
+begin
+  P:=AddPath('api');
+  P.Get.ExternalDocs.Url:='123';
+  TestWrite('Path get externaldocs','{ "paths" : { "api" : { "get": { "externalDocs" : { "url" : "123" } } } } }');
+end;
+
+{ TTestOpenApiWriterPathRequestBody }
+
+function TTestOpenApiWriterPathRequestBody.AddBody(aPath: String): TRequestBody;
+
+begin
+  Result:=AddPath(aPath).Get.RequestBody;
+end;
+
+procedure TTestOpenApiWriterPathRequestBody.TestEmpty;
+
+var
+  R : TRequestBody;
+begin
+  R:=AddBody('api');
+  AssertNotNull('Get creates',R);
+  TestWrite('Path get requestbody','{ "paths" : { "api" : { "get": { "requestBody" : {  } } } } }');
+end;
+
+procedure TTestOpenApiWriterPathRequestBody.TestDescription;
+
+var
+  R : TRequestBody;
+begin
+  R:=AddBody('api');
+  R.Description:='123';
+  TestWrite('Path get requestbody','{ "paths" : { "api" : { "get": { "requestBody" : { "description" : "123" } } } } }');
+end;
+
+procedure TTestOpenApiWriterPathRequestBody.TestRequired;
+var
+  R : TRequestBody;
+begin
+  R:=AddBody('api');
+  R.Required:=True;
+  TestWrite('Path get requestbody','{ "paths" : { "api" : { "get": { "requestBody" : { "required" : true} } } } }');
+end;
+
+
+
+procedure TTestOpenApiWriterPathRequestBody.TestContent;
+
+var
+  R : TRequestBody;
+begin
+  R:=AddBody('api');
+  R.Content.AddItem('123');
+  TestWrite('Path get operationId','{ "paths" : { "api" : { "get": { "requestBody" : { "content" : { "123" : { } } } } } } }');
+end;
+
+procedure TTestOpenApiWriterPathRequestBody.TestContentSchema;
+
+var
+  R : TRequestBody;
+begin
+  R:=AddBody('api');
+  R.Content.AddItem('123').Schema:=TJSONSchema.Create();
+  TestWrite('Path get operationId','{ "paths" : { "api" : { "get": { "requestBody" : { "content" : { "123" : { "schema" : true } } } } } } }');
+end;
+
+procedure TTestOpenApiWriterPathRequestBody.TestContentExample;
+var
+  R : TRequestBody;
+begin
+  R:=AddBody('api');
+  R.Content.AddItem('123').example:=TJSONObject.Create;
+  TestWrite('Path get operationId','{ "paths" : { "api" : { "get": { "requestBody" : { "content" : { "123" : { "example" : { } } } } } } } }');
+end;
+
+procedure TTestOpenApiWriterPathRequestBody.TestContentExamples;
+var
+  R : TRequestBody;
+begin
+  R:=AddBody('api');
+  R.Content.AddItem('123').examples.AddItem('abc').Summary:='x';
+  TestWrite('Path get operationId','{ "paths" : { "api" : { "get": { "requestBody" : { "content" : { "123" : { "examples" : { "abc" : { "summary": "x"} } } } } } } } }');
+end;
+
+procedure TTestOpenApiWriterPathRequestBody.TestContentEncodingContentType;
+var
+  R : TRequestBody;
+begin
+  R:=AddBody('api');
+  R.Content.AddItem('123').Encoding.AddItem('abc').ContentType:='def';
+  TestWrite('Path get operationId','{ "paths" : { "api" : { "get": { "requestBody" : { "content" : { "123" : { "encoding" : { "abc" : { "contentType": "def"} } } } } } } } }');
+end;
+
+procedure TTestOpenApiWriterPathRequestBody.TestContentEncodingExplode;
+var
+  R : TRequestBody;
+begin
+  R:=AddBody('api');
+  R.Content.AddItem('123').Encoding.AddItem('abc').Explode:=True;
+  TestWrite('Path get operationId','{ "paths" : { "api" : { "get": { "requestBody" : { "content" : { "123" : { "encoding" : { "abc" : { "explode": true} } } } } } } } }');
+end;
+
+procedure TTestOpenApiWriterPathRequestBody.TestContentEncodingStyle;
+var
+  R : TRequestBody;
+begin
+  R:=AddBody('api');
+  R.Content.AddItem('123').Encoding.AddItem('abc').Style:='def';
+  TestWrite('Path get operationId','{ "paths" : { "api" : { "get": { "requestBody" : { "content" : { "123" : { "encoding" : { "abc" : { "style": "def"} } } } } } } } }');
+end;
+
+procedure TTestOpenApiWriterPathRequestBody.TestContentEncodingAllowReserved;
+var
+  R : TRequestBody;
+begin
+  R:=AddBody('api');
+  R.Content.AddItem('123').Encoding.AddItem('abc').AllowReserved:=True;
+  TestWrite('Path get operationId','{ "paths" : { "api" : { "get": { "requestBody" : { "content" : { "123" : { "encoding" : { "abc" : { "allowReserved": true} } } } } } } } }');
+end;
+
+procedure TTestOpenApiWriterPathRequestBody.TestContentEncodingHeaders;
+var
+  R : TRequestBody;
+begin
+  R:=AddBody('api');
+  R.Content.AddItem('123').Encoding.AddItem('abc').Headers.AddItem('def').Explode:=True;
+  TestWrite('Path get operationId','{ "paths" : { "api" : { "get": { "requestBody" : { "content" : { "123" : { "encoding" : { "abc" : { "headers": { "def" : { "explode" : true } } } } } } } } } } }');
+end;
+
+function TTestOpenApiWriterPathParameters.AddParam(aPath: String): TParameter;
+
+var
+  P : TPathItem;
+
+begin
+  P:=addPath(aPath);
+  Result:=P.Parameters.AddParam(P);
+end;
+
+procedure TTestOpenApiWriterPathParameters.TestGetParametersEmpty;
+
+var
+  P : TParameter;
+
+begin
+  P:=AddParam('api');
+  AssertNotNull('have p',p);
+  TestWrite('Path param','{ "paths" : { "api" : { "parameters": [ {} ] } } }');
+end;
+
+function TTestOpenApiWriterPathResponses.AddResponse(aPath: String): TResponse;
+begin
+  Result:=AddPath(aPath).Get.Responses.AddItem('default');
+end;
+
+procedure TTestOpenApiWriterPathResponses.TestEmpty;
+begin
+  AssertNotNull('Have response',AddResponse('api'));
+  TestWrite('Path param','{ "paths" : { "api" : { "get" : { "responses": { "default" : {} } } } } }');
+end;
+
+procedure TTestOpenApiWriterPathResponses.TestHeaders;
+begin
+  AddResponse('api').Headers.AddItem('x-content');
+  TestWrite('Path param','{ "paths" : { "api" : { "get" : { "responses": { "default" : { "headers" : { "x-content" : { } } } } } } } }');
+end;
+
+procedure TTestOpenApiWriterPathResponses.TestDescription;
+begin
+  AddResponse('api').Description:='abc';
+  TestWrite('Path param','{ "paths" : { "api" : { "get" : { "responses": { "default" : { "description" : "abc" } } } } } }');
+end;
+
+procedure TTestOpenApiWriterPathResponses.TestContentEmpty;
+begin
+  AddResponse('api').content.AddItem('application/json');
+  TestWrite('Path param','{ "paths" : { "api" : { "get" : { "responses": { "default" : { "content" : { "application/json" : { } } } } } } } }');
+end;
+
+procedure TTestOpenApiWriterPathResponses.TestContentSchema;
+begin
+  AssertNotNull('Have schema',AddResponse('api').content.AddItem('application/json').Schema);
+  TestWrite('Path param','{ "paths" : { "api" : { "get" : { "responses": { "default" : { "content" : { "application/json" : { "schema" : true } } } } } } } }');
+end;
+
+procedure TTestOpenApiWriterPathResponses.TestContentExample;
+begin
+  AddResponse('api').content.AddItem('application/json').Example:=TJSONObject.Create;
+  TestWrite('Path param','{ "paths" : { "api" : { "get" : { "responses": { "default" : { "content" : { "application/json" : { "example" : {} } } } } } } } }');
+end;
+
+procedure TTestOpenApiWriterPathResponses.TestContentExamples;
+begin
+  AddResponse('api').content.AddItem('application/json').Examples.AddItem('abc').Summary:='x';
+  TestWrite('Path param','{ "paths" : { "api" : { "get" : { "responses": { "default" : { "content" : { "application/json" : { "examples" : { "abc" : { "summary": "x"} } } } } } } } } }');
+end;
+
+procedure TTestOpenApiWriterPathResponses.TestContentEncodingEmpty;
+begin
+  AddResponse('api').content.AddItem('application/json').Encoding.AddItem('abc'); //.ContentType:='application/json';
+  TestWrite('Path param','{ "paths" : { "api" : { "get" : { "responses": { "default" : { "content" : { "application/json" : { "encoding" : { "abc" : { } } } } } } } } } }');
+
+end;
+
+procedure TTestOpenApiWriterPathResponses.TestContentEncodingContentType;
+begin
+  AddResponse('api').content.AddItem('application/json').Encoding.AddItem('abc').ContentType:='application/json';
+  TestWrite('Path param','{ "paths" : { "api" : { "get" : { "responses": { "default" : { "content" : { "application/json" : { "encoding" : { "abc" : { "contentType" : "application/json" } } } } } } } } } }');
+end;
+
+{ TTestOpenApiWriterPathResponsesLinks }
+
+function TTestOpenApiWriterPathResponsesLinks.AddLink(aPath: String): TLink;
+begin
+  Result:=AddPath(aPath).Get.Responses.AddItem('default').links.AddItem('abc');
+end;
+
+procedure TTestOpenApiWriterPathResponsesLinks.TestEmpty;
+begin
+  AddLink('api');
+  TestWrite('Path param','{ "paths" : { "api" : { "get" : { "responses" : { "default" : { "links": { "abc" : { } } } } } } } }');
+end;
+
+procedure TTestOpenApiWriterPathResponsesLinks.TestOperatonRef;
+begin
+  AddLink('api').OperationRef:='123';
+  TestWrite('Path param','{ "paths" : { "api" : { "get" : { "responses" : { "default" : { "links": { "abc" : { "operationRef" : "123" } } } } } } } }');
+end;
+
+procedure TTestOpenApiWriterPathResponsesLinks.TestOperatonId;
+begin
+  AddLink('api').OperationId:='123';
+  TestWrite('Path param','{ "paths" : { "api" : { "get" : { "responses" : { "default" : { "links": { "abc" : { "operationId" : "123" } } } } } } } }');
+end;
+
+procedure TTestOpenApiWriterPathResponsesLinks.TestParameters;
+begin
+  AddLink('api').Parameters.Add('x','y');
+  TestWrite('Path param','{ "paths" : { "api" : { "get" : { "responses" : { "default" : { "links": { "abc" : { "parameters" : { "x" : "y" } } } } } } } } }');
+end;
+
+procedure TTestOpenApiWriterPathResponsesLinks.TestRequestBody;
+begin
+  AddLink('api').RequestBody:=TJSONObject.Create();
+  TestWrite('Path param','{ "paths" : { "api" : { "get" : { "responses" : { "default" : { "links": { "abc" : { "requestBody" : {} } } } } } } } }');
+end;
+
+procedure TTestOpenApiWriterPathResponsesLinks.TestDescription;
+begin
+  AddLink('api').Description:='123';
+  TestWrite('Path param','{ "paths" : { "api" : { "get" : { "responses" : { "default" : { "links": { "abc" : { "description" : "123" } } } } } } } }');
+end;
+
+procedure TTestOpenApiWriterPathResponsesLinks.TestServer;
+begin
+  AddLink('api').Server.Url:='123';
+  TestWrite('Path param','{ "paths" : { "api" : { "get" : { "responses" : { "default" : { "links": { "abc" : { "server" : { "url" : "123" } } } } } } } } }');
+end;
+
+procedure TTestOpenApiWriterPathSecurity.TestEmpty;
+
+var
+  O : TAPIOperation;
+
+begin
+  O:=AddPath('api').Get;
+  O.Security.AddSecurity(O);
+  TestWrite('Path param','{ "paths" : { "api" : { "get" : { "security" : [ {} ] } } } }');
+end;
+
+procedure TTestOpenApiWriterPathSecurity.TestAPIKey;
+var
+  O : TAPIOperation;
+
+begin
+  O:=AddPath('api').Get;
+  O.Security.AddSecurity(O).AddItem('api_key').Add('akey');
+  TestWrite('Path param','{ "paths" : { "api" : { "get" : { "security" : [ { "api_key" : ["akey"] } ] } } } }');
+end;
+
+{ TTestOpenApiWriterWebHooks }
+
+function TTestOpenApiWriterWebHooks.AddWebHook(const aname: string): TPathItem;
+begin
+  Result:=OpenAPI.WebHooks.AddItem(aName);
+end;
+
+procedure TTestOpenApiWriterWebHooks.TestEmpty;
+begin
+  AssertNotNull(OpenAPI.WebHooks.AddItem('newitem'));
+  TestWrite('Path param','{ "webhooks" : { "newitem" : { } } }');
+end;
+
+procedure TTestOpenApiWriterWebHooks.TestSummary;
+begin
+  OpenAPI.WebHooks.AddItem('newitem').Summary:='abc';
+  TestWrite('Path param','{ "webhooks" : { "newitem" : { "summary" : "abc" } } }');
+end;
+
+{ TTestOpenApiWriterComponents }
+
+function TTestOpenApiWriterComponents.AddComponentSchema(const aname: string): TJSONSchema;
+begin
+  Result:=OpenAPI.Components.Schemas.Add(aName);
+end;
+
+procedure TTestOpenApiWriterComponents.TestSchemaEmpty;
+begin
+  AssertNotNull('Schema',AddComponentSchema('abc'));
+  TestWrite('Path componentschema','{ "components" : { "schemas" : { "abc" : true } } }');
+end;
+
+procedure TTestOpenApiWriterComponents.TestSchemaContentEncoding;
+begin
+  AddComponentSchema('abc').Validations.contentEncoding:='utf8';
+  TestWrite('Path componentschema','{ "components" : { "schemas" : { "abc" : { "contentEncoding" : "utf8" } } } }');
+end;
+
+{ TTestOpenApiWriterSecurity }
+
+procedure TTestOpenApiWriterSecurity.TestOne;
+begin
+  OpenAPI.Security.AddSecurity(OpenAPI).AddItem('abc');
+  TestWrite('Security','{ "security" : [ { "abc" : [] } ] }');
+end;
+
+procedure StartSources;
+
+begin
+  _Sources:=TStringList.Create;
+  _Decl:=TStringList.Create;
+  _Decl.Add('unit ReadTests;');
+  _Decl.Add('');
+  _Decl.Add('interface');
+  _Decl.Add('');
+  _Decl.Add('uses fpcunit;');
+  _Decl.Add('');
+  _Decl.Add('type');
+  _Decl.Add('');
+end;
+
+procedure WriteSources;
+
+begin
+  _Decl.Add('  end;');
+  _Decl.Add('');
+  _Decl.Add('implementation');
+  _Decl.Add('');
+  _Decl.AddStrings(_Sources);
+  _Decl.Add('');
+  _Decl.Add('end.');
+  _Decl.SaveToFile('ReadTests.pp');
+  _Sources.Free;
+  _Decl.Free;
+end;
+
+initialization
+//  StartSources;
+  RegisterTests('Writer',[
+    TTestopenApiWriterOpenAPI,
+    TTestopenApiWriterInfo,
+    TTestopenApiWriterTags,
+    TTestOpenApiWriterExternalDocs,
+    TTestOpenApiWriterServers,
+    TTestOpenApiWriterPaths,
+    TTestOpenApiWriterPathRequestBody,
+    TTestOpenApiWriterPathParameters,
+    TTestOpenApiWriterPathResponses,
+    TTestOpenApiWriterPathSecurity,
+    TTestOpenApiWriterPathResponsesLinks,
+    TTestOpenApiWriterWebHooks,
+    TTestOpenApiWriterComponents,
+    TTestOpenApiWriterSecurity
+  ]);
+
+finalization
+  if assigned(_Decl) then
+    WriteSources;
+end.
+

+ 64 - 0
packages/fcl-openapi/tests/utOpenApi.pp

@@ -0,0 +1,64 @@
+unit utOpenApi;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, fpcunit, testutils, testregistry, fpopenapi.objects;
+
+type
+
+  { TTestOpenApi }
+
+  TTestOpenApi= class(TTestCase)
+  private
+    FOpenAPI: TOpenAPI;
+  Public
+    procedure SetUp; override;
+    procedure TearDown; override;
+    Property OpenApi : TOpenAPI Read FOpenAPI;
+  published
+    procedure TestHookUp;
+    procedure TestFind;
+  end;
+
+implementation
+
+procedure TTestOpenApi.SetUp;
+begin
+  inherited SetUp;
+  FOpenApi:=TOpenAPi.Create;
+end;
+
+procedure TTestOpenApi.TearDown;
+begin
+  FreeAndNil(FOpenApi);
+  inherited TearDown;
+end;
+
+procedure TTestOpenApi.TestHookUp;
+begin
+  AssertNotNull('Have api',OpenApi);
+end;
+
+procedure TTestOpenApi.TestFind;
+
+var
+  P : TBaseOpenAPIObject;
+
+
+begin
+  AssertNull('Nothing yet',OpenApi.Find('paths'));
+  P:=OpenApi.Paths.AddItem('get');
+  AssertSame('Have paths',OpenApi.Paths,OpenApi.Find('paths'));
+  AssertSame('Have paths/get',P,OpenApi.Find('paths/get'));
+end;
+
+
+
+initialization
+
+  RegisterTest(TTestOpenApi);
+end.
+

+ 1079 - 0
packages/fcl-openapi/tests/utOpenApiReader.pp

@@ -0,0 +1,1079 @@
+unit utOpenApiReader;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, fpcunit, fpjson, testregistry, fpopenapi.objects, fpopenapi.reader;
+
+Type
+
+  { TTestOpenApiReader }
+
+  TTestOpenApiReader = class(TTestCase)
+  private
+    FOpenAPI: TOpenAPi;
+    FReader: TOpenAPIReader;
+  Public
+    Procedure Setup; override;
+    Procedure TearDown; override;
+    procedure LoadJSON(aJSON: TJSONStringType);
+    procedure LoadJSONFile(aJSONFileName: TJSONStringType);
+    Procedure TestRead(const aJSON : String);
+    Property Reader : TOpenAPIReader Read FReader;
+    Property OpenAPI : TOpenAPi Read FOpenAPI;
+  Published
+    Procedure TestHookup;
+  end;
+
+  TTestOpenApiReaderLarge = class (TTestOpenApiReader)
+  Published
+    procedure TestTitle;
+    Procedure TestLarge;
+  end;
+
+//  TTestOpenAPIReader =
+
+  TTestOpenApiReaderOpenAPI = Class(TTestOpenAPIReader)
+    Procedure TestOpenAPI;
+    Procedure TestJSONSchemaDialect;
+  end;
+
+  TTestOpenApiReaderInfo = Class(TTestOpenAPIReader)
+    Procedure TestVersion;
+    Procedure TestTitle;
+    Procedure TestSummary;
+    Procedure TestDescription;
+    Procedure TestTermsOfService;
+    Procedure TestContactEmail;
+    Procedure TestContactName;
+    Procedure TestContactURL;
+    Procedure TestLicenseUrl;
+    Procedure TestLicenseIdentifier;
+    Procedure TestLicenseName;
+  end;
+
+  TTestOpenApiReaderTags = Class(TTestOpenAPIReader)
+    Procedure TestName;
+    Procedure TestDescription;
+    Procedure TestExternalDocs;
+    Procedure Test2Tags;
+  end;
+
+  TTestOpenApiReaderExternalDocs = Class(TTestOpenAPIReader)
+    Procedure TestUrl;
+    Procedure TestDescription;
+  end;
+
+  TTestOpenApiReaderServers = Class(TTestOpenAPIReader)
+    Procedure TestUrl;
+    Procedure TestDescription;
+    Procedure TestVariablesDefault;
+    Procedure TestVariablesDescription;
+    Procedure TestVariablesEnum;
+    Procedure Test2Url;
+  end;
+
+  TTestOpenApiReaderPaths = Class(TTestOpenAPIReader)
+    Procedure TestEmpty;
+    Procedure TestRef;
+    Procedure TestSummary;
+    Procedure TestDescription;
+    Procedure TestGetEmpty;
+    Procedure TestGetSummary;
+    Procedure TestGetDescription;
+    Procedure TestGetOperationId;
+    Procedure TestGetDeprecated;
+    Procedure TestGetExternalDocsEmpty;
+    Procedure TestGetExternalDocsURL;
+    Procedure TestGetServers;
+  end;
+
+  TTestOpenApiReaderPathRequestBody = Class(TTestOpenAPIReader)
+    Procedure TestEmpty;
+    Procedure TestDescription;
+    Procedure TestRequired;
+    Procedure TestContent;
+    Procedure TestContentSchema;
+    Procedure TestContentExample;
+    Procedure TestContentExamples;
+    Procedure TestContentEncodingContentType;
+    Procedure TestContentEncodingExplode;
+    Procedure TestContentEncodingStyle;
+    Procedure TestContentEncodingAllowReserved;
+    Procedure TestContentEncodingHeaders;
+  end;
+
+  TTestOpenApiReaderPathParameters = Class(TTestOpenAPIReader)
+    Procedure TestGetParametersEmpty;
+  end;
+
+  TTestOpenApiReaderPathResponses = Class(TTestOpenAPIReader)
+    Procedure TestEmpty;
+    Procedure TestHeaders;
+    Procedure TestDescription;
+    Procedure TestContentEmpty;
+    Procedure TestContentSchema;
+    Procedure TestContentExample;
+    Procedure TestContentExamples;
+    Procedure TestContentEncodingEmpty;
+    Procedure TestContentEncodingContentType;
+  end;
+
+  TTestOpenApiReaderPathSecurity = Class(TTestOpenAPIReader)
+    Procedure TestEmpty;
+    Procedure TestAPIKey;
+  end;
+
+  TTestOpenApiReaderPathResponsesLinks = Class(TTestOpenAPIReader)
+    Procedure TestEmpty;
+    Procedure TestOperatonRef;
+    Procedure TestOperatonId;
+    Procedure TestParameters;
+    Procedure TestRequestBody;
+    Procedure TestDescription;
+    Procedure TestServer;
+  end;
+
+  TTestOpenApiReaderWebHooks = Class(TTestOpenAPIReader)
+    Procedure TestEmpty;
+    Procedure TestSummary;
+  end;
+
+  TTestOpenApiReaderComponents = Class(TTestOpenAPIReader)
+    Procedure TestSchemaEmpty;
+    Procedure TestSchemaContentEncoding;
+  end;
+
+  TTestOpenApiReaderSecurity = Class(TTestOpenAPIReader)
+    Procedure TestOne;
+  end;
+
+implementation
+
+{ TTestOpenApiReader }
+
+procedure TTestOpenApiReader.Setup;
+begin
+  Inherited;
+  FReader:=TOpenAPIReader.Create(Nil);
+end;
+
+procedure TTestOpenApiReader.TearDown;
+begin
+  FreeAndNil(FOpenAPI);
+  FreeAndNil(FReader);
+  Inherited;
+end;
+
+procedure TTestOpenApiReader.LoadJSON(aJSON: TJSONStringType);
+begin
+  FreeAndNil(FOpenAPI);
+  FOpenAPI:=TOpenAPI.Create;
+  Reader.ReadFromString(OpenAPI,aJSON);
+end;
+
+procedure TTestOpenApiReader.LoadJSONFile(aJSONFileName: TJSONStringType);
+
+var
+  F : TFileStream;
+  aJSON : TJSONStringType;
+
+begin
+  aJSON:='';
+  F:=TFileStream.Create(aJSONFileName,fmOpenRead or fmShareDenyWrite);
+  try
+    SetLength(aJSON,F.Size);
+    F.ReadBuffer(aJSON[1],Length(aJSON));
+    LoadJSON(aJSON);
+  finally
+    F.Free;
+  end;
+end;
+
+procedure TTestOpenApiReader.TestRead(const aJSON: String);
+begin
+  LoadJSON(aJSON);
+end;
+
+procedure TTestOpenApiReader.TestHookup;
+begin
+  AssertNotNull('Have reader',FReader);
+end;
+
+procedure TTestOpenApiReaderLarge.TestTitle;
+
+const
+  JSON =
+    '  {' + sLineBreak+
+    '    "openapi": "3.0.0",' + sLineBreak+
+    '    "info": {' + sLineBreak+
+    '      "version": "1.0.0",' + sLineBreak+
+    '      "title": "Sample API",' + sLineBreak+
+    '      "description": "A sample API to illustrate OpenAPI concepts"' + sLineBreak+
+    '    }' + sLineBreak+
+    '  }';
+
+begin
+  LoadJSON(JSON);
+  AssertEquals('OpenApi','3.0.0',OpenAPI.OpenApi);
+  AssertEquals('OpenAPI.Info.Version','1.0.0',OpenAPI.Info.Version);
+  AssertEquals('OpenAPI.Info.title','Sample API',OpenAPI.Info.Title);
+  AssertEquals('OpenAPI.Info.description','A sample API to illustrate OpenAPI concepts',OpenAPI.Info.Description);
+end;
+
+procedure TTestOpenApiReaderLarge.TestLarge;
+begin
+  LoadJSONFile('openapi-all.json');
+end;
+
+procedure TTestOpenApiReaderOpenAPI.TestOpenAPI;
+
+begin
+  TestRead('{ "openapi" : "123" }');
+  AssertEquals('OpenAPI.openapi','123',OpenAPI.openapi);
+end;
+
+
+procedure TTestOpenApiReaderOpenAPI.TestJSONSchemaDialect;
+
+begin
+  TestRead('{ "jsonSchemaDialect" : "123" }');
+  AssertEquals('OpenAPI.jsonSchemaDialect','123',OpenAPI.jsonSchemaDialect);
+end;
+
+
+procedure TTestOpenApiReaderInfo.TestVersion;
+
+begin
+  TestRead('{ "info" : { "version" : "123" } }');
+  AssertNotNull('OpenAPI.info',OpenAPI.info);
+  AssertEquals('OpenAPI.info.version','123',OpenAPI.info.version);
+end;
+
+
+procedure TTestOpenApiReaderInfo.TestTitle;
+
+begin
+  TestRead('{ "info" : { "title" : "123" } }');
+  AssertNotNull('OpenAPI.info',OpenAPI.info);
+  AssertEquals('OpenAPI.info.title','123',OpenAPI.info.title);
+end;
+
+
+procedure TTestOpenApiReaderInfo.TestSummary;
+
+begin
+  TestRead('{ "info" : { "summary" : "123" } }');
+  AssertNotNull('OpenAPI.info',OpenAPI.info);
+  AssertEquals('OpenAPI.info.summary','123',OpenAPI.info.summary);
+end;
+
+
+procedure TTestOpenApiReaderInfo.TestDescription;
+
+begin
+  TestRead('{ "info" : { "description" : "123" } }');
+  AssertNotNull('OpenAPI.info',OpenAPI.info);
+  AssertEquals('OpenAPI.info.description','123',OpenAPI.info.description);
+end;
+
+
+procedure TTestOpenApiReaderInfo.TestTermsOfService;
+
+begin
+  TestRead('{ "info" : { "termsOfService" : "123" } }');
+  AssertNotNull('OpenAPI.info',OpenAPI.info);
+  AssertEquals('OpenAPI.info.termsOfService','123',OpenAPI.info.termsOfService);
+end;
+
+
+procedure TTestOpenApiReaderInfo.TestContactEmail;
+
+begin
+  TestRead('{ "info" : { "contact" : { "email" : "123" } } }');
+  AssertNotNull('OpenAPI.info',OpenAPI.info);
+  AssertNotNull('OpenAPI.info.contact',OpenAPI.info.contact);
+  AssertEquals('OpenAPI.info.contact.email','123',OpenAPI.info.contact.email);
+end;
+
+
+procedure TTestOpenApiReaderInfo.TestContactName;
+
+begin
+  TestRead('{ "info" : { "contact" : { "name" : "123" } } }');
+  AssertNotNull('OpenAPI.info',OpenAPI.info);
+  AssertNotNull('OpenAPI.info.contact',OpenAPI.info.contact);
+  AssertEquals('OpenAPI.info.contact.name','123',OpenAPI.info.contact.name);
+end;
+
+
+procedure TTestOpenApiReaderInfo.TestContactURL;
+
+begin
+  TestRead('{ "info" : { "contact" : { "url" : "123" } } }');
+  AssertNotNull('OpenAPI.info',OpenAPI.info);
+  AssertNotNull('OpenAPI.info.contact',OpenAPI.info.contact);
+  AssertEquals('OpenAPI.info.contact.url','123',OpenAPI.info.contact.url);
+end;
+
+
+procedure TTestOpenApiReaderInfo.TestLicenseUrl;
+
+begin
+  TestRead('{ "info" : { "license" : { "url" : "123" } } }');
+  AssertNotNull('OpenAPI.info',OpenAPI.info);
+  AssertNotNull('OpenAPI.info.license',OpenAPI.info.license);
+  AssertEquals('OpenAPI.info.license.url','123',OpenAPI.info.license.url);
+end;
+
+
+procedure TTestOpenApiReaderInfo.TestLicenseIdentifier;
+
+begin
+  TestRead('{ "info" : { "license" : { "identifier" : "123" } } }');
+  AssertNotNull('OpenAPI.info',OpenAPI.info);
+  AssertNotNull('OpenAPI.info.license',OpenAPI.info.license);
+  AssertEquals('OpenAPI.info.license.identifier','123',OpenAPI.info.license.identifier);
+end;
+
+
+procedure TTestOpenApiReaderInfo.TestLicenseName;
+
+begin
+  TestRead('{ "info" : { "license" : { "name" : "123" } } }');
+  AssertNotNull('OpenAPI.info',OpenAPI.info);
+  AssertNotNull('OpenAPI.info.license',OpenAPI.info.license);
+  AssertEquals('OpenAPI.info.license.name','123',OpenAPI.info.license.name);
+end;
+
+
+procedure TTestOpenApiReaderTags.TestName;
+
+begin
+  TestRead('{ "tags" : [ { "name" : "123" } ] }');
+end;
+
+
+procedure TTestOpenApiReaderTags.TestDescription;
+
+begin
+  TestRead('{ "tags" : [ { "description" : "123" } ] }');
+end;
+
+
+procedure TTestOpenApiReaderTags.TestExternalDocs;
+
+begin
+  TestRead('{ "tags" : [ { "externalDocs" : { "url" :"123" } } ] }');
+end;
+
+
+procedure TTestOpenApiReaderTags.Test2Tags;
+
+begin
+  TestRead('{ "tags" : [ { "name" : "123" },  { "name" : "456" } ] }');
+end;
+
+
+procedure TTestOpenApiReaderExternalDocs.TestUrl;
+
+begin
+  TestRead('{ "externalDocs" : { "url" :"123" } }');
+  AssertNotNull('OpenAPI.externalDocs',OpenAPI.externalDocs);
+  AssertEquals('OpenAPI.externalDocs.url','123',OpenAPI.externalDocs.url);
+end;
+
+
+procedure TTestOpenApiReaderExternalDocs.TestDescription;
+
+begin
+  TestRead('{ "externalDocs" : { "description" :"123" } }');
+  AssertNotNull('OpenAPI.externalDocs',OpenAPI.externalDocs);
+  AssertEquals('OpenAPI.externalDocs.description','123',OpenAPI.externalDocs.description);
+end;
+
+
+procedure TTestOpenApiReaderServers.TestUrl;
+
+begin
+  TestRead('{ "servers" : [ { "url" :"123" } ] }');
+end;
+
+
+procedure TTestOpenApiReaderServers.TestDescription;
+
+begin
+  TestRead('{ "servers" : [ { "description" :"123" } ] }');
+end;
+
+
+procedure TTestOpenApiReaderServers.TestVariablesDefault;
+
+begin
+  TestRead('{ "servers" : [ { "variables" : { "user": { "default": "123" } } } ] }');
+end;
+
+
+procedure TTestOpenApiReaderServers.TestVariablesDescription;
+
+begin
+  TestRead('{ "servers" : [ { "variables" : { "user": { "description": "123" } } } ] }');
+end;
+
+
+procedure TTestOpenApiReaderServers.TestVariablesEnum;
+
+begin
+  TestRead('{ "servers" : [ { "variables" : { "user": { "enum": [ "123", "456" ] } } } ] }');
+end;
+
+
+procedure TTestOpenApiReaderServers.Test2Url;
+
+begin
+  TestRead('{ "servers" : [ { "url" :"123" }, { "url" :"456" } ] }');
+end;
+
+
+procedure TTestOpenApiReaderPaths.TestEmpty;
+
+begin
+  TestRead('{ "paths" : { "api" : {} } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.paths['api']);
+end;
+
+
+procedure TTestOpenApiReaderPaths.TestRef;
+
+begin
+  TestRead('{ "paths" : { "api" : { "$ref": "abc"} } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.paths['api']);
+  AssertEquals('OpenAPI.paths.api.$ref','abc',OpenAPI.Paths['api'].ref);
+end;
+
+
+procedure TTestOpenApiReaderPaths.TestSummary;
+
+begin
+  TestRead('{ "paths" : { "api" : { "summary": "abc"} } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertEquals('OpenAPI.paths.api.summary','abc',OpenAPI.Paths['api'].summary);
+end;
+
+
+procedure TTestOpenApiReaderPaths.TestDescription;
+
+begin
+  TestRead('{ "paths" : { "api" : { "description": "abc"} } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertEquals('OpenAPI.paths.api.description','abc',OpenAPI.Paths['api'].description);
+end;
+
+
+procedure TTestOpenApiReaderPaths.TestGetEmpty;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get": { } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+end;
+
+
+procedure TTestOpenApiReaderPaths.TestGetSummary;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get": { "summary" : "123" } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertEquals('OpenAPI.paths.api.get.summary','123',OpenAPI.Paths['api'].get.summary);
+end;
+
+
+procedure TTestOpenApiReaderPaths.TestGetDescription;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get": { "description" : "123" } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertEquals('OpenAPI.paths.api.get.description','123',OpenAPI.Paths['api'].get.description);
+end;
+
+
+procedure TTestOpenApiReaderPaths.TestGetOperationId;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get": { "operationId" : "123" } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertEquals('OpenAPI.paths.api.get.operationId','123',OpenAPI.Paths['api'].get.operationId);
+end;
+
+
+procedure TTestOpenApiReaderPaths.TestGetDeprecated;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get": { "deprecated" : true } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertEquals('OpenAPI.paths.api.get.deprecated',True,OpenAPI.Paths['api'].get.deprecated);
+end;
+
+
+procedure TTestOpenApiReaderPaths.TestGetExternalDocsEmpty;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get": { "externalDocs" : {  } } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.externalDocs',OpenAPI.Paths['api'].get.externalDocs);
+end;
+
+
+procedure TTestOpenApiReaderPaths.TestGetExternalDocsURL;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get": { "externalDocs" : { "url" : "123" } } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.externalDocs',OpenAPI.Paths['api'].get.externalDocs);
+  AssertEquals('OpenAPI.paths.api.get.externalDocs.url','123',OpenAPI.Paths['api'].get.externalDocs.url);
+end;
+
+
+procedure TTestOpenApiReaderPaths.TestGetServers;
+
+begin
+  TestRead('{ "paths" : { "api" : { "servers": [ {} ] } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.servers[0]',OpenAPI.Paths['api'].servers[0]);
+end;
+
+
+procedure TTestOpenApiReaderPathRequestBody.TestEmpty;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get": { "requestBody" : {  } } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody',OpenAPI.Paths['api'].get.requestBody);
+end;
+
+
+procedure TTestOpenApiReaderPathRequestBody.TestDescription;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get": { "requestBody" : { "description" : "123" } } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody',OpenAPI.Paths['api'].get.requestBody);
+  AssertEquals('OpenAPI.paths.api.get.requestBody.description','123',OpenAPI.Paths['api'].get.requestBody.description);
+end;
+
+
+procedure TTestOpenApiReaderPathRequestBody.TestRequired;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get": { "requestBody" : { "required" : true} } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody',OpenAPI.Paths['api'].get.requestBody);
+  AssertEquals('OpenAPI.paths.api.get.requestBody.required',True,OpenAPI.Paths['api'].get.requestBody.required);
+end;
+
+
+procedure TTestOpenApiReaderPathRequestBody.TestContent;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get": { "requestBody" : { "content" : { "123" : { } } } } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody',OpenAPI.Paths['api'].get.requestBody);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content',OpenAPI.Paths['api'].get.requestBody.content);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content.123',OpenAPI.Paths['api'].get.requestBody.content['123']);
+end;
+
+
+procedure TTestOpenApiReaderPathRequestBody.TestContentSchema;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get": { "requestBody" : { "content" : { "123" : { "schema" : true } } } } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody',OpenAPI.Paths['api'].get.requestBody);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content',OpenAPI.Paths['api'].get.requestBody.content);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content.123',OpenAPI.Paths['api'].get.requestBody.content['123']);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content.123.schema',OpenAPI.Paths['api'].get.requestBody.content['123'].schema);
+end;
+
+
+procedure TTestOpenApiReaderPathRequestBody.TestContentExample;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get": { "requestBody" : { "content" : { "123" : { "example" : { } } } } } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody',OpenAPI.Paths['api'].get.requestBody);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content',OpenAPI.Paths['api'].get.requestBody.content);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content.123',OpenAPI.Paths['api'].get.requestBody.content['123']);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content.123.example',OpenAPI.Paths['api'].get.requestBody.content['123'].example);
+end;
+
+
+procedure TTestOpenApiReaderPathRequestBody.TestContentExamples;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get": { "requestBody" : { "content" : { "123" : { "examples" : { "abc" : { "summary": "x"} } } } } } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody',OpenAPI.Paths['api'].get.requestBody);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content',OpenAPI.Paths['api'].get.requestBody.content);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content.123',OpenAPI.Paths['api'].get.requestBody.content['123']);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content.123.examples',OpenAPI.Paths['api'].get.requestBody.content['123'].examples);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content.123.examples.abc',OpenAPI.Paths['api'].get.requestBody.content['123'].examples['abc']);
+  AssertEquals('OpenAPI.paths.api.get.requestBody.content.123.examples.abc.summary','x',OpenAPI.Paths['api'].get.requestBody.content['123'].examples['abc'].summary);
+end;
+
+
+procedure TTestOpenApiReaderPathRequestBody.TestContentEncodingContentType;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get": { "requestBody" : { "content" : { "123" : { "encoding" : { "abc" : { "contentType": "def"} } } } } } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody',OpenAPI.Paths['api'].get.requestBody);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content',OpenAPI.Paths['api'].get.requestBody.content);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content.[123]',OpenAPI.Paths['api'].get.requestBody.content['123']);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content.123.encoding',OpenAPI.Paths['api'].get.requestBody.content['123'].encoding);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content.123.encoding.abc',OpenAPI.Paths['api'].get.requestBody.content['123'].encoding['abc']);
+  AssertEquals('OpenAPI.paths.api.get.requestBody.content.123.encoding.abc.contentType','def',OpenAPI.Paths['api'].get.requestBody.content['123'].encoding['abc'].contentType);
+end;
+
+
+procedure TTestOpenApiReaderPathRequestBody.TestContentEncodingExplode;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get": { "requestBody" : { "content" : { "123" : { "encoding" : { "abc" : { "explode": true} } } } } } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody',OpenAPI.Paths['api'].get.requestBody);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content',OpenAPI.Paths['api'].get.requestBody.content);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content.123',OpenAPI.Paths['api'].get.requestBody.content['123']);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content.123.encoding',OpenAPI.Paths['api'].get.requestBody.content['123'].encoding);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content.123.encoding.abc',OpenAPI.Paths['api'].get.requestBody.content['123'].encoding['abc']);
+  AssertEquals('OpenAPI.paths.api.get.requestBody.content.123.encoding.abc.explode',True,OpenAPI.Paths['api'].get.requestBody.content['123'].encoding['abc'].explode);
+end;
+
+
+procedure TTestOpenApiReaderPathRequestBody.TestContentEncodingStyle;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get": { "requestBody" : { "content" : { "123" : { "encoding" : { "abc" : { "style": "def"} } } } } } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody',OpenAPI.Paths['api'].get.requestBody);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content',OpenAPI.Paths['api'].get.requestBody.content);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content.123',OpenAPI.Paths['api'].get.requestBody.content['123']);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content.123.encoding',OpenAPI.Paths['api'].get.requestBody.content['123'].encoding);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content.123.encoding.abc',OpenAPI.Paths['api'].get.requestBody.content['123'].encoding['abc']);
+  AssertEquals('OpenAPI.paths.api.get.requestBody.content.123.encoding.abc.style','def',OpenAPI.Paths['api'].get.requestBody.content['123'].encoding['abc'].style);
+end;
+
+
+procedure TTestOpenApiReaderPathRequestBody.TestContentEncodingAllowReserved;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get": { "requestBody" : { "content" : { "123" : { "encoding" : { "abc" : { "allowReserved": true} } } } } } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody',OpenAPI.Paths['api'].get.requestBody);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content',OpenAPI.Paths['api'].get.requestBody.content);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content.123',OpenAPI.Paths['api'].get.requestBody.content['123']);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content.123.encoding',OpenAPI.Paths['api'].get.requestBody.content['123'].encoding);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content.123.encoding.abc',OpenAPI.Paths['api'].get.requestBody.content['123'].encoding['abc']);
+  AssertEquals('OpenAPI.paths.api.get.requestBody.content.123.encoding.abc.allowReserved',True,OpenAPI.Paths['api'].get.requestBody.content['123'].encoding['abc'].allowReserved);
+end;
+
+
+procedure TTestOpenApiReaderPathRequestBody.TestContentEncodingHeaders;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get": { "requestBody" : { "content" : { "123" : { "encoding" : { "abc" : { "headers": { "def" : { "explode" : true } } } } } } } } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody',OpenAPI.Paths['api'].get.requestBody);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content',OpenAPI.Paths['api'].get.requestBody.content);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content.123',OpenAPI.Paths['api'].get.requestBody.content['123']);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content.123.encoding',OpenAPI.Paths['api'].get.requestBody.content['123'].encoding);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content.123.encoding.abc',OpenAPI.Paths['api'].get.requestBody.content['123'].encoding['abc']);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content.123.encoding.abc.headers',OpenAPI.Paths['api'].get.requestBody.content['123'].encoding['abc'].headers);
+  AssertNotNull('OpenAPI.paths.api.get.requestBody.content.123.encoding.abc.headers.def',OpenAPI.Paths['api'].get.requestBody.content['123'].encoding['abc'].headers['def']);
+  AssertEquals('OpenAPI.paths.api.get.requestBody.content.123.encoding.abc.headers.def.explode',True,OpenAPI.Paths['api'].get.requestBody.content['123'].encoding['abc'].headers['def'].explode);
+end;
+
+
+procedure TTestOpenApiReaderPathParameters.TestGetParametersEmpty;
+
+begin
+  TestRead('{ "paths" : { "api" : { "parameters": [ {} ] } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.parameters[0]',OpenAPI.Paths['api'].parameters[0]);
+end;
+
+
+procedure TTestOpenApiReaderPathResponses.TestEmpty;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get" : { "responses": { "default" : {} } } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.responses',OpenAPI.Paths['api'].get.responses);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default',OpenAPI.Paths['api'].get.responses['default']);
+end;
+
+
+procedure TTestOpenApiReaderPathResponses.TestHeaders;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get" : { "responses": { "default" : { "headers" : { "x-content" : { } } } } } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.responses',OpenAPI.Paths['api'].get.responses);
+  AssertNotNull('OpenAPI.paths.api.get.responses[default]',OpenAPI.Paths['api'].get.responses['default']);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default.headers',OpenAPI.Paths['api'].get.responses['default'].headers);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default.headers.x-content',OpenAPI.Paths['api'].get.responses['default'].headers['x-content']);
+end;
+
+
+procedure TTestOpenApiReaderPathResponses.TestDescription;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get" : { "responses": { "default" : { "description" : "abc" } } } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.responses',OpenAPI.Paths['api'].get.responses);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default',OpenAPI.Paths['api'].get.responses['default']);
+  AssertEquals('OpenAPI.paths.api.get.responses.default.description','abc',OpenAPI.Paths['api'].get.responses['default'].description);
+end;
+
+
+procedure TTestOpenApiReaderPathResponses.TestContentEmpty;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get" : { "responses": { "default" : { "content" : { "application/json" : { } } } } } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.responses',OpenAPI.Paths['api'].get.responses);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default',OpenAPI.Paths['api'].get.responses['default']);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default.content',OpenAPI.Paths['api'].get.responses['default'].content);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default.content.application/json',OpenAPI.Paths['api'].get.responses['default'].content['application/json']);
+end;
+
+
+procedure TTestOpenApiReaderPathResponses.TestContentSchema;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get" : { "responses": { "default" : { "content" : { "application/json" : { "schema" : true } } } } } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.responses',OpenAPI.Paths['api'].get.responses);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default',OpenAPI.Paths['api'].get.responses['default']);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default.content',OpenAPI.Paths['api'].get.responses['default'].content);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default.content.application/json',OpenAPI.Paths['api'].get.responses['default'].content['application/json']);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default.content.application/json.schema',OpenAPI.Paths['api'].get.responses['default'].content['application/json'].schema);
+end;
+
+
+procedure TTestOpenApiReaderPathResponses.TestContentExample;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get" : { "responses": { "default" : { "content" : { "application/json" : { "example" : {} } } } } } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.responses',OpenAPI.Paths['api'].get.responses);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default',OpenAPI.Paths['api'].get.responses['default']);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default.content',OpenAPI.Paths['api'].get.responses['default'].content);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default.content.application/json',OpenAPI.Paths['api'].get.responses['default'].content['application/json']);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default.content.application/json.example',OpenAPI.Paths['api'].get.responses['default'].content['application/json'].example);
+end;
+
+
+procedure TTestOpenApiReaderPathResponses.TestContentExamples;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get" : { "responses": { "default" : { "content" : { "application/json" : { "examples" : { "abc" : { "summary": "x"} } } } } } } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.responses',OpenAPI.Paths['api'].get.responses);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default',OpenAPI.Paths['api'].get.responses['default']);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default.content',OpenAPI.Paths['api'].get.responses['default'].content);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default.content.application/json',OpenAPI.Paths['api'].get.responses['default'].content['application/json']);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default.content.application/json.examples',OpenAPI.Paths['api'].get.responses['default'].content['application/json'].examples);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default.content.application/json.examples.abc',OpenAPI.Paths['api'].get.responses['default'].content['application/json'].examples['abc']);
+  AssertEquals('OpenAPI.paths.api.get.responses.default.content.application/json.examples.abc.summary','x',OpenAPI.Paths['api'].get.responses['default'].content['application/json'].examples['abc'].summary);
+end;
+
+
+procedure TTestOpenApiReaderPathResponses.TestContentEncodingEmpty;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get" : { "responses": { "default" : { "content" : { "application/json" : { "encoding" : { "abc" : { } } } } } } } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.responses',OpenAPI.Paths['api'].get.responses);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default',OpenAPI.Paths['api'].get.responses['default']);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default.content',OpenAPI.Paths['api'].get.responses['default'].content);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default.content.application/json',OpenAPI.Paths['api'].get.responses['default'].content['application/json']);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default.content.application/json.encoding',OpenAPI.Paths['api'].get.responses['default'].content['application/json'].encoding);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default.content.application/json.encoding.abc',OpenAPI.Paths['api'].get.responses['default'].content['application/json'].encoding['abc']);
+end;
+
+
+procedure TTestOpenApiReaderPathResponses.TestContentEncodingContentType;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get" : { "responses": { "default" : { "content" : { "application/json" : { "encoding" : { "abc" : { "contentType" : "application/json" } } } } } } } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.responses',OpenAPI.Paths['api'].get.responses);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default',OpenAPI.Paths['api'].get.responses['default']);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default.content',OpenAPI.Paths['api'].get.responses['default'].content);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default.content.application/json',OpenAPI.Paths['api'].get.responses['default'].content['application/json']);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default.content.application/json.encoding',OpenAPI.Paths['api'].get.responses['default'].content['application/json'].encoding);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default.content.application/json.encoding.abc',OpenAPI.Paths['api'].get.responses['default'].content['application/json'].encoding['abc']);
+  AssertEquals('OpenAPI.paths.api.get.responses.default.content.application/json.encoding.abc.contentType','application/json',OpenAPI.Paths['api'].get.responses['default'].content['application/json'].encoding['abc'].contentType);
+end;
+
+
+procedure TTestOpenApiReaderPathSecurity.TestEmpty;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get" : { "security" : [ {} ] } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.security[0]',OpenAPI.Paths['api'].get.security[0]);
+end;
+
+
+procedure TTestOpenApiReaderPathSecurity.TestAPIKey;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get" : { "security" : [ { "api_key" : ["akey"] } ] } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.security[0]',OpenAPI.Paths['api'].get.security[0]);
+  AssertEquals('OpenAPI.paths.api.get.security[0].api_key[0]','akey',OpenAPI.Paths['api'].get.security[0].Requirements['api_key'].Strings[0]);
+end;
+
+
+procedure TTestOpenApiReaderPathResponsesLinks.TestEmpty;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get" : { "responses" : { "default" : { "links": { "abc" : { } } } } } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.responses',OpenAPI.Paths['api'].get.responses);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default',OpenAPI.Paths['api'].get.responses['default']);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default.links',OpenAPI.Paths['api'].get.responses['default'].links);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default.links.abc',OpenAPI.Paths['api'].get.responses['default'].links['abc']);
+end;
+
+
+procedure TTestOpenApiReaderPathResponsesLinks.TestOperatonRef;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get" : { "responses" : { "default" : { "links": { "abc" : { "operationRef" : "123" } } } } } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.responses',OpenAPI.Paths['api'].get.responses);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default',OpenAPI.Paths['api'].get.responses['default']);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default.links',OpenAPI.Paths['api'].get.responses['default'].links);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default.links.abc',OpenAPI.Paths['api'].get.responses['default'].links['abc']);
+  AssertEquals('OpenAPI.paths.api.get.responses.default.links.abc.operationRef','123',OpenAPI.Paths['api'].get.responses['default'].links['abc'].operationRef);
+end;
+
+
+procedure TTestOpenApiReaderPathResponsesLinks.TestOperatonId;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get" : { "responses" : { "default" : { "links": { "abc" : { "operationId" : "123" } } } } } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.responses',OpenAPI.Paths['api'].get.responses);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default',OpenAPI.Paths['api'].get.responses['default']);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default.links',OpenAPI.Paths['api'].get.responses['default'].links);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default.links.abc',OpenAPI.Paths['api'].get.responses['default'].links['abc']);
+  AssertEquals('OpenAPI.paths.api.get.responses.default.links.abc.operationId','123',OpenAPI.Paths['api'].get.responses['default'].links['abc'].operationId);
+end;
+
+
+procedure TTestOpenApiReaderPathResponsesLinks.TestParameters;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get" : { "responses" : { "default" : { "links": { "abc" : { "parameters" : { "x" : "y" } } } } } } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.responses',OpenAPI.Paths['api'].get.responses);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default',OpenAPI.Paths['api'].get.responses['default']);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default.links',OpenAPI.Paths['api'].get.responses['default'].links);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default.links.abc',OpenAPI.Paths['api'].get.responses['default'].links['abc']);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default.links.abc.parameters',OpenAPI.Paths['api'].get.responses['default'].links['abc'].parameters);
+  AssertEquals('OpenAPI.paths.api.get.responses.default.links.abc.parameters.x','y',OpenAPI.Paths['api'].get.responses['default'].links['abc'].parameters['x'].AsString);
+end;
+
+
+procedure TTestOpenApiReaderPathResponsesLinks.TestRequestBody;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get" : { "responses" : { "default" : { "links": { "abc" : { "requestBody" : {} } } } } } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.responses',OpenAPI.Paths['api'].get.responses);
+  AssertNotNull('OpenAPI.paths.api.get.responses.default',OpenAPI.Paths['api'].get.responses['default']);
+  AssertNotNull('OpenAPI.paths.api.get.responses[default].links',OpenAPI.Paths['api'].get.responses['default'].links);
+  AssertNotNull('OpenAPI.paths.api.get.responses[default].links.abc',OpenAPI.Paths['api'].get.responses['default'].links['abc']);
+  AssertNotNull('OpenAPI.paths.api.get.responses[default].links.abc.requestBody',OpenAPI.Paths['api'].get.responses['default'].links['abc'].requestBody);
+end;
+
+
+procedure TTestOpenApiReaderPathResponsesLinks.TestDescription;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get" : { "responses" : { "default" : { "links": { "abc" : { "description" : "123" } } } } } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.responses',OpenAPI.Paths['api'].get.responses);
+  AssertNotNull('OpenAPI.paths.api.get.responses[default]',OpenAPI.Paths['api'].get.responses['default']);
+  AssertNotNull('OpenAPI.paths.api.get.responses[default].links',OpenAPI.Paths['api'].get.responses['default'].links);
+  AssertNotNull('OpenAPI.paths.api.get.responses[default].links.abc',OpenAPI.Paths['api'].get.responses['default'].links['abc']);
+  AssertEquals('OpenAPI.paths.api.get.responses[default].links.abc.description','123',OpenAPI.Paths['api'].get.responses['default'].links['abc'].description);
+end;
+
+
+procedure TTestOpenApiReaderPathResponsesLinks.TestServer;
+
+begin
+  TestRead('{ "paths" : { "api" : { "get" : { "responses" : { "default" : { "links": { "abc" : { "server" : { "url" : "123" } } } } } } } } }');
+  AssertNotNull('OpenAPI.paths',OpenAPI.paths);
+  AssertNotNull('OpenAPI.paths.api',OpenAPI.Paths['api']);
+  AssertNotNull('OpenAPI.paths.api.get',OpenAPI.Paths['api'].get);
+  AssertNotNull('OpenAPI.paths.api.get.responses',OpenAPI.Paths['api'].get.responses);
+  AssertNotNull('OpenAPI.paths.api.get.responses[default]',OpenAPI.Paths['api'].get.responses['default']);
+  AssertNotNull('OpenAPI.paths.api.get.responses[default].links',OpenAPI.Paths['api'].get.responses['default'].links);
+  AssertNotNull('OpenAPI.paths.api.get.responses[default].links.abc',OpenAPI.Paths['api'].get.responses['default'].links['abc']);
+  AssertNotNull('OpenAPI.paths.api.get.responses[default].links.abc.server',OpenAPI.Paths['api'].get.responses['default'].links['abc'].server);
+  AssertEquals('OpenAPI.paths.api.get.responses[default].links.abc.server.url','123',OpenAPI.Paths['api'].get.responses['default'].links['abc'].server.url);
+end;
+
+
+procedure TTestOpenApiReaderWebHooks.TestEmpty;
+
+begin
+  TestRead('{ "webhooks" : { "newitem" : { } } }');
+  AssertNotNull('OpenAPI.webhooks',OpenAPI.webhooks);
+  AssertNotNull('OpenAPI.webhooks.newitem',OpenAPI.webhooks['newitem']);
+end;
+
+
+procedure TTestOpenApiReaderWebHooks.TestSummary;
+
+begin
+  TestRead('{ "webhooks" : { "newitem" : { "summary" : "abc" } } }');
+  AssertNotNull('OpenAPI.webhooks',OpenAPI.webhooks);
+  AssertNotNull('OpenAPI.webhooks.newitem',OpenAPI.webhooks['newitem']);
+  AssertEquals('OpenAPI.webhooks.newitem.summary','abc',OpenAPI.webhooks['newitem'].summary);
+end;
+
+
+procedure TTestOpenApiReaderComponents.TestSchemaEmpty;
+
+begin
+  TestRead('{ "components" : { "schemas" : { "abc" : true } } }');
+  AssertNotNull('OpenAPI.components',OpenAPI.components);
+  AssertNotNull('OpenAPI.components.schemas',OpenAPI.components.schemas);
+  AssertNotNUll('OpenAPI.components.schemas.abc',OpenAPI.components.schemas['abc']);
+end;
+
+
+procedure TTestOpenApiReaderComponents.TestSchemaContentEncoding;
+
+begin
+  TestRead('{ "components" : { "schemas" : { "abc" : { "contentEncoding" : "utf8" } } } }');
+  AssertNotNull('OpenAPI.components',OpenAPI.components);
+  AssertNotNull('OpenAPI.components.schemas',OpenAPI.components.schemas);
+  AssertNotNull('OpenAPI.components.schemas.abc',OpenAPI.components.schemas['abc']);
+  AssertEquals('OpenAPI.components.schemas.abc.contentEncoding','utf8',OpenAPI.components.schemas['abc'].Validations.contentEncoding);
+end;
+
+
+procedure TTestOpenApiReaderSecurity.TestOne;
+
+begin
+  TestRead('{ "security" : [ { "abc" : [] } ] }');
+end;
+
+
+initialization
+  registertests('Reader',[
+    TTestOpenApiReaderLarge,
+    TTestopenApiReaderOpenAPI,
+    TTestopenApiReaderInfo,
+    TTestopenApiReaderTags,
+    TTestOpenApiReaderExternalDocs,
+    TTestOpenApiReaderServers,
+    TTestOpenApiReaderPaths,
+    TTestOpenApiReaderPathRequestBody,
+    TTestOpenApiReaderPathParameters,
+    TTestOpenApiReaderPathResponses,
+    TTestOpenApiReaderPathSecurity,
+    TTestOpenApiReaderPathResponsesLinks,
+    TTestOpenApiReaderWebHooks,
+    TTestOpenApiReaderComponents,
+    TTestOpenApiReaderSecurity
+  ]);
+
+end.
+

+ 1 - 0
packages/fpmake_add.inc

@@ -160,5 +160,6 @@
   add_wasm_utils(ADirectory+IncludeTrailingPathDelimiter('wasm-utils'));
   add_wasm_oi(ADirectory+IncludeTrailingPathDelimiter('wasm-oi'));
   add_fcl_jsonschema(ADirectory+IncludeTrailingPathDelimiter('fcl-jsonschema'));
+  add_fcl_openapi(ADirectory+IncludeTrailingPathDelimiter('fcl-openapi'));
   add_ptckvm(ADirectory+IncludeTrailingPathDelimiter('ptckvm'));
   add_fcl_fpterm(ADirectory+IncludeTrailingPathDelimiter('fcl-fpterm'));

+ 6 - 0
packages/fpmake_proc.inc

@@ -906,6 +906,12 @@ begin
 {$include fcl-jsonschema/fpmake.pp}
 end;
 
+procedure add_fcl_openapi(const ADirectory: string);
+begin
+  with Installer do
+{$include fcl-openapi/fpmake.pp}
+end;
+
 procedure add_ptckvm(const ADirectory: string);
 begin
   with Installer do