mirror of
https://github.com/danieleteti/delphimvcframework.git
synced 2024-11-15 15:55:54 +01:00
Merge remote-tracking branch 'joaoduarte1/middlewareswagger_dev' into SwagDoc
This commit is contained in:
commit
e83f025b09
@ -134,12 +134,6 @@ resourcestring
|
||||
' end;' + sLineBreak +
|
||||
'end;' + sLineBreak +
|
||||
sLineBreak +
|
||||
'class procedure TDMVCParseAuthentication.OnParseAuthentication(AContext: TIdContext; const AAuthType, AAuthData: String;' + sLineBreak +
|
||||
' var VUsername, VPassword: String; var VHandled: Boolean);' + sLineBreak +
|
||||
'begin' + sLineBreak +
|
||||
' VHandled := SameText(LowerCase(AAuthType), ''bearer'');' + sLineBreak +
|
||||
'end;' + sLineBreak +
|
||||
sLineBreak +
|
||||
'begin' + sLineBreak +
|
||||
' ReportMemoryLeaksOnShutdown := True;' + sLineBreak +
|
||||
' IsMultiThread := True;' + sLineBreak +
|
||||
|
46
samples/swaggerdoc/AuthHandler.pas
Normal file
46
samples/swaggerdoc/AuthHandler.pas
Normal file
@ -0,0 +1,46 @@
|
||||
unit AuthHandler;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
MVCFramework,
|
||||
System.Generics.Collections,
|
||||
MVCFramework.Middleware.Authentication.RoleBasedAuthHandler;
|
||||
|
||||
type
|
||||
TAuthHandler = class(TRoleBasedAuthHandler)
|
||||
public
|
||||
procedure OnAuthentication(
|
||||
const AContext: TWebContext;
|
||||
const UserName: string;
|
||||
const Password: string;
|
||||
UserRoles: TList<string>;
|
||||
var IsValid: Boolean;
|
||||
const SessionData: TDictionary<string, string>); override;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
System.SysUtils;
|
||||
|
||||
{ TAuthHandler }
|
||||
|
||||
procedure TAuthHandler.OnAuthentication(const AContext: TWebContext; const UserName, Password: string;
|
||||
UserRoles: TList<string>; var IsValid: Boolean; const SessionData: TDictionary<string, string>);
|
||||
begin
|
||||
IsValid := UserName.Equals(Password);
|
||||
if IsValid then
|
||||
begin
|
||||
UserRoles.Add('role1');
|
||||
UserRoles.Add('role2');
|
||||
UserRoles.Add('role3');
|
||||
UserRoles.Add('role4');
|
||||
SessionData.AddOrSetValue('custom1', 'value1');
|
||||
SessionData.AddOrSetValue('custom2', 'value2');
|
||||
SessionData.AddOrSetValue('custom3', 'value3');
|
||||
SessionData.AddOrSetValue('custom4', 'value4');
|
||||
end;
|
||||
end;
|
||||
|
||||
end.
|
65
samples/swaggerdoc/MainFormU.dfm
Normal file
65
samples/swaggerdoc/MainFormU.dfm
Normal file
@ -0,0 +1,65 @@
|
||||
object Form1: TForm1
|
||||
Left = 271
|
||||
Top = 114
|
||||
Caption = 'Form1'
|
||||
ClientHeight = 235
|
||||
ClientWidth = 399
|
||||
Color = clBtnFace
|
||||
Font.Charset = DEFAULT_CHARSET
|
||||
Font.Color = clWindowText
|
||||
Font.Height = -11
|
||||
Font.Name = 'Tahoma'
|
||||
Font.Style = []
|
||||
OldCreateOrder = False
|
||||
OnCreate = FormCreate
|
||||
OnShow = FormShow
|
||||
PixelsPerInch = 96
|
||||
TextHeight = 13
|
||||
object Label1: TLabel
|
||||
Left = 24
|
||||
Top = 48
|
||||
Width = 20
|
||||
Height = 13
|
||||
Caption = 'Port'
|
||||
end
|
||||
object ButtonStart: TButton
|
||||
Left = 24
|
||||
Top = 8
|
||||
Width = 75
|
||||
Height = 25
|
||||
Caption = 'Start'
|
||||
TabOrder = 0
|
||||
OnClick = ButtonStartClick
|
||||
end
|
||||
object ButtonStop: TButton
|
||||
Left = 105
|
||||
Top = 8
|
||||
Width = 75
|
||||
Height = 25
|
||||
Caption = 'Stop'
|
||||
TabOrder = 1
|
||||
OnClick = ButtonStopClick
|
||||
end
|
||||
object EditPort: TEdit
|
||||
Left = 24
|
||||
Top = 67
|
||||
Width = 121
|
||||
Height = 21
|
||||
TabOrder = 2
|
||||
Text = '8080'
|
||||
end
|
||||
object ButtonOpenBrowser: TButton
|
||||
Left = 24
|
||||
Top = 112
|
||||
Width = 107
|
||||
Height = 25
|
||||
Caption = 'Open Browser'
|
||||
TabOrder = 3
|
||||
OnClick = ButtonOpenBrowserClick
|
||||
end
|
||||
object ApplicationEvents1: TApplicationEvents
|
||||
OnIdle = ApplicationEvents1Idle
|
||||
Left = 288
|
||||
Top = 24
|
||||
end
|
||||
end
|
110
samples/swaggerdoc/MainFormU.pas
Normal file
110
samples/swaggerdoc/MainFormU.pas
Normal file
@ -0,0 +1,110 @@
|
||||
unit MainFormU;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Winapi.Messages,
|
||||
System.SysUtils,
|
||||
System.Variants,
|
||||
System.Classes,
|
||||
Vcl.Graphics,
|
||||
Vcl.Controls,
|
||||
Vcl.Forms,
|
||||
Vcl.Dialogs,
|
||||
Vcl.AppEvnts,
|
||||
Vcl.StdCtrls,
|
||||
IdHTTPWebBrokerBridge,
|
||||
Web.HTTPApp,
|
||||
IdContext;
|
||||
|
||||
type
|
||||
TForm1 = class(TForm)
|
||||
ButtonStart: TButton;
|
||||
ButtonStop: TButton;
|
||||
EditPort: TEdit;
|
||||
Label1: TLabel;
|
||||
ApplicationEvents1: TApplicationEvents;
|
||||
ButtonOpenBrowser: TButton;
|
||||
procedure FormCreate(Sender: TObject);
|
||||
procedure ApplicationEvents1Idle(Sender: TObject; var Done: Boolean);
|
||||
procedure ButtonStartClick(Sender: TObject);
|
||||
procedure ButtonStopClick(Sender: TObject);
|
||||
procedure ButtonOpenBrowserClick(Sender: TObject);
|
||||
procedure FormShow(Sender: TObject);
|
||||
private
|
||||
FServer: TIdHTTPWebBrokerBridge;
|
||||
procedure StartServer;
|
||||
procedure OnParseAuthentication(AContext: TIdContext; const AAuthType, AAuthData: String;
|
||||
var VUsername, VPassword: String; var VHandled: Boolean);
|
||||
|
||||
{ Private declarations }
|
||||
public
|
||||
{ Public declarations }
|
||||
end;
|
||||
|
||||
var
|
||||
Form1: TForm1;
|
||||
|
||||
implementation
|
||||
|
||||
{$R *.dfm}
|
||||
|
||||
uses
|
||||
WinApi.Windows, Winapi.ShellApi;
|
||||
|
||||
procedure TForm1.ApplicationEvents1Idle(Sender: TObject; var Done: Boolean);
|
||||
begin
|
||||
ButtonStart.Enabled := not FServer.Active;
|
||||
ButtonStop.Enabled := FServer.Active;
|
||||
EditPort.Enabled := not FServer.Active;
|
||||
end;
|
||||
|
||||
procedure TForm1.ButtonOpenBrowserClick(Sender: TObject);
|
||||
var
|
||||
LURL: string;
|
||||
begin
|
||||
StartServer;
|
||||
LURL := Format('http://localhost:%s/swagger/index.html', [EditPort.Text]);
|
||||
ShellExecute(0, nil, PChar(LURL), nil, nil, SW_SHOWNOACTIVATE);
|
||||
end;
|
||||
|
||||
procedure TForm1.ButtonStartClick(Sender: TObject);
|
||||
begin
|
||||
StartServer;
|
||||
end;
|
||||
|
||||
procedure TForm1.ButtonStopClick(Sender: TObject);
|
||||
begin
|
||||
FServer.Active := False;
|
||||
FServer.Bindings.Clear;
|
||||
end;
|
||||
|
||||
procedure TForm1.FormCreate(Sender: TObject);
|
||||
begin
|
||||
FServer := TIdHTTPWebBrokerBridge.Create(Self);
|
||||
FServer.OnParseAuthentication := OnParseAuthentication;
|
||||
end;
|
||||
|
||||
procedure TForm1.FormShow(Sender: TObject);
|
||||
begin
|
||||
ButtonOpenBrowser.Click;
|
||||
end;
|
||||
|
||||
procedure TForm1.OnParseAuthentication(AContext: TIdContext; const AAuthType, AAuthData: String; var VUsername,
|
||||
VPassword: String; var VHandled: Boolean);
|
||||
begin
|
||||
if SameText(AAuthType, 'Bearer') then
|
||||
VHandled := True;
|
||||
end;
|
||||
|
||||
procedure TForm1.StartServer;
|
||||
begin
|
||||
if not FServer.Active then
|
||||
begin
|
||||
FServer.Bindings.Clear;
|
||||
FServer.DefaultPort := StrToInt(EditPort.Text);
|
||||
FServer.Active := True;
|
||||
end;
|
||||
end;
|
||||
|
||||
end.
|
69
samples/swaggerdoc/MyController1U.pas
Normal file
69
samples/swaggerdoc/MyController1U.pas
Normal file
@ -0,0 +1,69 @@
|
||||
unit MyController1U;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
MVCFramework,
|
||||
MVCFramework.Commons,
|
||||
MVCFramework.Swagger.Commons;
|
||||
|
||||
const
|
||||
INDEX_JSON_SCHEMA =
|
||||
'{' + sLineBreak +
|
||||
' "type": "object",' + sLineBreak +
|
||||
' "properties": {' + sLineBreak +
|
||||
' "application": {' + sLineBreak +
|
||||
' "type": "string",' + sLineBreak +
|
||||
' "description": "Application Name"' + sLineBreak +
|
||||
' },' + sLineBreak +
|
||||
' "online": {' + sLineBreak +
|
||||
' "type": "boolean",' + sLineBreak +
|
||||
' "description": "Defines if the server is online"' + sLineBreak +
|
||||
' },' + sLineBreak +
|
||||
' "serverdatetime": {' + sLineBreak +
|
||||
' "type": "string",' + sLineBreak +
|
||||
' "description": "Current server time"' + sLineBreak +
|
||||
' }' + sLineBreak +
|
||||
' }' + sLineBreak +
|
||||
'}';
|
||||
|
||||
type
|
||||
|
||||
[MVCPath('/status')]
|
||||
TMyController1 = class(TMVCController)
|
||||
public
|
||||
[MVCPath('')]
|
||||
[MVCSwagSummary('Status', 'API Status')]
|
||||
[MVCSwagResponses(200, 'Sucess', INDEX_JSON_SCHEMA)]
|
||||
[MVCSwagResponses(500, 'Internal Server Error')]
|
||||
[MVCProduces(TMVCMediaType.APPLICATION_JSON)]
|
||||
[MVCHTTPMethod([httpGET])]
|
||||
procedure Index;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
JsonDataObjects,
|
||||
System.SysUtils,
|
||||
System.DateUtils,
|
||||
MVCFramework.Controllers.Register;
|
||||
|
||||
{ TMyController1 }
|
||||
|
||||
procedure TMyController1.Index;
|
||||
var
|
||||
LObj: TJDOJsonObject;
|
||||
begin
|
||||
LObj := TJDOJsonObject.Create;
|
||||
LObj.S['application'] := Context.Config[TMVCConfigKey.ServerName];
|
||||
LObj.B['online'] := True;
|
||||
LObj.S['serverdatetime'] := DateToISO8601(Now);
|
||||
Render(LObj);
|
||||
end;
|
||||
|
||||
initialization
|
||||
|
||||
TControllersRegister.Instance.RegisterController(TMyController1, 'MyServerName');
|
||||
|
||||
end.
|
88
samples/swaggerdoc/MyController2U.pas
Normal file
88
samples/swaggerdoc/MyController2U.pas
Normal file
@ -0,0 +1,88 @@
|
||||
unit MyController2U;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
MVCFramework,
|
||||
MVCFramework.Commons,
|
||||
MVCFramework.Swagger.Commons,
|
||||
MVCFramework.Serializer.Commons,
|
||||
MVCFramework.Middleware.Authentication.RoleBasedAuthHandler;
|
||||
|
||||
type
|
||||
[MVCNameCase(ncLowerCase)]
|
||||
TPerson = class
|
||||
private
|
||||
FName: string;
|
||||
FAge: Integer;
|
||||
FCountry: string;
|
||||
FCode: Integer;
|
||||
public
|
||||
[MVCSwagJsonSchemaField(stInteger, 'code', 'person id', True, False)]
|
||||
property Code: Integer read FCode write FCode;
|
||||
[MVCSwagJsonSchemaField('name', 'person name', True, False)]
|
||||
property Name: string read FName write FName;
|
||||
[MVCSwagJsonSchemaField('age', 'person age', True, False)]
|
||||
property Age: Integer read FAge write FAge;
|
||||
[MVCSwagJsonSchemaField('country', 'Nationality of the person', True, False)]
|
||||
property Country: string read FCountry write FCountry;
|
||||
end;
|
||||
|
||||
[MVCPath('/person')]
|
||||
TMyController2 = class(TMVCController)
|
||||
public
|
||||
[MVCPath('/($Id)')]
|
||||
[MVCSwagSummary('Person', 'List Persons', '66e83aa7-d170-44a7-a502-8f25ddd2a18a')]
|
||||
[MVCSwagParam(plPath, 'Id', 'Person id', ptInteger)]
|
||||
[MVCSwagParam(plQuery, 'filter', 'Search filter', ptString)]
|
||||
[MVCSwagParam(plQuery, 'per_page', 'Items per page', ptInteger)]
|
||||
[MVCSwagResponses(200, 'Sucess', TPerson)]
|
||||
[MVCSwagResponses(500, 'Internal Server Error')]
|
||||
[MVCHTTPMethod([httpGET])]
|
||||
procedure GetPerson(const Id: Integer);
|
||||
|
||||
[MVCPath('')]
|
||||
[MVCSwagSummary('Person', 'Insert Person')]
|
||||
[MVCSwagParam(plBody, 'entity', 'Person object', TPerson, ptNotDefined, True)]
|
||||
[MVCSwagResponses(201, 'Created')]
|
||||
[MVCSwagResponses(401, 'Requires Authentication')]
|
||||
[MVCSwagResponses(500, 'Internal Server Error')]
|
||||
[MVCConsumes(TMVCMediaType.APPLICATION_JSON)]
|
||||
[MVCHTTPMethod([httpPOST])]
|
||||
[MVCRequiresAuthentication]
|
||||
procedure InsertPerson;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
MVCFramework.Controllers.Register;
|
||||
|
||||
{ TMyController2 }
|
||||
|
||||
procedure TMyController2.GetPerson(const Id: Integer);
|
||||
var
|
||||
LPerson: TPerson;
|
||||
begin
|
||||
LPerson := TPerson.Create;
|
||||
LPerson.Code := Id;
|
||||
LPerson.Name := 'João Antônio Duarte';
|
||||
LPerson.Age := 26;
|
||||
LPerson.Country := 'Brasil';
|
||||
Render(LPerson);
|
||||
end;
|
||||
|
||||
procedure TMyController2.InsertPerson;
|
||||
var
|
||||
LPerson: TPerson;
|
||||
begin
|
||||
LPerson := Context.Request.BodyAs<TPerson>;
|
||||
Render(LPerson);
|
||||
ResponseStatus(201, 'Created');
|
||||
end;
|
||||
|
||||
initialization
|
||||
|
||||
TControllersRegister.Instance.RegisterController(TMyController2, 'MyServerName');
|
||||
|
||||
end.
|
24
samples/swaggerdoc/SwaggerDocApi.dpr
Normal file
24
samples/swaggerdoc/SwaggerDocApi.dpr
Normal file
@ -0,0 +1,24 @@
|
||||
program SwaggerDocApi;
|
||||
{$APPTYPE GUI}
|
||||
|
||||
uses
|
||||
Vcl.Forms,
|
||||
Web.WebReq,
|
||||
IdHTTPWebBrokerBridge,
|
||||
MainFormU in 'MainFormU.pas' {Form1},
|
||||
WebModuleMainU in 'WebModuleMainU.pas' {WebModule1: TWebModule},
|
||||
MyController1U in 'MyController1U.pas',
|
||||
MyController2U in 'MyController2U.pas',
|
||||
MVCFramework.Middleware.Swagger in '..\..\sources\MVCFramework.Middleware.Swagger.pas',
|
||||
MVCFramework.Swagger.Commons in '..\..\sources\MVCFramework.Swagger.Commons.pas',
|
||||
AuthHandler in 'AuthHandler.pas';
|
||||
|
||||
{$R *.res}
|
||||
|
||||
begin
|
||||
if WebRequestHandler <> nil then
|
||||
WebRequestHandler.WebModuleClass := WebModuleClass;
|
||||
Application.Initialize;
|
||||
Application.CreateForm(TForm1, Form1);
|
||||
Application.Run;
|
||||
end.
|
902
samples/swaggerdoc/SwaggerDocApi.dproj
Normal file
902
samples/swaggerdoc/SwaggerDocApi.dproj
Normal file
@ -0,0 +1,902 @@
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{7E1E507C-3EB8-4893-9A31-7FFDECD802EA}</ProjectGuid>
|
||||
<ProjectVersion>18.7</ProjectVersion>
|
||||
<FrameworkType>VCL</FrameworkType>
|
||||
<MainSource>SwaggerDocApi.dpr</MainSource>
|
||||
<Base>True</Base>
|
||||
<Config Condition="'$(Config)'==''">Debug</Config>
|
||||
<Platform Condition="'$(Platform)'==''">Win32</Platform>
|
||||
<TargetedPlatforms>1</TargetedPlatforms>
|
||||
<AppType>Application</AppType>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
|
||||
<Base_Win32>true</Base_Win32>
|
||||
<CfgParent>Base</CfgParent>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
|
||||
<Base_Win64>true</Base_Win64>
|
||||
<CfgParent>Base</CfgParent>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
|
||||
<Cfg_1>true</Cfg_1>
|
||||
<CfgParent>Base</CfgParent>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''">
|
||||
<Cfg_1_Win32>true</Cfg_1_Win32>
|
||||
<CfgParent>Cfg_1</CfgParent>
|
||||
<Cfg_1>true</Cfg_1>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
|
||||
<Cfg_2>true</Cfg_2>
|
||||
<CfgParent>Base</CfgParent>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
|
||||
<Cfg_2_Win32>true</Cfg_2_Win32>
|
||||
<CfgParent>Cfg_2</CfgParent>
|
||||
<Cfg_2>true</Cfg_2>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Base)'!=''">
|
||||
<DCC_DcuOutput>.\$(Platform)\$(Config)</DCC_DcuOutput>
|
||||
<DCC_ExeOutput>.\bin</DCC_ExeOutput>
|
||||
<DCC_E>false</DCC_E>
|
||||
<DCC_N>false</DCC_N>
|
||||
<DCC_S>false</DCC_S>
|
||||
<DCC_F>false</DCC_F>
|
||||
<DCC_K>false</DCC_K>
|
||||
<DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)</DCC_Namespace>
|
||||
<Icon_MainIcon>$(BDS)\bin\delphi_PROJECTICON.ico</Icon_MainIcon>
|
||||
<Icns_MainIcns>$(BDS)\bin\delphi_PROJECTICNS.icns</Icns_MainIcns>
|
||||
<SanitizedProjectName>SwaggerDocApi</SanitizedProjectName>
|
||||
<VerInfo_Locale>1046</VerInfo_Locale>
|
||||
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Base_Win32)'!=''">
|
||||
<DCC_UsePackage>DBXSqliteDriver;dxFlowChartRS26;fmxase;DBXDb2Driver;dxPSdxMapControlLnkRS26;vclactnband;dxBarRS26;vclFireDAC;JRRestDWComponents;dxFireDACEMFRS26;tethering;dxSpreadSheetInplaceRichEditRS26;FireDACADSDriver;dxRichEditCoreRS26;dxPSdxSpreadSheetLnkRS26;FireDACMSSQLDriver;vcltouch;ACBr_NFe;vcldb;dxPSTeeChartRS26;JRTools;dxGDIPlusRS26;dxPSdxFCLnkRS26;dxPSLnksRS26;FireDACDBXDriver;PascalScript_Core_D26;cxGridRS26;dxPsPrVwAdvRS26;RESTDWDriverFD;dxPDFViewerRS26;vclx;RESTManagerDesign;dxPScxTLLnkRS26;RESTBackendComponents;VCLRESTComponents;vclie;bindengine;CloudService;dxmdsRS26;rbRCL1926;FireDACMySQLDriver;dxdborRS26;DataSnapClient;bindcompdbx;GR32_D;ACBr_TCP;DBXSybaseASEDriver;IndyIPServer;cxPivotGridRS26;IndySystem;cxTreeListdxBarPopupMenuRS26;dsnapcon;cxTreeListRS26;ACBr_synapse;VirtualTreesR;cxSchedulerRibbonStyleEventEditorRS26;dxPSCoreRS26;ecComnD26;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;dxSpreadSheetRS26;dxBarExtItemsRS26;dxPScxPivotGridLnkRS26;dxPSdxGaugeControlLnkRS26;rbIDE1926;emshosting;ACBr_BoletoRL;DBXOdbcDriver;FireDACTDataDriver;FMXTee;dxdbtrRS26;dxRichEditControlCoreRS26;soaprtl;DbxCommonDriver;dxFlowChartAdvancedCustomizeFormRS26;rbRTL1926;ACBr_NFSeDanfseRL;dxDockingRS26;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;GR32_R;cxLibraryRS26;rtl;emsserverresource;DbxClientDriver;DBXSybaseASADriver;dxPScxSchedulerLnkRS26;dxSpreadSheetConditionalFormattingDialogsRS26;appanalytics;dxRibbonCustomizationFormRS26;cxSchedulerGridRS26;IndyIPClient;bindcompvcl;dclRBE1926;TeeUI;dxADOEMFRS26;VclSmp;FireDACODBCDriver;rbADO1926;dxRibbonRS26;DataSnapIndy10ServerTransport;dxPScxCommonRS26;dxRichEditDocumentModelRS26;ACBr_Boleto;DataSnapProviderClient;FireDACMongoDBDriver;dxPScxGridLnkRS26;ACBr_NFSe;rbUSERDesign1926;dxSpreadSheetCoreRS26;DataSnapServerMidas;RESTComponents;DBXInterBaseDriver;dxPScxExtCommonRS26;rbCIDE1926;rbDAD1926;rbDB1926;emsclientfiredac;DataSnapFireDAC;rbRest1926;DBXMSSQLDriver;dxRichEditControlRS26;DatasnapConnectorsFreePascal;dxGaugeControlRS26;ACBrDFeReportRL;dxorgcRS26;dxPScxVGridLnkRS26;bindcompfmx;DBXOracleDriver;inetdb;JRFireDACComponents;ACBr_Diversos;dxBarDBNavRS26;FmxTeeUI;emsedge;FireDACIBDriver;fmx;fmxdae;dxWizardControlRS26;rbUSER1926;ZipMasterR;dxTabbedMDIRS26;dxEMFRS26;dbexpress;IndyCore;dxComnRS26;rbRIDE1926;rbDIDE1926;dsnap;DataSnapCommon;emsclient;FireDACCommon;ACBr_PCNComum;DataSnapConnectors;cxSchedulerTreeBrowserRS26;soapserver;cxPivotGridOLAPRS26;cxVerticalGridRS26;dxtrmdRS26;FireDACOracleDriver;DBXMySQLDriver;Catracas;cxSchedulerRS26;dxPSdxLCLnkRS26;DBXFirebirdDriver;rbTCUI1926;FireDACCommonODBC;FireDACCommonDriver;dxMapControlRS26;inet;dxSpellCheckerRS26;IndyIPCommon;dclRBDBE1926;dxSpreadSheetCoreConditionalFormattingDialogsRS26;vcl;ACBr_NFeDanfeRL;dxPSdxDBOCLnkRS26;SyntEditDcl26;rbRAP1926;FireDACDb2Driver;dxSpreadSheetReportDesignerRS26;ACBr_Integrador;dxPScxPCProdRS26;madExcept_;dxNavBarRS26;dxCoreRS26;madBasic_;cxExportRS26;TeeDB;FireDAC;dxHttpIndyRequestRS26;dxPSPrVwRibbonRS26;ACBr_Comum;rbTC1926;FireDACSqliteDriver;FireDACPgDriver;dxPSRichEditControlLnkRS26;FireDACASADriver;cxPivotGridChartRS26;rbBDE1926;dxPSDBTeeChartRS26;Tee;DataSnapServer;dxPSdxDBTVLnkRS26;vclwinx;FireDACDSDriver;ACBr_OpenSSL;ActiveX;madDisAsm_;dxTileControlRS26;ACBr_DFeComum;CustomIPTransport;vcldsnap;dxSkinsCoreRS26;dclRBADO1926;bindcomp;ACBr_Serial;DBXInformixDriver;dxPSdxOCLnkRS26;frce;SynEdit_R;dclRBFireDAC1926;dbxcds;adortl;RESTManager;dxSpreadSheetCoreDialogsRS26;dxBarExtDBItemsRS26;dsnapxml;rbFireDAC1926;dbrtl;inetdbxpress;IndyProtocols;dxPSdxPDFViewerLnkRS26;dxRichEditInplaceRS26;rbDBE1926;JRDatabaseTools;RestDatawareCORE;$(DCC_UsePackage)</DCC_UsePackage>
|
||||
<DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
|
||||
<BT_BuildType>Debug</BT_BuildType>
|
||||
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
|
||||
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
|
||||
<VerInfo_Locale>1033</VerInfo_Locale>
|
||||
<Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Base_Win64)'!=''">
|
||||
<DCC_UsePackage>DBXSqliteDriver;dxFlowChartRS26;fmxase;DBXDb2Driver;dxPSdxMapControlLnkRS26;vclactnband;dxBarRS26;vclFireDAC;dxFireDACEMFRS26;tethering;dxSpreadSheetInplaceRichEditRS26;FireDACADSDriver;dxRichEditCoreRS26;dxPSdxSpreadSheetLnkRS26;FireDACMSSQLDriver;vcltouch;vcldb;dxPSTeeChartRS26;dxGDIPlusRS26;dxPSdxFCLnkRS26;dxPSLnksRS26;FireDACDBXDriver;PascalScript_Core_D26;cxGridRS26;dxPsPrVwAdvRS26;RESTDWDriverFD;dxPDFViewerRS26;vclx;dxPScxTLLnkRS26;RESTBackendComponents;VCLRESTComponents;vclie;bindengine;CloudService;dxmdsRS26;FireDACMySQLDriver;dxdborRS26;DataSnapClient;bindcompdbx;DBXSybaseASEDriver;IndyIPServer;cxPivotGridRS26;IndySystem;cxTreeListdxBarPopupMenuRS26;dsnapcon;cxTreeListRS26;VirtualTreesR;cxSchedulerRibbonStyleEventEditorRS26;dxPSCoreRS26;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;dxSpreadSheetRS26;dxBarExtItemsRS26;dxPScxPivotGridLnkRS26;dxPSdxGaugeControlLnkRS26;emshosting;DBXOdbcDriver;FireDACTDataDriver;FMXTee;dxdbtrRS26;dxRichEditControlCoreRS26;soaprtl;DbxCommonDriver;dxFlowChartAdvancedCustomizeFormRS26;dxDockingRS26;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;GR32_R;cxLibraryRS26;rtl;emsserverresource;DbxClientDriver;DBXSybaseASADriver;dxPScxSchedulerLnkRS26;dxSpreadSheetConditionalFormattingDialogsRS26;appanalytics;dxRibbonCustomizationFormRS26;cxSchedulerGridRS26;IndyIPClient;bindcompvcl;TeeUI;dxADOEMFRS26;VclSmp;FireDACODBCDriver;dxRibbonRS26;DataSnapIndy10ServerTransport;dxPScxCommonRS26;dxRichEditDocumentModelRS26;DataSnapProviderClient;FireDACMongoDBDriver;dxPScxGridLnkRS26;dxSpreadSheetCoreRS26;DataSnapServerMidas;RESTComponents;DBXInterBaseDriver;dxPScxExtCommonRS26;emsclientfiredac;DataSnapFireDAC;DBXMSSQLDriver;dxRichEditControlRS26;DatasnapConnectorsFreePascal;dxGaugeControlRS26;dxorgcRS26;dxPScxVGridLnkRS26;bindcompfmx;DBXOracleDriver;inetdb;dxBarDBNavRS26;FmxTeeUI;emsedge;FireDACIBDriver;fmx;fmxdae;dxWizardControlRS26;dxTabbedMDIRS26;dxEMFRS26;dbexpress;IndyCore;dxComnRS26;dsnap;DataSnapCommon;emsclient;FireDACCommon;DataSnapConnectors;cxSchedulerTreeBrowserRS26;soapserver;cxPivotGridOLAPRS26;cxVerticalGridRS26;dxtrmdRS26;FireDACOracleDriver;DBXMySQLDriver;cxSchedulerRS26;dxPSdxLCLnkRS26;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;dxMapControlRS26;inet;dxSpellCheckerRS26;IndyIPCommon;dxSpreadSheetCoreConditionalFormattingDialogsRS26;vcl;dxPSdxDBOCLnkRS26;FireDACDb2Driver;dxSpreadSheetReportDesignerRS26;dxPScxPCProdRS26;dxNavBarRS26;dxCoreRS26;cxExportRS26;TeeDB;FireDAC;dxHttpIndyRequestRS26;dxPSPrVwRibbonRS26;FireDACSqliteDriver;FireDACPgDriver;dxPSRichEditControlLnkRS26;FireDACASADriver;cxPivotGridChartRS26;dxPSDBTeeChartRS26;Tee;DataSnapServer;dxPSdxDBTVLnkRS26;vclwinx;FireDACDSDriver;dxTileControlRS26;CustomIPTransport;vcldsnap;dxSkinsCoreRS26;bindcomp;DBXInformixDriver;dxPSdxOCLnkRS26;SynEdit_R;dbxcds;adortl;RESTManager;dxSpreadSheetCoreDialogsRS26;dxBarExtDBItemsRS26;dsnapxml;dbrtl;inetdbxpress;IndyProtocols;dxPSdxPDFViewerLnkRS26;dxRichEditInplaceRS26;RestDatawareCORE;$(DCC_UsePackage)</DCC_UsePackage>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Cfg_1)'!=''">
|
||||
<DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
|
||||
<DCC_DebugDCUs>true</DCC_DebugDCUs>
|
||||
<DCC_Optimize>false</DCC_Optimize>
|
||||
<DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
|
||||
<DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
|
||||
<DCC_RemoteDebug>true</DCC_RemoteDebug>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
|
||||
<DCC_RemoteDebug>false</DCC_RemoteDebug>
|
||||
<AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
|
||||
<AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
|
||||
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
|
||||
<VerInfo_Locale>1033</VerInfo_Locale>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Cfg_2)'!=''">
|
||||
<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
|
||||
<DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
|
||||
<DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
|
||||
<DCC_DebugInformation>0</DCC_DebugInformation>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
|
||||
<AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
|
||||
<AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<DelphiCompile Include="$(MainSource)">
|
||||
<MainSource>MainSource</MainSource>
|
||||
</DelphiCompile>
|
||||
<DCCReference Include="MainFormU.pas">
|
||||
<Form>Form1</Form>
|
||||
<FormType>dfm</FormType>
|
||||
</DCCReference>
|
||||
<DCCReference Include="WebModuleMainU.pas">
|
||||
<Form>WebModule1</Form>
|
||||
<FormType>dfm</FormType>
|
||||
<DesignClass>TWebModule</DesignClass>
|
||||
</DCCReference>
|
||||
<DCCReference Include="MyController1U.pas"/>
|
||||
<DCCReference Include="MyController2U.pas"/>
|
||||
<DCCReference Include="..\..\sources\MVCFramework.Middleware.Swagger.pas"/>
|
||||
<DCCReference Include="..\..\sources\MVCFramework.Swagger.Commons.pas"/>
|
||||
<DCCReference Include="AuthHandler.pas"/>
|
||||
<BuildConfiguration Include="Release">
|
||||
<Key>Cfg_2</Key>
|
||||
<CfgParent>Base</CfgParent>
|
||||
</BuildConfiguration>
|
||||
<BuildConfiguration Include="Base">
|
||||
<Key>Base</Key>
|
||||
</BuildConfiguration>
|
||||
<BuildConfiguration Include="Debug">
|
||||
<Key>Cfg_1</Key>
|
||||
<CfgParent>Base</CfgParent>
|
||||
</BuildConfiguration>
|
||||
</ItemGroup>
|
||||
<ProjectExtensions>
|
||||
<Borland.Personality>Delphi.Personality.12</Borland.Personality>
|
||||
<Borland.ProjectType>Application</Borland.ProjectType>
|
||||
<BorlandProject>
|
||||
<Delphi.Personality>
|
||||
<Source>
|
||||
<Source Name="MainSource">SwaggerDocApi.dpr</Source>
|
||||
</Source>
|
||||
<Excluded_Packages>
|
||||
<Excluded_Packages Name="$(BDSBIN)\dcloffice2k260.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
|
||||
<Excluded_Packages Name="$(BDSBIN)\dclofficexp260.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
|
||||
</Excluded_Packages>
|
||||
</Delphi.Personality>
|
||||
<Deployment Version="3">
|
||||
<DeployFile LocalName="bin\SwaggerDocApi.exe" Configuration="Debug" Class="ProjectOutput">
|
||||
<Platform Name="Win32">
|
||||
<RemoteName>SwaggerDocApi.exe</RemoteName>
|
||||
<Overwrite>true</Overwrite>
|
||||
</Platform>
|
||||
</DeployFile>
|
||||
<DeployClass Name="AdditionalDebugSymbols">
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="OSX32">
|
||||
<RemoteDir>Contents\MacOS</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidClassesDexFile">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>classes</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidFileProvider">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\xml</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidGDBServer">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidLibnativeArmeabiFile">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>library\lib\armeabi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidLibnativeMipsFile">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>library\lib\mips</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidServiceOutput">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidSplashImageDef">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidSplashStyles">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\values</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidSplashStylesV21">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\values-v21</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_Colors">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\values</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_DefaultAppIcon">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_LauncherIcon144">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_LauncherIcon36">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-ldpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_LauncherIcon48">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-mdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_LauncherIcon72">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-hdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_LauncherIcon96">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-xhdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_NotificationIcon24">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-mdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_NotificationIcon36">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-hdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_NotificationIcon48">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-xhdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_NotificationIcon72">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_NotificationIcon96">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-xxxhdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_SplashImage426">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-small</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_SplashImage470">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-normal</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_SplashImage640">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-large</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_SplashImage960">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-xlarge</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_Strings">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\values</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="DebugSymbols">
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="OSX32">
|
||||
<RemoteDir>Contents\MacOS</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="DependencyFramework">
|
||||
<Platform Name="OSX32">
|
||||
<RemoteDir>Contents\MacOS</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.framework</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="OSX64">
|
||||
<RemoteDir>Contents\MacOS</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.framework</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="DependencyModule">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="OSX32">
|
||||
<RemoteDir>Contents\MacOS</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="OSX64">
|
||||
<RemoteDir>Contents\MacOS</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<Operation>0</Operation>
|
||||
<Extensions>.dll;.bpl</Extensions>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Required="true" Name="DependencyPackage">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="OSX32">
|
||||
<RemoteDir>Contents\MacOS</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="OSX64">
|
||||
<RemoteDir>Contents\MacOS</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<Operation>0</Operation>
|
||||
<Extensions>.bpl</Extensions>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="File">
|
||||
<Platform Name="Android">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
<Platform Name="OSX32">
|
||||
<RemoteDir>Contents\Resources\StartUp\</RemoteDir>
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
<Platform Name="OSX64">
|
||||
<RemoteDir>Contents\Resources\StartUp\</RemoteDir>
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch1024">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch1024x768">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch1536">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch1536x2048">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch1668">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch1668x2388">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch2048">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch2048x1536">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch2048x2732">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch2224">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch2388x1668">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch2732x2048">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch768">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch768x1024">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch1125">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch1136x640">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch1242">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch1242x2688">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch1334">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch1792">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch2208">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch2436">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch2688x1242">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch320">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch640">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch640x1136">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch750">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch828">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectAndroidManifest">
|
||||
<Platform Name="Android">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectiOSDeviceDebug">
|
||||
<Platform Name="iOSDevice32">
|
||||
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectiOSDeviceResourceRules">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectiOSEntitlements">
|
||||
<Platform Name="iOSDevice32">
|
||||
<RemoteDir>..\</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<RemoteDir>..\</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectiOSInfoPList">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectiOSResource">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectOSXDebug">
|
||||
<Platform Name="OSX64">
|
||||
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectOSXEntitlements">
|
||||
<Platform Name="OSX32">
|
||||
<RemoteDir>..\</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="OSX64">
|
||||
<RemoteDir>..\</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectOSXInfoPList">
|
||||
<Platform Name="OSX32">
|
||||
<RemoteDir>Contents</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="OSX64">
|
||||
<RemoteDir>Contents</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectOSXResource">
|
||||
<Platform Name="OSX32">
|
||||
<RemoteDir>Contents\Resources</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="OSX64">
|
||||
<RemoteDir>Contents\Resources</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Required="true" Name="ProjectOutput">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Linux64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="OSX32">
|
||||
<RemoteDir>Contents\MacOS</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="OSX64">
|
||||
<RemoteDir>Contents\MacOS</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectUWPManifest">
|
||||
<Platform Name="Win32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Win64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="UWP_DelphiLogo150">
|
||||
<Platform Name="Win32">
|
||||
<RemoteDir>Assets</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Win64">
|
||||
<RemoteDir>Assets</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="UWP_DelphiLogo44">
|
||||
<Platform Name="Win32">
|
||||
<RemoteDir>Assets</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Win64">
|
||||
<RemoteDir>Assets</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>
|
||||
<ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
|
||||
<ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
|
||||
<ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
|
||||
<ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
|
||||
<ProjectRoot Platform="OSX32" Name="$(PROJECTNAME).app"/>
|
||||
<ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
|
||||
<ProjectRoot Platform="OSX64" Name="$(PROJECTNAME).app"/>
|
||||
<ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
|
||||
</Deployment>
|
||||
<Platforms>
|
||||
<Platform value="Win32">True</Platform>
|
||||
<Platform value="Win64">False</Platform>
|
||||
</Platforms>
|
||||
</BorlandProject>
|
||||
<ProjectFileVersion>12</ProjectFileVersion>
|
||||
</ProjectExtensions>
|
||||
<Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
|
||||
<Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
|
||||
<Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/>
|
||||
</Project>
|
8
samples/swaggerdoc/WebModuleMainU.dfm
Normal file
8
samples/swaggerdoc/WebModuleMainU.dfm
Normal file
@ -0,0 +1,8 @@
|
||||
object WebModule1: TWebModule1
|
||||
OldCreateOrder = False
|
||||
OnCreate = WebModuleCreate
|
||||
OnDestroy = WebModuleDestroy
|
||||
Actions = <>
|
||||
Height = 230
|
||||
Width = 415
|
||||
end
|
87
samples/swaggerdoc/WebModuleMainU.pas
Normal file
87
samples/swaggerdoc/WebModuleMainU.pas
Normal file
@ -0,0 +1,87 @@
|
||||
unit WebModuleMainU;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
System.SysUtils,
|
||||
System.Classes,
|
||||
Web.HTTPApp,
|
||||
MVCFramework;
|
||||
|
||||
type
|
||||
TWebModule1 = class(TWebModule)
|
||||
procedure WebModuleCreate(Sender: TObject);
|
||||
procedure WebModuleDestroy(Sender: TObject);
|
||||
private
|
||||
{ Private declarations }
|
||||
FEngine: TMVCEngine;
|
||||
public
|
||||
{ Public declarations }
|
||||
end;
|
||||
|
||||
var
|
||||
WebModuleClass: TComponentClass = TWebModule1;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
MVCFramework.Commons,
|
||||
MVCFramework.Controllers.Register,
|
||||
MVCFramework.Middleware.Swagger,
|
||||
MVCFramework.Swagger.Commons,
|
||||
MVCFramework.Middleware.JWT,
|
||||
AuthHandler, MVCFramework.JWT, System.DateUtils;
|
||||
|
||||
{%CLASSGROUP 'Vcl.Controls.TControl'}
|
||||
{$R *.dfm}
|
||||
|
||||
|
||||
procedure TWebModule1.WebModuleCreate(Sender: TObject);
|
||||
var
|
||||
LSwagInfo: TMVCSwaggerInfo;
|
||||
LClaimsSetup: TJWTClaimsSetup;
|
||||
begin
|
||||
FEngine := TMVCEngine.Create(Self);
|
||||
|
||||
// Path prefix will be swagger basepath
|
||||
FEngine.Config[TMVCConfigKey.PathPrefix] := '/api';
|
||||
FEngine.Config[TMVCConfigKey.DocumentRoot] := '.\www';
|
||||
|
||||
LSwagInfo.Title := 'Sample Swagger API';
|
||||
LSwagInfo.Version := 'v1';
|
||||
LSwagInfo.TermsOfService := 'http://www.apache.org/licenses/LICENSE-2.0.txt';
|
||||
LSwagInfo.Description := 'Swagger Documentation Example';
|
||||
LSwagInfo.ContactName := 'João Antônio Duarte';
|
||||
LSwagInfo.ContactEmail := 'joao.antonioduarte@hotmail.com';
|
||||
LSwagInfo.ContactUrl := 'https://github.com/joaoduarte19';
|
||||
LSwagInfo.LicenseName := 'Apache License - Version 2.0, January 2004';
|
||||
LSwagInfo.LicenseUrl := 'http://www.apache.org/licenses/LICENSE-2.0';
|
||||
FEngine.AddMiddleware(TMVCSwaggerMiddleware.Create(FEngine, LSwagInfo, '/api/swagger.json'));
|
||||
|
||||
LClaimsSetup := procedure(const JWT: TJWT)
|
||||
begin
|
||||
JWT.Claims.Issuer := 'Delphi MVC Framework Swagger Documentation';
|
||||
JWT.Claims.ExpirationTime := Now + OneHour; // valid for 1 hour
|
||||
JWT.Claims.NotBefore := Now - OneMinute * 5; // valid since 5 minutes ago
|
||||
JWT.Claims.IssuedAt := Now;
|
||||
end;
|
||||
|
||||
FEngine.AddMiddleware(TMVCJWTAuthenticationMiddleware.Create(
|
||||
TAuthHandler.Create,
|
||||
'D3lph1MVCFram3w0rk',
|
||||
'/api/login',
|
||||
LClaimsSetup,
|
||||
[TJWTCheckableClaim.ExpirationTime, TJWTCheckableClaim.NotBefore, TJWTCheckableClaim.IssuedAt]
|
||||
));
|
||||
|
||||
/// Add your registered controllers to engine.
|
||||
/// Only registered controls such as "MyServerName" will be added
|
||||
TControllersRegister.Instance.AddControllersInEngine(FEngine, 'MyServerName');
|
||||
end;
|
||||
|
||||
procedure TWebModule1.WebModuleDestroy(Sender: TObject);
|
||||
begin
|
||||
FEngine.Free;
|
||||
end;
|
||||
|
||||
end.
|
BIN
samples/swaggerdoc/bin/www/swagger/favicon-16x16.png
Normal file
BIN
samples/swaggerdoc/bin/www/swagger/favicon-16x16.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 665 B |
BIN
samples/swaggerdoc/bin/www/swagger/favicon-32x32.png
Normal file
BIN
samples/swaggerdoc/bin/www/swagger/favicon-32x32.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 628 B |
60
samples/swaggerdoc/bin/www/swagger/index.html
Normal file
60
samples/swaggerdoc/bin/www/swagger/index.html
Normal file
@ -0,0 +1,60 @@
|
||||
<!-- HTML for static distribution bundle build -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Swagger UI</title>
|
||||
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" >
|
||||
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
|
||||
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
|
||||
<style>
|
||||
html
|
||||
{
|
||||
box-sizing: border-box;
|
||||
overflow: -moz-scrollbars-vertical;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
*,
|
||||
*:before,
|
||||
*:after
|
||||
{
|
||||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
body
|
||||
{
|
||||
margin:0;
|
||||
background: #fafafa;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="swagger-ui"></div>
|
||||
|
||||
<script src="./swagger-ui-bundle.js"> </script>
|
||||
<script src="./swagger-ui-standalone-preset.js"> </script>
|
||||
<script>
|
||||
window.onload = function() {
|
||||
// Begin Swagger UI call region
|
||||
const ui = SwaggerUIBundle({
|
||||
url: "/api/swagger.json",
|
||||
dom_id: '#swagger-ui',
|
||||
deepLinking: true,
|
||||
presets: [
|
||||
SwaggerUIBundle.presets.apis,
|
||||
SwaggerUIStandalonePreset
|
||||
],
|
||||
plugins: [
|
||||
SwaggerUIBundle.plugins.DownloadUrl
|
||||
],
|
||||
layout: "StandaloneLayout"
|
||||
})
|
||||
// End Swagger UI call region
|
||||
|
||||
window.ui = ui
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
67
samples/swaggerdoc/bin/www/swagger/oauth2-redirect.html
Normal file
67
samples/swaggerdoc/bin/www/swagger/oauth2-redirect.html
Normal file
@ -0,0 +1,67 @@
|
||||
<!doctype html>
|
||||
<html lang="en-US">
|
||||
<body onload="run()">
|
||||
</body>
|
||||
</html>
|
||||
<script>
|
||||
'use strict';
|
||||
function run () {
|
||||
var oauth2 = window.opener.swaggerUIRedirectOauth2;
|
||||
var sentState = oauth2.state;
|
||||
var redirectUrl = oauth2.redirectUrl;
|
||||
var isValid, qp, arr;
|
||||
|
||||
if (/code|token|error/.test(window.location.hash)) {
|
||||
qp = window.location.hash.substring(1);
|
||||
} else {
|
||||
qp = location.search.substring(1);
|
||||
}
|
||||
|
||||
arr = qp.split("&")
|
||||
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';})
|
||||
qp = qp ? JSON.parse('{' + arr.join() + '}',
|
||||
function (key, value) {
|
||||
return key === "" ? value : decodeURIComponent(value)
|
||||
}
|
||||
) : {}
|
||||
|
||||
isValid = qp.state === sentState
|
||||
|
||||
if ((
|
||||
oauth2.auth.schema.get("flow") === "accessCode"||
|
||||
oauth2.auth.schema.get("flow") === "authorizationCode"
|
||||
) && !oauth2.auth.code) {
|
||||
if (!isValid) {
|
||||
oauth2.errCb({
|
||||
authId: oauth2.auth.name,
|
||||
source: "auth",
|
||||
level: "warning",
|
||||
message: "Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"
|
||||
});
|
||||
}
|
||||
|
||||
if (qp.code) {
|
||||
delete oauth2.state;
|
||||
oauth2.auth.code = qp.code;
|
||||
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
|
||||
} else {
|
||||
let oauthErrorMsg
|
||||
if (qp.error) {
|
||||
oauthErrorMsg = "["+qp.error+"]: " +
|
||||
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
|
||||
(qp.error_uri ? "More info: "+qp.error_uri : "");
|
||||
}
|
||||
|
||||
oauth2.errCb({
|
||||
authId: oauth2.auth.name,
|
||||
source: "auth",
|
||||
level: "error",
|
||||
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server"
|
||||
});
|
||||
}
|
||||
} else {
|
||||
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
|
||||
}
|
||||
window.close();
|
||||
}
|
||||
</script>
|
125
samples/swaggerdoc/bin/www/swagger/swagger-ui-bundle.js
Normal file
125
samples/swaggerdoc/bin/www/swagger/swagger-ui-bundle.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
4
samples/swaggerdoc/bin/www/swagger/swagger-ui.css
Normal file
4
samples/swaggerdoc/bin/www/swagger/swagger-ui.css
Normal file
File diff suppressed because one or more lines are too long
1
samples/swaggerdoc/bin/www/swagger/swagger-ui.css.map
Normal file
1
samples/swaggerdoc/bin/www/swagger/swagger-ui.css.map
Normal file
File diff suppressed because one or more lines are too long
9
samples/swaggerdoc/bin/www/swagger/swagger-ui.js
Normal file
9
samples/swaggerdoc/bin/www/swagger/swagger-ui.js
Normal file
File diff suppressed because one or more lines are too long
1
samples/swaggerdoc/bin/www/swagger/swagger-ui.js.map
Normal file
1
samples/swaggerdoc/bin/www/swagger/swagger-ui.js.map
Normal file
File diff suppressed because one or more lines are too long
357
sources/MVCFramework.Middleware.Swagger.pas
Normal file
357
sources/MVCFramework.Middleware.Swagger.pas
Normal file
@ -0,0 +1,357 @@
|
||||
unit MVCFramework.Middleware.Swagger;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
MVCFramework,
|
||||
Swag.Doc,
|
||||
MVCFramework.Swagger.Commons,
|
||||
Swag.Doc.SecurityDefinition,
|
||||
Swag.Common.Types,
|
||||
System.JSON;
|
||||
|
||||
type
|
||||
TMVCSwaggerMiddleware = class(TInterfacedObject, IMVCMiddleware)
|
||||
private
|
||||
FEngine: TMVCEngine;
|
||||
FSwaggerInfo: TMVCSwaggerInfo;
|
||||
FSwagDocURL: string;
|
||||
procedure DocumentApiInfo(const ASwagDoc: TSwagDoc);
|
||||
procedure DocumentApiSettings(AContext: TWebContext; ASwagDoc: TSwagDoc);
|
||||
procedure DocumentApiJWTAuthentication(const ASwagDoc: TSwagDoc);
|
||||
procedure DocumentApi(ASwagDoc: TSwagDoc);
|
||||
procedure InternalRender(AContent: string; AContext: TWebContext);
|
||||
procedure RenderError(const AContext: TWebContext; const AErrorMessage, AErrorClassName: string);
|
||||
public
|
||||
constructor Create(
|
||||
const AEngine: TMVCEngine;
|
||||
const ASwaggerInfo: TMVCSwaggerInfo;
|
||||
const ASwaggerDocumentationURL: string = '/swagger.json'
|
||||
);
|
||||
destructor Destroy; override;
|
||||
procedure OnBeforeRouting(AContext: TWebContext; var AHandled: Boolean);
|
||||
procedure OnBeforeControllerAction(AContext: TWebContext; const AControllerQualifiedClassName: string;
|
||||
const AActionName: string; var AHandled: Boolean);
|
||||
procedure OnAfterControllerAction(AContext: TWebContext; const AActionName: string; const AHandled: Boolean);
|
||||
end;
|
||||
|
||||
TSwagSecurityDefinitionBasic = class(TSwagSecurityDefinition)
|
||||
protected
|
||||
function GetTypeSecurity: TSwagSecurityDefinitionType; override;
|
||||
public
|
||||
function GenerateJsonObject: System.JSON.TJSONObject; override;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
System.SysUtils,
|
||||
MVCFramework.Commons,
|
||||
System.Classes,
|
||||
JsonDataObjects,
|
||||
System.Rtti,
|
||||
Swag.Doc.Path,
|
||||
Swag.Doc.Path.Operation,
|
||||
Swag.Doc.Path.Operation.Response,
|
||||
MVCFramework.Middleware.JWT,
|
||||
Swag.Doc.Path.Operation.RequestParameter,
|
||||
Swag.Doc.SecurityDefinitionApiKey;
|
||||
|
||||
{ TMVCSwaggerMiddleware }
|
||||
|
||||
constructor TMVCSwaggerMiddleware.Create(const AEngine: TMVCEngine; const ASwaggerInfo: TMVCSwaggerInfo;
|
||||
const ASwaggerDocumentationURL: string);
|
||||
begin
|
||||
inherited Create;
|
||||
FSwagDocURL := ASwaggerDocumentationURL;
|
||||
FEngine := AEngine;
|
||||
FSwaggerInfo := ASwaggerInfo;
|
||||
end;
|
||||
|
||||
destructor TMVCSwaggerMiddleware.Destroy;
|
||||
begin
|
||||
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TMVCSwaggerMiddleware.DocumentApi(ASwagDoc: TSwagDoc);
|
||||
var
|
||||
LRttiContext: TRttiContext;
|
||||
LObjType: TRttiType;
|
||||
LController: TMVCControllerDelegate;
|
||||
LSwagPath: TSwagPath;
|
||||
LAttr: TCustomAttribute;
|
||||
LControllerPath: string;
|
||||
LMethodPath: string;
|
||||
LMethod: TRttiMethod;
|
||||
LFoundAttr: Boolean;
|
||||
LMVCHttpMethods: TMVCHTTPMethods;
|
||||
LSwagPathOp: TSwagPathOperation;
|
||||
I: TMVCHTTPMethodType;
|
||||
LPathUri: string;
|
||||
LIndex: Integer;
|
||||
begin
|
||||
LRttiContext := TRttiContext.Create;
|
||||
try
|
||||
for LController in FEngine.Controllers do
|
||||
begin
|
||||
LControllerPath := '';
|
||||
LObjType := LRttiContext.GetType(LController.Clazz);
|
||||
for LAttr in LObjType.GetAttributes do
|
||||
begin
|
||||
if LAttr is MVCPathAttribute then
|
||||
begin
|
||||
LControllerPath := MVCPathAttribute(LAttr).Path;
|
||||
Break;
|
||||
end;
|
||||
end;
|
||||
|
||||
if LControllerPath.IsEmpty then
|
||||
Continue;
|
||||
|
||||
for LMethod in LObjType.GetDeclaredMethods do
|
||||
begin
|
||||
LFoundAttr := False;
|
||||
LMVCHttpMethods := [];
|
||||
LMethodPath := '';
|
||||
|
||||
for LAttr in LMethod.GetAttributes do
|
||||
begin
|
||||
if LAttr is MVCPathAttribute then
|
||||
begin
|
||||
LMethodPath := MVCPathAttribute(LAttr).Path;
|
||||
LFoundAttr := True;
|
||||
end;
|
||||
if LAttr is MVCHTTPMethodsAttribute then
|
||||
begin
|
||||
LMVCHttpMethods := MVCHTTPMethodsAttribute(LAttr).MVCHTTPMethods;
|
||||
end;
|
||||
end;
|
||||
|
||||
if LFoundAttr then
|
||||
begin
|
||||
LSwagPath := nil;
|
||||
LPathUri := TMVCSwagger.MVCPathToSwagPath(LControllerPath + LMethodPath);
|
||||
for LIndex := 0 to Pred(ASwagDoc.Paths.Count) do
|
||||
begin
|
||||
if SameText(ASwagDoc.Paths[LIndex].Uri, LPathUri) then
|
||||
begin
|
||||
LSwagPath := ASwagDoc.Paths[LIndex];
|
||||
Break;
|
||||
end;
|
||||
end;
|
||||
|
||||
if not Assigned(LSwagPath) then
|
||||
begin
|
||||
LSwagPath := TSwagPath.Create;
|
||||
LSwagPath.Uri := LPathUri;
|
||||
ASwagDoc.Paths.Add(LSwagPath);
|
||||
end;
|
||||
|
||||
for I in LMVCHttpMethods do
|
||||
begin
|
||||
LSwagPathOp := TSwagPathOperation.Create;
|
||||
TMVCSwagger.FillOperationSummary(LSwagPathOp, LMethod);
|
||||
|
||||
if TMVCSwagger.MethodRequiresAuthentication(LMethod, LObjType) then
|
||||
LSwagPathOp.Security.Add(SECURITY_BEARER_NAME);
|
||||
|
||||
LSwagPathOp.Parameters.AddRange(TMVCSwagger.GetParamsFromMethod(LSwagPath.Uri, LMethod));
|
||||
LSwagPathOp.Operation := TMVCSwagger.MVCHttpMethodToSwagPathOperation(I);
|
||||
LSwagPath.Operations.Add(LSwagPathOp);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
finally
|
||||
LRttiContext.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMVCSwaggerMiddleware.DocumentApiInfo(const ASwagDoc: TSwagDoc);
|
||||
begin
|
||||
ASwagDoc.Info.Title := FSwaggerInfo.Title;
|
||||
ASwagDoc.Info.Version := FSwaggerInfo.Version;
|
||||
ASwagDoc.Info.TermsOfService := FSwaggerInfo.TermsOfService;
|
||||
ASwagDoc.Info.Description := FSwaggerInfo.Description;
|
||||
ASwagDoc.Info.Contact.Name := FSwaggerInfo.ContactName;
|
||||
ASwagDoc.Info.Contact.Email := FSwaggerInfo.ContactEmail;
|
||||
ASwagDoc.Info.Contact.Url := FSwaggerInfo.ContactUrl;
|
||||
ASwagDoc.Info.License.Name := FSwaggerInfo.LicenseName;
|
||||
ASwagDoc.Info.License.Url := FSwaggerInfo.LicenseUrl;
|
||||
end;
|
||||
|
||||
procedure TMVCSwaggerMiddleware.DocumentApiJWTAuthentication(const ASwagDoc: TSwagDoc);
|
||||
var
|
||||
LMiddleware: IMVCMiddleware;
|
||||
LJWTMiddleware: TMVCJWTAuthenticationMiddleware;
|
||||
LRttiContext: TRttiContext;
|
||||
LObjType: TRttiType;
|
||||
LJwtUrlField: TRttiField;
|
||||
LJwtUrlSegment: string;
|
||||
LSecurityDefsBearer: TSwagSecurityDefinitionApiKey;
|
||||
LSecurityDefsBasic: TSwagSecurityDefinitionBasic;
|
||||
begin
|
||||
LJWTMiddleware := nil;
|
||||
for LMiddleware in FEngine.Middlewares do
|
||||
begin
|
||||
if LMiddleware is TMVCJWTAuthenticationMiddleware then
|
||||
begin
|
||||
LJWTMiddleware := LMiddleware as TMVCJWTAuthenticationMiddleware;
|
||||
Break;
|
||||
end;
|
||||
end;
|
||||
|
||||
if Assigned(LJWTMiddleware) then
|
||||
begin
|
||||
LRttiContext := TRttiContext.Create;
|
||||
try
|
||||
LObjType := LRttiContext.GetType(LJWTMiddleware.ClassInfo);
|
||||
LJwtUrlField := LObjType.GetField('FLoginURLSegment');
|
||||
if Assigned(LJwtUrlField) then
|
||||
begin
|
||||
LJwtUrlSegment := LJwtUrlField.GetValue(LJWTMiddleware).AsString;
|
||||
if LJwtUrlSegment.StartsWith(ASwagDoc.BasePath) then
|
||||
LJwtUrlSegment := LJwtUrlSegment.Remove(0, ASwagDoc.BasePath.Length);
|
||||
if not LJwtUrlSegment.StartsWith('/') then
|
||||
LJwtUrlSegment.Insert(0, '/');
|
||||
|
||||
// Path operation Middleware JWT
|
||||
ASwagDoc.Paths.Add(TMVCSwagger.GetJWTAuthenticationPath(LJwtUrlSegment));
|
||||
|
||||
// basic auth is used by jwt middleware to generate json web token
|
||||
LSecurityDefsBasic := TSwagSecurityDefinitionBasic.Create;
|
||||
LSecurityDefsBasic.SchemaName := SECURITY_BASIC_NAME;
|
||||
LSecurityDefsBasic.Description := 'Send UserName and Password to return JWT Token';
|
||||
ASwagDoc.SecurityDefinitions.Add(LSecurityDefsBasic);
|
||||
|
||||
// Methods that have the MVCRequiresAuthentication attribute use bearer authentication.
|
||||
LSecurityDefsBearer := TSwagSecurityDefinitionApiKey.Create;
|
||||
LSecurityDefsBearer.SchemaName := SECURITY_BEARER_NAME;
|
||||
LSecurityDefsBearer.InLocation := kilHeader;
|
||||
LSecurityDefsBearer.Name := 'Authorization';
|
||||
LSecurityDefsBearer.Description :=
|
||||
'For accessing the API a valid JWT token must be passed in all the queries ' +
|
||||
'in the ''Authorization'' header.' + sLineBreak + sLineBreak +
|
||||
'A valid JWT token is generated by the API and retourned as answer of a call ' +
|
||||
'to the route `' + LJwtUrlSegment + '` giving a valid username and password.' + sLineBreak + sLineBreak +
|
||||
'The following syntax must be used in the ''Authorization'' header :' + sLineBreak + sLineBreak +
|
||||
' Bearer xxxxxx.yyyyyyy.zzzzzz' + sLineBreak;
|
||||
ASwagDoc.SecurityDefinitions.Add(LSecurityDefsBearer);
|
||||
end;
|
||||
finally
|
||||
LRttiContext.Free;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMVCSwaggerMiddleware.DocumentApiSettings(AContext: TWebContext; ASwagDoc: TSwagDoc);
|
||||
begin
|
||||
ASwagDoc.Host := Format('%s:%d', [AContext.Request.RawWebRequest.Host, AContext.Request.RawWebRequest.ServerPort]);
|
||||
ASwagDoc.BasePath := FEngine.Config[TMVCConfigKey.PathPrefix];
|
||||
|
||||
if ASwagDoc.BasePath.IsEmpty then
|
||||
ASwagDoc.BasePath := '/';
|
||||
|
||||
ASwagDoc.Schemes := [tpsHttp, tpsHttps];
|
||||
end;
|
||||
|
||||
procedure TMVCSwaggerMiddleware.InternalRender(AContent: string; AContext: TWebContext);
|
||||
var
|
||||
LContentType: string;
|
||||
LEncoding: TEncoding;
|
||||
begin
|
||||
LContentType := BuildContentType(TMVCMediaType.APPLICATION_JSON, TMVCConstants.DEFAULT_CONTENT_CHARSET);
|
||||
AContext.Response.RawWebResponse.ContentType := LContentType;
|
||||
|
||||
LEncoding := TEncoding.GetEncoding(TMVCConstants.DEFAULT_CONTENT_CHARSET);
|
||||
try
|
||||
AContext.Response.SetContentStream(TBytesStream.Create(TEncoding.Convert(TEncoding.Default, LEncoding,
|
||||
TEncoding.Default.GetBytes(AContent))), LContentType);
|
||||
finally
|
||||
LEncoding.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMVCSwaggerMiddleware.OnAfterControllerAction(AContext: TWebContext; const AActionName: string;
|
||||
const AHandled: Boolean);
|
||||
begin
|
||||
//
|
||||
end;
|
||||
|
||||
procedure TMVCSwaggerMiddleware.OnBeforeControllerAction(AContext: TWebContext; const AControllerQualifiedClassName,
|
||||
AActionName: string; var AHandled: Boolean);
|
||||
begin
|
||||
//
|
||||
end;
|
||||
|
||||
procedure TMVCSwaggerMiddleware.OnBeforeRouting(AContext: TWebContext; var AHandled: Boolean);
|
||||
var
|
||||
LSwagDoc: TSwagDoc;
|
||||
begin
|
||||
if SameText(AContext.Request.PathInfo, FSwagDocURL) and (AContext.Request.HTTPMethod in [httpGET, httpPOST]) then
|
||||
begin
|
||||
LSwagDoc := TSwagDoc.Create;
|
||||
try
|
||||
try
|
||||
DocumentApiInfo(LSwagDoc);
|
||||
DocumentApiSettings(AContext, LSwagDoc);
|
||||
DocumentApiJWTAuthentication(LSwagDoc);
|
||||
DocumentApi(LSwagDoc);
|
||||
|
||||
LSwagDoc.GenerateSwaggerJson;
|
||||
InternalRender(LSwagDoc.SwaggerJson.Format, AContext);
|
||||
AHandled := True;
|
||||
except
|
||||
on E: Exception do
|
||||
begin
|
||||
RenderError(AContext, E.Message, E.ClassName);
|
||||
AHandled := True;
|
||||
end;
|
||||
end;
|
||||
finally
|
||||
LSwagDoc.Free;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMVCSwaggerMiddleware.RenderError(const AContext: TWebContext;
|
||||
const AErrorMessage, AErrorClassName: string);
|
||||
var
|
||||
LJSonOb: TJDOJsonObject;
|
||||
begin
|
||||
AContext.Response.StatusCode := HTTP_STATUS.InternalServerError;
|
||||
AContext.Response.ReasonString := AErrorMessage;
|
||||
|
||||
LJSonOb := TJDOJsonObject.Create;
|
||||
try
|
||||
LJSonOb.S['status'] := 'error';
|
||||
|
||||
if AErrorClassName = '' then
|
||||
LJSonOb.Values['classname'] := nil
|
||||
else
|
||||
LJSonOb.S['classname'] := AErrorClassName;
|
||||
|
||||
LJSonOb.S['message'] := AErrorMessage;
|
||||
|
||||
InternalRender(LJSonOb.ToJSON, AContext);
|
||||
finally
|
||||
LJSonOb.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TSwagSecurityDefinitionBasic }
|
||||
|
||||
function TSwagSecurityDefinitionBasic.GenerateJsonObject: System.JSON.TJSONObject;
|
||||
begin
|
||||
Result := System.JSON.TJsonObject.Create;
|
||||
Result.AddPair('type', ReturnTypeSecurityToString);
|
||||
Result.AddPair('description', fDescription);
|
||||
end;
|
||||
|
||||
function TSwagSecurityDefinitionBasic.GetTypeSecurity: TSwagSecurityDefinitionType;
|
||||
begin
|
||||
Result := ssdBasic;
|
||||
end;
|
||||
|
||||
end.
|
779
sources/MVCFramework.Swagger.Commons.pas
Normal file
779
sources/MVCFramework.Swagger.Commons.pas
Normal file
@ -0,0 +1,779 @@
|
||||
unit MVCFramework.Swagger.Commons;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Json.Schema,
|
||||
System.Rtti,
|
||||
Swag.Common.Types,
|
||||
MVCFramework.Commons,
|
||||
Swag.Doc.Path.Operation.RequestParameter,
|
||||
Swag.Doc.Path.Operation,
|
||||
Swag.Doc.Path,
|
||||
System.JSON,
|
||||
Json.Schema.Field;
|
||||
|
||||
type
|
||||
TMVCSwagParamLocation = (plNotDefined, plQuery, plHeader, plPath, plFormData, plBody);
|
||||
TMVCSwagParamType = (ptNotDefined, ptString, ptNumber, ptInteger, ptBoolean, ptArray, ptFile);
|
||||
TMVCSwagSchemaType = (stUnknown, stInteger, stInt64, stNumber, stDateTime, stDate, stTime,
|
||||
stEnumeration, stBoolean, stObject, stArray, stString, stChar, stGuid);
|
||||
|
||||
/// <summary>
|
||||
/// Swagger info object
|
||||
/// </summary>
|
||||
TMVCSwaggerInfo = record
|
||||
Title: string;
|
||||
Version: string;
|
||||
TermsOfService: string;
|
||||
Description: string;
|
||||
ContactName: string;
|
||||
ContactEmail: string;
|
||||
ContactUrl: string;
|
||||
LicenseName: string;
|
||||
LicenseUrl: string;
|
||||
end;
|
||||
|
||||
/// <summary>
|
||||
/// Specify swagger path summary. See <see href="https://swagger.io/docs/specification/2-0/paths-and-operations/">
|
||||
/// Swagger path and operations</see>
|
||||
/// </summary>
|
||||
MVCSwagSummaryAttribute = class(TCustomAttribute)
|
||||
private
|
||||
FTags: string;
|
||||
FDeprecated: Boolean;
|
||||
FDescription: string;
|
||||
FPathId: string;
|
||||
public
|
||||
constructor Create(const ATags, ADescription: string; const APathId: string = ''; ADeprecated: Boolean = False);
|
||||
function GetTags: TArray<string>;
|
||||
property Tags: string read FTags;
|
||||
property Description: string read FDescription;
|
||||
property PathId: string read FPathId;
|
||||
property Deprecated: Boolean read FDeprecated;
|
||||
end;
|
||||
|
||||
/// <summary>
|
||||
/// Specify swagger path responses.
|
||||
/// </summary>
|
||||
MVCSwagResponsesAttribute = class(TCustomAttribute)
|
||||
private
|
||||
FStatusCode: Integer;
|
||||
FDescription: string;
|
||||
FJsonSchema: string;
|
||||
FJsonSchemaClass: TClass;
|
||||
public
|
||||
constructor Create(
|
||||
const AStatusCode: Integer;
|
||||
const ADescription: string;
|
||||
const AJsonSchema: string = ''
|
||||
); overload;
|
||||
constructor Create(
|
||||
const AStatusCode: Integer;
|
||||
const ADescription: string;
|
||||
const AJsonSchemaClass: TClass
|
||||
); overload;
|
||||
|
||||
property StatusCode: Integer read FStatusCode;
|
||||
property Description: string read FDescription;
|
||||
property JsonSchema: string read FJsonSchema;
|
||||
property JsonSchemaClass: TClass read FJsonSchemaClass;
|
||||
end;
|
||||
|
||||
/// <summary>
|
||||
/// Specify swagger path params.
|
||||
/// </summary>
|
||||
MVCSwagParamAttribute = class(TCustomAttribute)
|
||||
private
|
||||
FParamLocation: TMVCSwagParamLocation;
|
||||
FParamName: string;
|
||||
FParamDescription: string;
|
||||
FParamType: TMVCSwagParamType;
|
||||
FRequired: Boolean;
|
||||
FJsonSchema: string;
|
||||
FJsonSchemaClass: TClass;
|
||||
public
|
||||
constructor Create(
|
||||
const AParamLocation: TMVCSwagParamLocation;
|
||||
const AParamName: string;
|
||||
const AParamDescription: string;
|
||||
const AParamType: TMVCSwagParamType;
|
||||
const ARequired: Boolean = True;
|
||||
const AJsonSchema: string = ''); overload;
|
||||
constructor Create(
|
||||
const AParamLocation: TMVCSwagParamLocation;
|
||||
const AParamName: string;
|
||||
const AParamDescription: string;
|
||||
const AJsonSchemaClass: TClass;
|
||||
const AParamType: TMVCSwagParamType = ptNotDefined;
|
||||
const ARequired: Boolean = True); overload;
|
||||
|
||||
property ParamLocation: TMVCSwagParamLocation read FParamLocation;
|
||||
property ParamName: string read FParamName;
|
||||
property ParamDescription: string read FParamDescription;
|
||||
property ParamType: TMVCSwagParamType read FParamType;
|
||||
property Required: Boolean read FRequired;
|
||||
property JsonSchema: string read FJsonSchema;
|
||||
property JsonSchemaClass: TClass read FJsonSchemaClass;
|
||||
end;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the field definition in the json schema.
|
||||
/// Use this attribute on a class property that will be mapped to a json schema
|
||||
/// </summary>
|
||||
MVCSwagJsonSchemaFieldAttribute = class(TCustomAttribute)
|
||||
private
|
||||
FSchemaFieldType: TMVCSwagSchemaType;
|
||||
FFieldName: string;
|
||||
FDescription: string;
|
||||
FRequired: Boolean;
|
||||
FNullable: Boolean;
|
||||
public
|
||||
constructor Create(
|
||||
const ASchemaFieldType: TMVCSwagSchemaType;
|
||||
const AFieldName: string;
|
||||
const ADescription: string;
|
||||
const ARequired: Boolean;
|
||||
const ANullable: Boolean); overload;
|
||||
constructor Create(
|
||||
const AFieldName: string;
|
||||
const ADescription: string;
|
||||
const ARequired: Boolean;
|
||||
const ANullable: Boolean); overload;
|
||||
|
||||
property SchemaFieldType: TMVCSwagSchemaType read FSchemaFieldType;
|
||||
property FieldName: string read FFieldName;
|
||||
property Description: string read FDescription;
|
||||
property Required: Boolean read FRequired;
|
||||
property Nullable: Boolean read FNullable;
|
||||
end;
|
||||
|
||||
/// <summary>
|
||||
/// SwaggerDoc Methods
|
||||
/// </summary>
|
||||
TMVCSwagger = class sealed
|
||||
private
|
||||
class var FRttiContext: TRttiContext;
|
||||
class function GetMVCSwagParamsFromMethod(const AMethod: TRttiMethod): TArray<MVCSwagParamAttribute>;
|
||||
class function MVCParamLocationToSwagRequestParamInLocation(const AMVCSwagParamLocation: TMVCSwagParamLocation):
|
||||
TSwagRequestParameterInLocation;
|
||||
class function MVCParamTypeToSwagTypeParameter(const AMVSwagParamType: TMVCSwagParamType): TSwagTypeParameter;
|
||||
class function ExtractJsonSchemaFromClass(const AClass: TClass): TJSONObject;
|
||||
class function GetJsonFieldClass(const ASchemaFieldType: TMVCSwagSchemaType): TJsonFieldClass;
|
||||
class function TypeKindToMVCSwagSchemaType(APropType: TRttiType): TMVCSwagSchemaType; static;
|
||||
public
|
||||
class constructor Create;
|
||||
class destructor Destroy;
|
||||
class function MVCHttpMethodToSwagPathOperation(const AMVCHTTPMethod: TMVCHTTPMethodType): TSwagPathTypeOperation;
|
||||
class function MVCPathToSwagPath(const AResourcePath: string): string;
|
||||
class function GetParamsFromMethod(const AResourcePath: string; const AMethod: TRttiMethod):
|
||||
TArray<TSwagRequestParameter>;
|
||||
class function RttiTypeToSwagType(const ARttiType: TRttiType): TSwagTypeParameter;
|
||||
class procedure FillOperationSummary(const ASwagPathOperation: TSwagPathOperation; const AMethod: TRttiMethod);
|
||||
class function MethodRequiresAuthentication(const AMethod: TRttiMethod; const AType: TRttiType): Boolean;
|
||||
class function GetJWTAuthenticationPath(const AJWTUrlSegment: string): TSwagPath;
|
||||
end;
|
||||
|
||||
const
|
||||
SECURITY_BEARER_NAME = 'bearer';
|
||||
SECURITY_BASIC_NAME = 'basic';
|
||||
JWT_JSON_SCHEMA =
|
||||
'{' + sLineBreak +
|
||||
' "type": "object",' + sLineBreak +
|
||||
' "properties": {' + sLineBreak +
|
||||
' "token": {' + sLineBreak +
|
||||
' "type": "string",' + sLineBreak +
|
||||
' "description": "JWT Token"' + sLineBreak +
|
||||
' }' + sLineBreak +
|
||||
' }' + sLineBreak +
|
||||
'}';
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
System.RegularExpressions,
|
||||
System.SysUtils,
|
||||
MVCFramework,
|
||||
Swag.Doc.Path.Operation.Response,
|
||||
System.Classes,
|
||||
System.TypInfo,
|
||||
MVCFramework.Serializer.Commons,
|
||||
MVCFramework.Middleware.Authentication.RoleBasedAuthHandler,
|
||||
Json.Schema.Field.Numbers,
|
||||
Json.Schema.Field.Strings,
|
||||
Json.Schema.Field.Arrays,
|
||||
Json.Schema.Field.DateTimes,
|
||||
Json.Schema.Field.Enums,
|
||||
Json.Schema.Field.Booleans;
|
||||
|
||||
{ TSwaggerUtils }
|
||||
|
||||
class constructor TMVCSwagger.Create;
|
||||
begin
|
||||
FRttiContext := TRttiContext.Create;
|
||||
end;
|
||||
|
||||
class function TMVCSwagger.RttiTypeToSwagType(const ARttiType: TRttiType): TSwagTypeParameter;
|
||||
begin
|
||||
case ARttiType.TypeKind of
|
||||
tkInteger, tkInt64:
|
||||
Result := stpInteger;
|
||||
tkChar, tkString, tkWChar, tkLString, tkWString, tkUString:
|
||||
Result := stpString;
|
||||
tkFloat:
|
||||
if (ARttiType.Handle = TypeInfo(TDateTime)) or
|
||||
(ARttiType.Handle = TypeInfo(TDate)) or
|
||||
(ARttiType.Handle = TypeInfo(TTime)) then
|
||||
Result := stpString
|
||||
else
|
||||
Result := stpNumber;
|
||||
tkEnumeration:
|
||||
if ARttiType.Handle = TypeInfo(Boolean) then
|
||||
Result := stpBoolean
|
||||
else
|
||||
Result := stpArray;
|
||||
else
|
||||
Result := stpNotDefined;
|
||||
end;
|
||||
end;
|
||||
|
||||
class destructor TMVCSwagger.Destroy;
|
||||
begin
|
||||
FRttiContext.Free;
|
||||
end;
|
||||
|
||||
type
|
||||
TFieldSchemaDefinition = record
|
||||
SchemaFieldType: TMVCSwagSchemaType;
|
||||
FieldName: string;
|
||||
Description: string;
|
||||
Required: Boolean;
|
||||
Nullable: Boolean;
|
||||
class function Create: TFieldSchemaDefinition; static; inline;
|
||||
end;
|
||||
|
||||
class function TMVCSwagger.ExtractJsonSchemaFromClass(const AClass: TClass): TJSONObject;
|
||||
var
|
||||
LObjType: TRttiType;
|
||||
LProp: TRttiProperty;
|
||||
LJsonSchema: TJsonSchema;
|
||||
LAttr: TCustomAttribute;
|
||||
LJSFieldAttr: MVCSwagJsonSchemaFieldAttribute;
|
||||
LFieldSchemaDef: TFieldSchemaDefinition;
|
||||
LJsonField: TJsonField;
|
||||
LSkipProp: Boolean;
|
||||
begin
|
||||
LObjType := FRttiContext.GetType(AClass.ClassInfo);
|
||||
LJsonSchema := TJsonSchema.Create;
|
||||
try
|
||||
LFieldSchemaDef := TFieldSchemaDefinition.Create;
|
||||
|
||||
for LProp in LObjType.GetProperties do
|
||||
begin
|
||||
LSkipProp := False;
|
||||
LFieldSchemaDef := TFieldSchemaDefinition.Create;
|
||||
|
||||
for LAttr in LProp.GetAttributes do
|
||||
begin
|
||||
if LAttr is MVCDoNotSerializeAttribute then
|
||||
begin
|
||||
LSkipProp := True;
|
||||
Break;
|
||||
end;
|
||||
|
||||
if LAttr is MVCSwagJsonSchemaFieldAttribute then
|
||||
begin
|
||||
LJSFieldAttr := MVCSwagJsonSchemaFieldAttribute(LAttr);
|
||||
LFieldSchemaDef.SchemaFieldType := LJSFieldAttr.SchemaFieldType;
|
||||
LFieldSchemaDef.FieldName := LJSFieldAttr.FieldName;
|
||||
LFieldSchemaDef.Description := LJSFieldAttr.Description;
|
||||
LFieldSchemaDef.Required := LJSFieldAttr.Required;
|
||||
LFieldSchemaDef.Nullable := LJSFieldAttr.Nullable;
|
||||
Break;
|
||||
end;
|
||||
end;
|
||||
|
||||
if LSkipProp then
|
||||
Continue;
|
||||
|
||||
if LFieldSchemaDef.SchemaFieldType = stUnknown then
|
||||
begin
|
||||
LFieldSchemaDef.SchemaFieldType := TypeKindToMVCSwagSchemaType(LProp.PropertyType);
|
||||
LFieldSchemaDef.FieldName := TMVCSerializerHelper.GetKeyName(LProp, LObjType);
|
||||
end;
|
||||
|
||||
LJsonField := GetJsonFieldClass(LFieldSchemaDef.SchemaFieldType).Create;
|
||||
|
||||
if not Assigned(LJsonField) then
|
||||
Continue;
|
||||
|
||||
LJsonField.Name := LFieldSchemaDef.FieldName;
|
||||
LJsonField.Required := LFieldSchemaDef.Required;
|
||||
LJsonField.Nullable := LFieldSchemaDef.Nullable;
|
||||
if not LFieldSchemaDef.Description.IsEmpty then
|
||||
TJsonFieldInteger(LJsonField).Description := LFieldSchemaDef.Description;
|
||||
|
||||
LJsonSchema.Root.AddField(LJsonField);
|
||||
end;
|
||||
Result := LJsonSchema.ToJson;
|
||||
finally
|
||||
LJsonSchema.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
class procedure TMVCSwagger.FillOperationSummary(const ASwagPathOperation: TSwagPathOperation;
|
||||
const AMethod: TRttiMethod);
|
||||
var
|
||||
LAttr: TCustomAttribute;
|
||||
LSwagResponse: TSwagResponse;
|
||||
LSwagResponsesAttr: MVCSwagResponsesAttribute;
|
||||
begin
|
||||
for LAttr in AMethod.GetAttributes do
|
||||
begin
|
||||
if LAttr is MVCSwagSummaryAttribute then
|
||||
begin
|
||||
ASwagPathOperation.Tags.AddRange(MVCSwagSummaryAttribute(LAttr).GetTags);
|
||||
ASwagPathOperation.Description := MVCSwagSummaryAttribute(LAttr).Description;
|
||||
ASwagPathOperation.OperationId := MVCSwagSummaryAttribute(LAttr).PathId;
|
||||
ASwagPathOperation.Deprecated := MVCSwagSummaryAttribute(LAttr).Deprecated;
|
||||
end;
|
||||
if LAttr is MVCConsumesAttribute then
|
||||
begin
|
||||
ASwagPathOperation.Consumes.Add(MVCConsumesAttribute(LAttr).Value)
|
||||
end;
|
||||
if LAttr is MVCProducesAttribute then
|
||||
begin
|
||||
ASwagPathOperation.Produces.Add(MVCProducesAttribute(LAttr).Value)
|
||||
end;
|
||||
if LAttr is MVCSwagResponsesAttribute then
|
||||
begin
|
||||
LSwagResponsesAttr := MVCSwagResponsesAttribute(LAttr);
|
||||
|
||||
LSwagResponse := TSwagResponse.Create;
|
||||
LSwagResponse.StatusCode := LSwagResponsesAttr.StatusCode.ToString;
|
||||
LSwagResponse.Description := LSwagResponsesAttr.Description;
|
||||
if not LSwagResponsesAttr.JsonSchema.IsEmpty then
|
||||
LSwagResponse.Schema.JsonSchema := TJSONObject.ParseJSONValue(LSwagResponsesAttr.JsonSchema) as TJSONObject
|
||||
else if Assigned(LSwagResponsesAttr.JsonSchemaClass) then
|
||||
LSwagResponse.Schema.JsonSchema := ExtractJsonSchemaFromClass(LSwagResponsesAttr.JsonSchemaClass);
|
||||
|
||||
ASwagPathOperation.Responses.Add(LSwagResponse.StatusCode, LSwagResponse);
|
||||
end;
|
||||
end;
|
||||
|
||||
if ASwagPathOperation.Tags.Count = 0 then
|
||||
ASwagPathOperation.Tags.Add(AMethod.Parent.QualifiedName);
|
||||
|
||||
if ASwagPathOperation.Produces.Count <= 0 then
|
||||
ASwagPathOperation.Produces.Add(TMVCMediaType.APPLICATION_JSON);
|
||||
|
||||
if ASwagPathOperation.Responses.Count <= 0 then
|
||||
begin
|
||||
LSwagResponse := TSwagResponse.Create;
|
||||
LSwagResponse.StatusCode := HTTP_STATUS.OK.ToString;
|
||||
LSwagResponse.Description := 'Ok';
|
||||
ASwagPathOperation.Responses.Add(LSwagResponse.StatusCode, LSwagResponse);
|
||||
|
||||
LSwagResponse := TSwagResponse.Create;
|
||||
LSwagResponse.StatusCode := HTTP_STATUS.InternalServerError.ToString;
|
||||
LSwagResponse.Description := 'Internal server error';
|
||||
ASwagPathOperation.Responses.Add(LSwagResponse.StatusCode, LSwagResponse);
|
||||
end;
|
||||
|
||||
end;
|
||||
|
||||
class function TMVCSwagger.GetJsonFieldClass(const ASchemaFieldType: TMVCSwagSchemaType): TJsonFieldClass;
|
||||
begin
|
||||
case ASchemaFieldType of
|
||||
stInteger:
|
||||
Result := TJsonFieldInteger;
|
||||
stInt64:
|
||||
Result := TJsonFieldInt64;
|
||||
stNumber:
|
||||
Result := TJsonFieldNumber;
|
||||
stDateTime:
|
||||
Result := TJsonFieldDateTime;
|
||||
stDate:
|
||||
Result := TJsonFieldDate;
|
||||
stTime:
|
||||
Result := TJsonFieldTime;
|
||||
stEnumeration:
|
||||
Result := TJsonFieldEnum;
|
||||
stBoolean:
|
||||
Result := TJsonFieldBoolean;
|
||||
stArray:
|
||||
Result := TJsonFieldArray;
|
||||
stString, stChar:
|
||||
Result := TJsonFieldString;
|
||||
stGuid:
|
||||
Result := TJsonFieldGuid;
|
||||
else
|
||||
Result := nil;
|
||||
end;
|
||||
end;
|
||||
|
||||
class function TMVCSwagger.TypeKindToMVCSwagSchemaType(APropType: TRttiType): TMVCSwagSchemaType;
|
||||
begin
|
||||
Result := stUnknown;
|
||||
|
||||
if APropType.TypeKind = tkUnknown then
|
||||
Exit;
|
||||
|
||||
case APropType.TypeKind of
|
||||
tkClass:
|
||||
begin
|
||||
if (APropType.Handle = TypeInfo(TStream)) or
|
||||
(APropType.Handle = TypeInfo(TMemoryStream)) or
|
||||
(APropType.Handle = TypeInfo(TStringStream)) then
|
||||
Result := stString
|
||||
else
|
||||
Result := stObject;
|
||||
end;
|
||||
tkArray:
|
||||
Result := stArray;
|
||||
tkString, tkUString, tkChar:
|
||||
Result := stString;
|
||||
tkRecord:
|
||||
begin
|
||||
if APropType.Handle = TypeInfo(TGUID) then
|
||||
Result := stGuid
|
||||
end;
|
||||
tkInteger:
|
||||
Result := stInteger;
|
||||
tkInt64:
|
||||
Result := stInt64;
|
||||
tkEnumeration:
|
||||
begin
|
||||
if APropType.Handle = TypeInfo(Boolean) then
|
||||
Result := stBoolean
|
||||
else
|
||||
Result := stEnumeration;
|
||||
end;
|
||||
tkFloat:
|
||||
begin
|
||||
if APropType.Handle = TypeInfo(TDateTime) then
|
||||
Result := stDateTime
|
||||
else if APropType.Handle = TypeInfo(TDate) then
|
||||
Result := stDate
|
||||
else if APropType.Handle = TypeInfo(TTime) then
|
||||
Result := stTime
|
||||
else
|
||||
Result := stNumber;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
class function TMVCSwagger.GetJWTAuthenticationPath(const AJWTUrlSegment: string): TSwagPath;
|
||||
var
|
||||
LSwagPathOp: TSwagPathOperation;
|
||||
LSwagResponse: TSwagResponse;
|
||||
begin
|
||||
LSwagPathOp := TSwagPathOperation.Create;
|
||||
LSwagPathOp.Tags.Add('JWT Authentication');
|
||||
LSwagPathOp.Operation := ohvPost;
|
||||
LSwagPathOp.Security.Add(SECURITY_BASIC_NAME);
|
||||
LSwagPathOp.Description := 'Create JSON Web Token';
|
||||
LSwagPathOp.Produces.Add(TMVCMediaType.APPLICATION_JSON);
|
||||
|
||||
LSwagResponse := TSwagResponse.Create;
|
||||
LSwagResponse.StatusCode := HTTP_STATUS.Unauthorized.ToString;
|
||||
LSwagResponse.Description := 'Invalid authorization type';
|
||||
LSwagPathOp.Responses.Add(LSwagResponse.StatusCode, LSwagResponse);
|
||||
|
||||
LSwagResponse := TSwagResponse.Create;
|
||||
LSwagResponse.StatusCode := HTTP_STATUS.Forbidden.ToString;
|
||||
LSwagResponse.Description := 'Forbidden';
|
||||
LSwagPathOp.Responses.Add(LSwagResponse.StatusCode, LSwagResponse);
|
||||
|
||||
LSwagResponse := TSwagResponse.Create;
|
||||
LSwagResponse.StatusCode := HTTP_STATUS.InternalServerError.ToString;
|
||||
LSwagResponse.Description := 'Internal server error';
|
||||
LSwagPathOp.Responses.Add(LSwagResponse.StatusCode, LSwagResponse);
|
||||
|
||||
LSwagResponse := TSwagResponse.Create;
|
||||
LSwagResponse.StatusCode := HTTP_STATUS.OK.ToString;
|
||||
LSwagResponse.Description := 'OK';
|
||||
LSwagResponse.Schema.JsonSchema := TJSONObject.ParseJSONValue(JWT_JSON_SCHEMA) as TJSONObject;
|
||||
LSwagPathOp.Responses.Add(LSwagResponse.StatusCode, LSwagResponse);
|
||||
|
||||
Result := TSwagPath.Create;
|
||||
Result.Uri := AJwtUrlSegment;
|
||||
Result.Operations.Add(LSwagPathOp);
|
||||
end;
|
||||
|
||||
class function TMVCSwagger.GetMVCSwagParamsFromMethod(const AMethod: TRttiMethod): TArray<MVCSwagParamAttribute>;
|
||||
var
|
||||
LAttr: TCustomAttribute;
|
||||
begin
|
||||
SetLength(Result, 0);
|
||||
for LAttr in AMethod.GetAttributes do
|
||||
begin
|
||||
if LAttr is MVCSwagParamAttribute then
|
||||
begin
|
||||
Insert([MVCSwagParamAttribute(LAttr)], Result, High(Result));
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
class function TMVCSwagger.GetParamsFromMethod(const AResourcePath: string; const AMethod: TRttiMethod):
|
||||
TArray<TSwagRequestParameter>;
|
||||
|
||||
function TryGetMVCPathParamByName(const AParams: TArray<MVCSwagParamAttribute>;
|
||||
const
|
||||
AParamName:
|
||||
string;
|
||||
out AMVCParam: MVCSwagParamAttribute;
|
||||
out AIndex: Integer): Boolean;
|
||||
var
|
||||
I: Integer;
|
||||
begin
|
||||
Result := False;
|
||||
AMVCParam := nil;
|
||||
AIndex := - 1;
|
||||
for I := Low(AParams) to High(AParams) do
|
||||
if SameText(AParams[I].ParamName, AParamName) and (AParams[I].ParamLocation = plPath) then
|
||||
begin
|
||||
AMVCParam := AParams[I];
|
||||
AIndex := I;
|
||||
Exit(True);
|
||||
end;
|
||||
end;
|
||||
|
||||
var
|
||||
LMatches: TMatchCollection;
|
||||
LMatch: TMatch;
|
||||
LParamName: string;
|
||||
LMethodParam: TRttiParameter;
|
||||
LSwagParam: TSwagRequestParameter;
|
||||
LMVCSwagParams: TArray<MVCSwagParamAttribute>;
|
||||
LMVCParam: MVCSwagParamAttribute;
|
||||
LIndex: Integer;
|
||||
I: Integer;
|
||||
begin
|
||||
LMVCSwagParams := GetMVCSwagParamsFromMethod(AMethod);
|
||||
|
||||
SetLength(Result, 0);
|
||||
|
||||
// Path parameters
|
||||
LMatches := TRegEx.Matches(AResourcePath, '({)([\w_]+)(})', [roIgnoreCase, roMultiLine]);
|
||||
for LMatch in LMatches do
|
||||
begin
|
||||
LParamName := LMatch.Groups[2].Value;
|
||||
for LMethodParam in AMethod.GetParameters do
|
||||
begin
|
||||
if SameText(LMethodParam.Name, LParamName) then
|
||||
begin
|
||||
LSwagParam := TSwagRequestParameter.Create;
|
||||
|
||||
if TryGetMVCPathParamByName(LMVCSwagParams, LParamName, LMVCParam, LIndex) then
|
||||
begin
|
||||
LSwagParam.Name := LParamName;
|
||||
LSwagParam.InLocation := MVCParamLocationToSwagRequestParamInLocation(LMVCParam.ParamLocation);
|
||||
LSwagParam.Required := LMVCParam.Required;
|
||||
LSwagParam.TypeParameter := MVCParamTypeToSwagTypeParameter(LMVCParam.ParamType);
|
||||
LSwagParam.Description := LMVCParam.ParamDescription;
|
||||
if not LMVCParam.JsonSchema.IsEmpty then
|
||||
LSwagParam.Schema.JsonSchema := TJSONObject.ParseJSONValue(LMVCParam.JsonSchema) as TJSONObject
|
||||
else if Assigned(LMVCParam.JsonSchemaClass) then
|
||||
LSwagParam.Schema.JsonSchema := ExtractJsonSchemaFromClass(LMVCParam.JsonSchemaClass);
|
||||
Delete(LMVCSwagParams, LIndex, 1);
|
||||
end
|
||||
else
|
||||
begin
|
||||
LSwagParam.Name := LParamName;
|
||||
LSwagParam.InLocation := rpiPath;
|
||||
LSwagParam.Required := True;
|
||||
LSwagParam.TypeParameter := RttiTypeToSwagType(LMethodParam.ParamType);
|
||||
end;
|
||||
Insert([LSwagParam], Result, High(Result));
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
// Other parameters
|
||||
for I := Low(LMVCSwagParams) to High(LMVCSwagParams) do
|
||||
begin
|
||||
LSwagParam := TSwagRequestParameter.Create;
|
||||
LSwagParam.Name := LMVCSwagParams[I].ParamName;
|
||||
LSwagParam.InLocation := MVCParamLocationToSwagRequestParamInLocation(LMVCSwagParams[I].ParamLocation);
|
||||
LSwagParam.Required := LMVCSwagParams[I].Required;
|
||||
LSwagParam.TypeParameter := MVCParamTypeToSwagTypeParameter(LMVCSwagParams[I].ParamType);
|
||||
LSwagParam.Description := LMVCSwagParams[I].ParamDescription;
|
||||
if not LMVCSwagParams[I].JsonSchema.IsEmpty then
|
||||
LSwagParam.Schema.JsonSchema := TJSONObject.ParseJSONValue(LMVCSwagParams[I].JsonSchema) as TJSONObject
|
||||
else if Assigned(LMVCSwagParams[I].JsonSchemaClass) then
|
||||
LSwagParam.Schema.JsonSchema := ExtractJsonSchemaFromClass(LMVCSwagParams[I].JsonSchemaClass);
|
||||
|
||||
Insert([LSwagParam], Result, High(Result));
|
||||
end;
|
||||
|
||||
end;
|
||||
|
||||
class function TMVCSwagger.MethodRequiresAuthentication(const AMethod: TRttiMethod; const AType: TRttiType): Boolean;
|
||||
var
|
||||
LAttr: TCustomAttribute;
|
||||
begin
|
||||
Result := False;
|
||||
|
||||
for LAttr in AMethod.GetAttributes do
|
||||
if LAttr is MVCRequiresAuthenticationAttribute then
|
||||
Exit(True);
|
||||
|
||||
for LAttr in AType.GetAttributes do
|
||||
if LAttr is MVCRequiresAuthenticationAttribute then
|
||||
Exit(True);
|
||||
end;
|
||||
|
||||
class function TMVCSwagger.MVCHttpMethodToSwagPathOperation(const AMVCHTTPMethod: TMVCHTTPMethodType):
|
||||
TSwagPathTypeOperation;
|
||||
begin
|
||||
case AMVCHTTPMethod of
|
||||
httpGET:
|
||||
Result := ohvGet;
|
||||
httpPOST:
|
||||
Result := ohvPost;
|
||||
httpPUT:
|
||||
Result := ohvPut;
|
||||
httpDELETE:
|
||||
Result := ohvDelete;
|
||||
httpHEAD:
|
||||
Result := ohvHead;
|
||||
httpOPTIONS:
|
||||
Result := ohvOptions;
|
||||
httpPATCH:
|
||||
Result := ohvPatch;
|
||||
else
|
||||
Result := ohvNotDefined;
|
||||
end;
|
||||
end;
|
||||
|
||||
class function TMVCSwagger.MVCParamLocationToSwagRequestParamInLocation(const AMVCSwagParamLocation: TMVCSwagParamLocation)
|
||||
: TSwagRequestParameterInLocation;
|
||||
begin
|
||||
case AMVCSwagParamLocation of
|
||||
plQuery:
|
||||
Result := rpiQuery;
|
||||
plHeader:
|
||||
Result := rpiHeader;
|
||||
plPath:
|
||||
Result := rpiPath;
|
||||
plFormData:
|
||||
Result := rpiFormData;
|
||||
plBody:
|
||||
Result := rpiBody;
|
||||
else
|
||||
Result := rpiNotDefined;
|
||||
end;
|
||||
end;
|
||||
|
||||
class function TMVCSwagger.MVCParamTypeToSwagTypeParameter(const AMVSwagParamType: TMVCSwagParamType): TSwagTypeParameter;
|
||||
begin
|
||||
case AMVSwagParamType of
|
||||
ptString:
|
||||
Result := stpString;
|
||||
ptNumber:
|
||||
Result := stpNumber;
|
||||
ptInteger:
|
||||
Result := stpInteger;
|
||||
ptBoolean:
|
||||
Result := stpBoolean;
|
||||
ptArray:
|
||||
Result := stpArray;
|
||||
ptFile:
|
||||
Result := stpFile;
|
||||
else
|
||||
Result := stpNotDefined;
|
||||
end;
|
||||
end;
|
||||
|
||||
class function TMVCSwagger.MVCPathToSwagPath(const AResourcePath: string): string;
|
||||
begin
|
||||
Result := TRegEx.Replace(AResourcePath, '(\([($])([\w_]+)([)])', '{\2}', [roIgnoreCase, roMultiLine]);
|
||||
end;
|
||||
|
||||
{ MVCSwagSummary }
|
||||
|
||||
constructor MVCSwagSummaryAttribute.Create(const ATags, ADescription: string; const APathId: string;
|
||||
ADeprecated: Boolean);
|
||||
begin
|
||||
FTags := ATags;
|
||||
FDescription := ADescription;
|
||||
FPathId := APathId;
|
||||
FDeprecated := ADeprecated;
|
||||
end;
|
||||
|
||||
function MVCSwagSummaryAttribute.GetTags: TArray<string>;
|
||||
begin
|
||||
Result := FTags.Split([',']);
|
||||
end;
|
||||
|
||||
{ MVCSwagResponsesAttribute }
|
||||
|
||||
constructor MVCSwagResponsesAttribute.Create(const AStatusCode: Integer; const ADescription: string;
|
||||
const AJsonSchema: string);
|
||||
begin
|
||||
FStatusCode := AStatusCode;
|
||||
FDescription := ADescription;
|
||||
FJsonSchema := AJsonSchema;
|
||||
FJsonSchemaClass := nil;
|
||||
end;
|
||||
|
||||
constructor MVCSwagResponsesAttribute.Create(const AStatusCode: Integer; const ADescription: string;
|
||||
const AJsonSchemaClass: TClass);
|
||||
begin
|
||||
Create(AStatusCode, ADescription, '');
|
||||
FJsonSchemaClass := AJsonSchemaClass;
|
||||
end;
|
||||
|
||||
{ MVCSwagParamAttribute }
|
||||
|
||||
constructor MVCSwagParamAttribute.Create(const AParamLocation: TMVCSwagParamLocation; const AParamName,
|
||||
AParamDescription: string; const AParamType: TMVCSwagParamType; const ARequired: Boolean; const AJsonSchema: string);
|
||||
begin
|
||||
FParamLocation := AParamLocation;
|
||||
FParamName := AParamName;
|
||||
FParamDescription := AParamDescription;
|
||||
FParamType := AParamType;
|
||||
FRequired := ARequired;
|
||||
FJsonSchema := AJsonSchema;
|
||||
FJsonSchemaClass := nil;
|
||||
end;
|
||||
|
||||
constructor MVCSwagParamAttribute.Create(const AParamLocation: TMVCSwagParamLocation; const AParamName,
|
||||
AParamDescription: string; const AJsonSchemaClass: TClass; const AParamType: TMVCSwagParamType;
|
||||
const ARequired: Boolean);
|
||||
begin
|
||||
Create(AParamLocation, AParamName, AParamDescription, AParamType, ARequired, '');
|
||||
FJsonSchemaClass := AJsonSchemaClass;
|
||||
end;
|
||||
|
||||
{ MVCSwagJsonSchemaFieldAttribute }
|
||||
|
||||
constructor MVCSwagJsonSchemaFieldAttribute.Create(const ASchemaFieldType: TMVCSwagSchemaType;
|
||||
const AFieldName, ADescription: string; const ARequired, ANullable: Boolean);
|
||||
begin
|
||||
FSchemaFieldType := ASchemaFieldType;
|
||||
FFieldName := AFieldName;
|
||||
FDescription := ADescription;
|
||||
FRequired := ARequired;
|
||||
FNullable := ANullable;
|
||||
end;
|
||||
|
||||
constructor MVCSwagJsonSchemaFieldAttribute.Create(const AFieldName, ADescription: string; const ARequired,
|
||||
ANullable: Boolean);
|
||||
begin
|
||||
Create(stUnknown, AFieldName, ADescription, ARequired, ANullable);
|
||||
end;
|
||||
|
||||
{ TFieldSchemaDefinition }
|
||||
|
||||
class function TFieldSchemaDefinition.Create: TFieldSchemaDefinition;
|
||||
begin
|
||||
Result.SchemaFieldType := stUnknown;
|
||||
Result.FieldName := '';
|
||||
Result.Description := '';
|
||||
Result.Required := False;
|
||||
Result.Nullable := False;
|
||||
end;
|
||||
|
||||
end.
|
Loading…
Reference in New Issue
Block a user