unit XData.OpenApi.Service;

interface

uses
  System.Classes,
  XData.OpenApi.Builder,
  XData.Service.Common;

type
  [ServiceContract]
  [URIPathSegment('openapi')]
  IOpenApiService = interface(IInvokable)
  ['{E2337352-5139-45CB-8567-770CC41B73BE}']
    [HttpGet, URIPathSegment('swagger.json')]
    function SwaggerDocument(
      [XDefault(False)] ExcludeEntities: Boolean = False;
      [XDefault(False)] ExcludeOperations: Boolean = False): TStream;
  end;

  [ServiceImplementation]
  TOpenApiService = class(TInterfacedObject, IOpenApiService)
  public
    function SwaggerDocument(
      ExcludeEntities: Boolean = False;
      ExcludeOperations: Boolean = False): TStream;
  end;

procedure RegisterOpenApiService;

implementation

uses
  Bcl.Json.Writer,
  OpenAPI.Document,
  OpenAPI.Json.Serializer,
  XData.Consts,
  XData.Aurelius.Model,
  XData.Server.Module;

procedure RegisterOpenApiService;
begin
  RegisterServiceType(TOpenApiService);
end;

{ TOpenApiService }

function TOpenApiService.SwaggerDocument(
  ExcludeEntities: Boolean = False;
  ExcludeOperations: Boolean = False): TStream;
var
  Doc: TOpenApiDocument;
  Builder: TOpenApiBuilder;
  Writer: TJsonWriter;
  Serializer: TSerializer;
  XModel: TXDataAureliusModel;
begin
  Doc := nil;
  Writer := nil;
  Serializer := nil;
  XModel := TXDataOperationContext.Current.Handler.XModel;
  Builder := TOpenApiBuilder.Create(XModel);
  try
    // Set build parameters
    Builder.ExcludeOperations := ExcludeOperations;
    Builder.ExcludeEntities := ExcludeEntities;

    // Now build
    Doc := Builder.GetDocument;

    Doc.Info.Title := XModel.Title;
    Doc.Info.Version := XModel.Version;

    Doc.Host := TXDataOperationContext.Current.Request.Uri.Authority;
    Doc.BasePath := TXDataOperationContext.Current.Handler.XModule.BaseUri.Path;
    Doc.Paths.Sort;

    TXDataOperationContext.Current.Response.ContentType := JsonMediaType;

    Result := TMemoryStream.Create;
    try
      Writer := TJsonWriter.Create(Result);
      Serializer := TSerializer.Create;
      Serializer.Write(Doc, Writer);
    except
      Result.Free;
      raise;
    end;
  finally
    Serializer.Free;
    Writer.Free;
    Doc.Free;
    Builder.Free;
  end;
end;

end.
