unit OpenAPI.Document;

interface

uses
  Classes, Generics.Collections,
  XData.JSchema.Classes,
  OpenAPI.Classes,
  OpenAPI.Classes.Info,
  OpenAPI.Classes.Parameter,
  OpenAPI.Classes.Path,
  OpenAPI.Classes.Security,
  OpenAPI.Json.Attributes,
  OpenAPI.Types;

type
  TDefinitions = TJsonSchemaDefinitions;

  // This is the root document object for the API specification.
  [OAJsonInclusion, OAJsonNaming]
  TDocument = class
  strict private
    FSwagger: string;
    FInfo: TInfo;
    FHost: string;
    FBasePath: string;
    FTags: TTags;
    FSchemes: TProtocols;
    FConsumes: TMimeTypes;
    FProduces: TMimeTypes;
    FPaths: TPaths;
    FSecurityDefinitions: TSecurityDefinitions;
    FDefinitions: TDefinitions;
    FParameters: TList<TParameter>;
    FResponses: TResponses;
    FSecurity: TList<TSecurityRequirement>;
    FExternalDocs: TExternalDoc;
    function GetExternalDocs: TExternalDoc;
    function GetConsumes: TMimeTypes;
    function GetProduces: TMimeTypes;
    function GetSecurityDefinitions: TSecurityDefinitions;
    function GetSecurity: TList<TSecurityRequirement>;
    function GetDefinitions: TDefinitions;
    function GetTags: TTags;
  public
    constructor Create;
    destructor Destroy; override;
    function AddTag(const Name: string; const Description: string = ''): TTag;
    function AddPath(const RelativePath: string): TPathItem;
    // Required. The value MUST be "2.0".
    property Swagger: string read FSwagger write FSwagger;
    // Required. Provides metadata about the API.
    property Info: TInfo read FInfo;
    // The host (name or ip) serving the API.
    // This MUST be the host only and does not include the scheme nor sub-paths. It MAY include a port.
    property Host: string read FHost write FHost;
    // The base path on which the API is served, which is relative to the host.
    // If it is not included, the API is served directly under the host. The value MUST start with a leading slash (/).
    property BasePath: string read FBasePath write FBasePath;
    // The transfer protocol of the API. Values MUST be from the list: "http", "https", "ws", "wss".
    property Schemes: TProtocols read FSchemes write FSchemes;
    // A list of MIME types the APIs can consume.
    property Consumes: TMimeTypes read GetConsumes;
    // A list of MIME types the APIs can produce.
    property Produces: TMimeTypes read GetProduces;
    // Required. The available paths and operations for the API.
    property Paths: TPaths read FPaths;
    // An object to hold data types produced and consumed by operations.
    property Definitions: TDefinitions read GetDefinitions;
    // An object to hold parameters that can be used across operations.
    property Parameters: TList<TParameter> read FParameters write FParameters;
    // An object to hold responses that can be used across operations.
    property Responses: TResponses read FResponses write FResponses;
    // Security scheme definitions that can be used across the specification.
    property SecurityDefinitions: TSecurityDefinitions read GetSecurityDefinitions;
    // A declaration of which security schemes are applied for the API as a whole.
    // The list of values describes alternative security schemes that can be used (that is, there is a logical OR between the security requirements).
    property Security: TList<TSecurityRequirement> read GetSecurity;
    // A list of tags used by the specification with additional metadata.
    property Tags: TTags read GetTags;
    // Additional external documentation.
    property ExternalDocs: TExternalDoc read GetExternalDocs write FExternalDocs;
  end;

  TOpenAPIDocument = TDocument;

implementation

uses
  OpenAPI.Consts;

{ TDocument }

function TDocument.AddPath(const RelativePath: string): TPathItem;
begin
  if not Paths.TryGetValue(RelativePath, Result) then
  begin
    result := TPathItem.Create;
    Paths.Add(RelativePath, result);
  end;
end;

function TDocument.AddTag(const Name, Description: string): TTag;
begin
  Result := Tags.Find(Name);
  if Result = nil then
  begin
    Result := TTag.Create;
    Tags.Add(Result);
    Result.Name := Name;
  end;
  Result.Description := Description;
end;

constructor TDocument.Create;
begin
  FSwagger := TOpenAPIConsts.Swagger;
  FInfo := TInfo.Create;
  FPaths := TPaths.Create;
end;

destructor TDocument.Destroy;
begin
  FInfo.Free;
  FPaths.Free;
  FDefinitions.Free;
  FTags.Free;
  FExternalDocs.Free;
  FConsumes.Free;
  FProduces.Free;
  FSecurityDefinitions.Free;
  FSecurity.Free;
  inherited;
end;

function TDocument.GetConsumes: TMimeTypes;
begin
  result := TMimeTypes.Return(FConsumes);
end;

function TDocument.GetDefinitions: TDefinitions;
begin
  if FDefinitions = nil then
    FDefinitions := TDefinitions.Create;
  result := FDefinitions;
end;

function TDocument.GetExternalDocs: TExternalDoc;
begin
  if FExternalDocs = nil then
    FExternalDocs := TExternalDoc.Create;
  result := FExternalDocs;
end;

function TDocument.GetProduces: TMimeTypes;
begin
  result := TMimeTypes.Return(FProduces);
end;

function TDocument.GetSecurity: TList<TSecurityRequirement>;
begin
  if FSecurity = nil then
    FSecurity := TObjectList<TSecurityRequirement>.Create;
  Result := FSecurity;
end;

function TDocument.GetSecurityDefinitions: TSecurityDefinitions;
begin
  if FSecurityDefinitions = nil then
    FSecurityDefinitions := TSecurityDefinitions.Create;
  result := FSecurityDefinitions;
end;

function TDocument.GetTags: TTags;
begin
  if FTags = nil then
    FTags := TTags.Create;
  result := FTags;
end;

end.

