Merge remote-tracking branch 'joaoduarte1/middlewareswagger_dev' into SwagDoc

This commit is contained in:
Geoffrey Smith 2019-08-06 11:01:57 +10:00
commit e83f025b09
24 changed files with 2818 additions and 6 deletions

View File

@ -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 +

View 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.

View 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

View 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.

View 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.

View 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.

View 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.

View 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>

View File

@ -0,0 +1,8 @@
object WebModule1: TWebModule1
OldCreateOrder = False
OnCreate = WebModuleCreate
OnDestroy = WebModuleDestroy
Actions = <>
Height = 230
Width = 415
end

View 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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 665 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 B

View 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>

View 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>

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

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

View 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.

View 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.