├── .gitignore
├── Demo
├── Demo.dpr
├── Demo.dproj
├── Demo.res
├── MainU.dfm
├── MainU.pas
├── PersonU.pas
├── Pkg.Json.DTO.pas
└── RootU.pas
├── LICENSE
├── ORM
├── DelphiRestOrm.ORM.IRequest.pas
├── DelphiRestOrm.ORM.Request.pas
├── DelphiRestOrm.ORM.Response.pas
└── Helpers
│ ├── DelphiRestOrm.ORM.Helper.Azure.pas
│ ├── DelphiRestOrm.ORM.Helper.GenericListHelper.pas
│ ├── DelphiRestOrm.ORM.Helper.ObjectContainer.pas
│ └── DelphiRestOrm.ORM.Helper.ThreadingEx.pas
├── README.md
└── RestServer
├── .vs
└── RestServer
│ ├── DesignTimeBuild
│ └── .dtbcache.v2
│ ├── config
│ └── applicationhost.config
│ └── v16
│ └── .suo
├── Demo Data
├── Create Table.sql
└── DemoData.json
├── RestServer.sln
└── RestServer
├── Controllers
└── ContactController.cs
├── Helpers
├── BasicAuthenticationHandler.cs
└── ExtensionMethods.cs
├── Models
├── DemoDataContext.cs
├── Person.cs
└── User.cs
├── Program.cs
├── Properties
└── launchSettings.json
├── RestServer.csproj
├── RestServer.csproj.user
├── Services
└── UserService.cs
├── Startup.cs
├── appsettings.Development.json
└── appsettings.json
/.gitignore:
--------------------------------------------------------------------------------
1 | # Uncomment these types if you want even more clean repository. But be careful.
2 | # It can make harm to an existing project source. Read explanations below.
3 | #
4 | # Resource files are binaries containing manifest, project icon and version info.
5 | # They can not be viewed as text or compared by diff-tools. Consider replacing them with .rc files.
6 | #*.res
7 | #
8 | # Type library file (binary). In old Delphi versions it should be stored.
9 | # Since Delphi 2009 it is produced from .ridl file and can safely be ignored.
10 | #*.tlb
11 | #
12 | # Diagram Portfolio file. Used by the diagram editor up to Delphi 7.
13 | # Uncomment this if you are not using diagrams or use newer Delphi version.
14 | #*.ddp
15 | #
16 | # Visual LiveBindings file. Added in Delphi XE2.
17 | # Uncomment this if you are not using LiveBindings Designer.
18 | #*.vlb
19 | #
20 | # Deployment Manager configuration file for your project. Added in Delphi XE2.
21 | # Uncomment this if it is not mobile development and you do not use remote debug feature.
22 | #*.deployproj
23 | #
24 | # C++ object files produced when C/C++ Output file generation is configured.
25 | # Uncomment this if you are not using external objects (zlib library for example).
26 | #*.obj
27 | #
28 |
29 | # Delphi compiler-generated binaries (safe to delete)
30 | *.exe
31 | *.dll
32 | *.bpl
33 | *.bpi
34 | *.dcp
35 | *.so
36 | *.apk
37 | *.drc
38 | *.map
39 | *.dres
40 | *.rsm
41 | *.tds
42 | *.dcu
43 | *.lib
44 | *.a
45 | *.o
46 | *.ocx
47 |
48 | # Delphi autogenerated files (duplicated info)
49 | *.cfg
50 | *.hpp
51 | *Resource.rc
52 |
53 | # Delphi local files (user-specific info)
54 | *.local
55 | *.identcache
56 | *.projdata
57 | *.tvsconfig
58 | *.dsk
59 |
60 | # Delphi history and backups
61 | __history/
62 | __recovery/
63 | *.~*
64 |
65 | # Castalia statistics file (since XE7 Castalia is distributed with Delphi)
66 | *.stat
67 |
68 | # Boss dependency manager vendor folder https://github.com/HashLoad/boss
69 | modules/
70 |
71 | *.skincfg
72 |
73 | RestServer/RestServer/bin/
74 | RestServer/RestServer/obj/
75 |
--------------------------------------------------------------------------------
/Demo/Demo.dpr:
--------------------------------------------------------------------------------
1 | program Demo;
2 |
3 | uses
4 | Vcl.Forms,
5 | MainU in 'MainU.pas' {Form59},
6 | DelphiRestOrm.ORM.Request in '..\ORM\DelphiRestOrm.ORM.Request.pas',
7 | DelphiRestOrm.ORM.Helper.ObjectContainer in '..\ORM\Helpers\DelphiRestOrm.ORM.Helper.ObjectContainer.pas',
8 | DelphiRestOrm.ORM.IRequest in '..\ORM\DelphiRestOrm.ORM.IRequest.pas',
9 | PersonU in 'PersonU.pas',
10 | DelphiRestOrm.ORM.Response in '..\ORM\DelphiRestOrm.ORM.Response.pas',
11 | DelphiRestOrm.ORM.Helper.GenericListHelper in '..\ORM\Helpers\DelphiRestOrm.ORM.Helper.GenericListHelper.pas',
12 | DelphiRestOrm.ORM.Helper.Azure in '..\ORM\Helpers\DelphiRestOrm.ORM.Helper.Azure.pas',
13 | DelphiRestOrm.ORM.Helper.ThreadingEx in '..\ORM\Helpers\DelphiRestOrm.ORM.Helper.ThreadingEx.pas';
14 |
15 | {$R *.res}
16 |
17 | begin
18 | ReportMemoryLeaksOnShutdown := True;
19 | Application.Initialize;
20 | Application.MainFormOnTaskbar := true;
21 | Application.CreateForm(TForm59, Form59);
22 | Application.Run;
23 |
24 | end.
25 |
--------------------------------------------------------------------------------
/Demo/Demo.dproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | {7DD92F11-8410-406D-861F-FE71C43E6588}
4 | 19.0
5 | VCL
6 | True
7 | Debug
8 | Win32
9 | 1
10 | Application
11 | Demo.dpr
12 |
13 |
14 | true
15 |
16 |
17 | true
18 | Base
19 | true
20 |
21 |
22 | true
23 | Base
24 | true
25 |
26 |
27 | true
28 | Base
29 | true
30 |
31 |
32 | true
33 | Cfg_1
34 | true
35 | true
36 |
37 |
38 | true
39 | Base
40 | true
41 |
42 |
43 | true
44 | Cfg_2
45 | true
46 | true
47 |
48 |
49 | .\$(Platform)\$(Config)
50 | .\$(Platform)\$(Config)
51 | false
52 | false
53 | false
54 | false
55 | false
56 | System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)
57 | $(BDS)\bin\delphi_PROJECTICON.ico
58 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png
59 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png
60 | Demo
61 |
62 |
63 | DBXSqliteDriver;DBXDb2Driver;vclactnband;vclFireDAC;tethering;FireDACADSDriver;cxLibraryRS27;dxRibbonCustomizationFormRS27;FireDACMSSQLDriver;vcltouch;vcldb;svn;dxPScxExtCommonRS27;cxTreeListRS27;dxPScxSchedulerLnkRS27;dxRichEditDocumentModelRS27;dxPsPrVwAdvRS27;FireDACDBXDriver;vclx;dxPSdxFCLnkRS27;dxSpellCheckerRS27;dxPDFViewerRS27;RESTBackendComponents;VCLRESTComponents;dxWizardControlRS27;cxSchedulerTreeBrowserRS27;vclie;bindengine;CloudService;dxBarExtDBItemsRS27;FireDACMySQLDriver;cxExportRS27;DataSnapClient;cxSchedulerWebServiceStorageRS27;bindcompdbx;IndyIPServer;DBXSybaseASEDriver;dxPScxPCProdRS27;IndySystem;dxHttpIndyRequestRS27;dxFlowChartRS27;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;dxmdsRS27;Jcl;dxPSPrVwRibbonRS27;dxCoreRS27;emshosting;DBXOdbcDriver;FireDACTDataDriver;FMXTee;cxSchedulerRibbonStyleEventEditorRS27;soaprtl;DbxCommonDriver;dxRichEditCoreRS27;dxCloudServiceLibraryRS27;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;rtl;emsserverresource;DbxClientDriver;dxdbtrRS27;DBXSybaseASADriver;dxdborRS27;dxPSDBTeeChartRS27;appanalytics;dxSpreadSheetCoreRS27;dxRichEditControlCoreRS27;dxGDIPlusRS27;IndyIPClient;dxFireDACServerModeRS27;dxFlowChartAdvancedCustomizeFormRS27;bindcompvcl;dxServerModeRS27;TeeUI;dxPSLnksRS27;dxorgcRS27;VclSmp;dxDBXServerModeRS27;FireDACODBCDriver;JclVcl;DataSnapIndy10ServerTransport;cxGridRS27;DataSnapProviderClient;FireDACMongoDBDriver;dxFireDACEMFRS27;dxtrmdRS27;dxSpreadSheetCoreConditionalFormattingDialogsRS27;RESTComponents;DataSnapServerMidas;DBXInterBaseDriver;dxSpreadSheetConditionalFormattingDialogsRS27;dxGaugeControlRS27;dxSpreadSheetReportDesignerRS27;dxSpreadSheetRS27;bindcompvclsmp;emsclientfiredac;DataSnapFireDAC;svnui;cxPivotGridOLAPRS27;dxPSRichEditControlLnkRS27;dxBarDBNavRS27;DBXMSSQLDriver;cxPivotGridRS27;dxADOServerModeRS27;DatasnapConnectorsFreePascal;bindcompfmx;DBXOracleDriver;inetdb;dxFlowChartDesignerRS27;FmxTeeUI;emsedge;fmx;FireDACIBDriver;fmxdae;vcledge;dbexpress;IndyCore;dxRibbonRS27;dxOrgChartAdvancedCustomizeFormRS27;dsnap;emsclient;DataSnapCommon;FireDACCommon;dxTileControlRS27;dxBarExtItemsRS27;DataSnapConnectors;cxSchedulerRS27;cxGridEMFRS27;soapserver;JclDeveloperTools;dxRichEditControlRS27;dxPScxTLLnkRS27;FireDACOracleDriver;DBXMySQLDriver;dxFlowChartLayoutsRS27;dxPSCoreRS27;dxADOEMFRS27;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;dxPScxPivotGridLnkRS27;inet;cxPivotGridChartRS27;IndyIPCommon;dxPSdxOCLnkRS27;vcl;FireDACDb2Driver;dxMapControlRS27;dxPSdxDBOCLnkRS27;dxComnRS27;dxPSdxGaugeControlLnkRS27;dxEMFRS27;TeeDB;FireDAC;cxTreeListdxBarPopupMenuRS27;dxPScxVGridLnkRS27;dxPSdxPDFViewerLnkRS27;dxPSdxSpreadSheetLnkRS27;FireDACSqliteDriver;FireDACPgDriver;FireDACASADriver;dxTabbedMDIRS27;Tee;DataSnapServer;vclwinx;FireDACDSDriver;dxPScxCommonRS27;CustomIPTransport;vcldsnap;dxPSTeeChartRS27;dxSkinsCoreRS27;dxPScxGridLnkRS27;bindcomp;DBXInformixDriver;cxVerticalGridRS27;cxSchedulerGridRS27;dxDockingRS27;dxNavBarRS27;dbxcds;adortl;dsnapxml;dbrtl;IndyProtocols;inetdbxpress;dxBarRS27;dxPSdxLCLnkRS27;dxPSdxMapControlLnkRS27;JclContainers;dxPSdxDBTVLnkRS27;fmxase;$(DCC_UsePackage)
64 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
65 | Debug
66 | true
67 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=
68 | 1033
69 | $(BDS)\bin\default_app.manifest
70 |
71 |
72 | DBXSqliteDriver;DBXDb2Driver;vclactnband;vclFireDAC;tethering;FireDACADSDriver;cxLibraryRS27;dxRibbonCustomizationFormRS27;FireDACMSSQLDriver;vcltouch;vcldb;dxPScxExtCommonRS27;cxTreeListRS27;dxPScxSchedulerLnkRS27;dxRichEditDocumentModelRS27;dxPsPrVwAdvRS27;FireDACDBXDriver;vclx;dxPSdxFCLnkRS27;dxSpellCheckerRS27;dxPDFViewerRS27;RESTBackendComponents;VCLRESTComponents;dxWizardControlRS27;cxSchedulerTreeBrowserRS27;vclie;bindengine;CloudService;dxBarExtDBItemsRS27;FireDACMySQLDriver;cxExportRS27;DataSnapClient;cxSchedulerWebServiceStorageRS27;bindcompdbx;IndyIPServer;DBXSybaseASEDriver;dxPScxPCProdRS27;IndySystem;dxHttpIndyRequestRS27;dxFlowChartRS27;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;dxmdsRS27;dxPSPrVwRibbonRS27;dxCoreRS27;emshosting;DBXOdbcDriver;FireDACTDataDriver;FMXTee;cxSchedulerRibbonStyleEventEditorRS27;soaprtl;DbxCommonDriver;dxRichEditCoreRS27;dxCloudServiceLibraryRS27;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;rtl;emsserverresource;DbxClientDriver;dxdbtrRS27;DBXSybaseASADriver;dxdborRS27;dxPSDBTeeChartRS27;appanalytics;dxSpreadSheetCoreRS27;dxRichEditControlCoreRS27;dxGDIPlusRS27;IndyIPClient;dxFireDACServerModeRS27;dxFlowChartAdvancedCustomizeFormRS27;bindcompvcl;dxServerModeRS27;TeeUI;dxPSLnksRS27;dxorgcRS27;VclSmp;dxDBXServerModeRS27;FireDACODBCDriver;DataSnapIndy10ServerTransport;cxGridRS27;DataSnapProviderClient;FireDACMongoDBDriver;dxFireDACEMFRS27;dxtrmdRS27;dxSpreadSheetCoreConditionalFormattingDialogsRS27;RESTComponents;DataSnapServerMidas;DBXInterBaseDriver;dxSpreadSheetConditionalFormattingDialogsRS27;dxGaugeControlRS27;dxSpreadSheetReportDesignerRS27;dxSpreadSheetRS27;bindcompvclsmp;emsclientfiredac;DataSnapFireDAC;cxPivotGridOLAPRS27;dxPSRichEditControlLnkRS27;dxBarDBNavRS27;DBXMSSQLDriver;cxPivotGridRS27;dxADOServerModeRS27;DatasnapConnectorsFreePascal;bindcompfmx;DBXOracleDriver;inetdb;dxFlowChartDesignerRS27;FmxTeeUI;emsedge;fmx;FireDACIBDriver;fmxdae;vcledge;dbexpress;IndyCore;dxRibbonRS27;dxOrgChartAdvancedCustomizeFormRS27;dsnap;emsclient;DataSnapCommon;FireDACCommon;dxTileControlRS27;dxBarExtItemsRS27;DataSnapConnectors;cxSchedulerRS27;cxGridEMFRS27;soapserver;dxRichEditControlRS27;dxPScxTLLnkRS27;FireDACOracleDriver;DBXMySQLDriver;dxFlowChartLayoutsRS27;dxPSCoreRS27;dxADOEMFRS27;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;dxPScxPivotGridLnkRS27;inet;cxPivotGridChartRS27;IndyIPCommon;dxPSdxOCLnkRS27;vcl;FireDACDb2Driver;dxMapControlRS27;dxPSdxDBOCLnkRS27;dxComnRS27;dxPSdxGaugeControlLnkRS27;dxEMFRS27;TeeDB;FireDAC;cxTreeListdxBarPopupMenuRS27;dxPScxVGridLnkRS27;dxPSdxPDFViewerLnkRS27;dxPSdxSpreadSheetLnkRS27;FireDACSqliteDriver;FireDACPgDriver;FireDACASADriver;dxTabbedMDIRS27;Tee;DataSnapServer;vclwinx;FireDACDSDriver;dxPScxCommonRS27;CustomIPTransport;vcldsnap;dxPSTeeChartRS27;dxSkinsCoreRS27;dxPScxGridLnkRS27;bindcomp;DBXInformixDriver;cxVerticalGridRS27;cxSchedulerGridRS27;dxDockingRS27;dxNavBarRS27;dbxcds;adortl;dsnapxml;dbrtl;IndyProtocols;inetdbxpress;dxBarRS27;dxPSdxLCLnkRS27;dxPSdxMapControlLnkRS27;dxPSdxDBTVLnkRS27;fmxase;$(DCC_UsePackage)
73 |
74 |
75 | DEBUG;$(DCC_Define)
76 | true
77 | false
78 | true
79 | true
80 | true
81 |
82 |
83 | false
84 | true
85 | PerMonitorV2
86 |
87 |
88 | false
89 | RELEASE;$(DCC_Define)
90 | 0
91 | 0
92 |
93 |
94 | true
95 | PerMonitorV2
96 |
97 |
98 |
99 | MainSource
100 |
101 |
102 |
103 | dfm
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 | Cfg_2
115 | Base
116 |
117 |
118 | Base
119 |
120 |
121 | Cfg_1
122 | Base
123 |
124 |
125 |
126 | Delphi.Personality.12
127 | Application
128 |
129 |
130 |
131 | Demo.dpr
132 |
133 |
134 |
135 | True
136 | False
137 |
138 |
139 |
140 |
141 | Demo.exe
142 | true
143 |
144 |
145 |
146 |
147 | 1
148 |
149 |
150 | Contents\MacOS
151 | 1
152 |
153 |
154 | 0
155 |
156 |
157 |
158 |
159 | classes
160 | 1
161 |
162 |
163 | classes
164 | 1
165 |
166 |
167 |
168 |
169 | res\xml
170 | 1
171 |
172 |
173 | res\xml
174 | 1
175 |
176 |
177 |
178 |
179 | library\lib\armeabi-v7a
180 | 1
181 |
182 |
183 |
184 |
185 | library\lib\armeabi
186 | 1
187 |
188 |
189 | library\lib\armeabi
190 | 1
191 |
192 |
193 |
194 |
195 | library\lib\armeabi-v7a
196 | 1
197 |
198 |
199 |
200 |
201 | library\lib\mips
202 | 1
203 |
204 |
205 | library\lib\mips
206 | 1
207 |
208 |
209 |
210 |
211 | library\lib\armeabi-v7a
212 | 1
213 |
214 |
215 | library\lib\arm64-v8a
216 | 1
217 |
218 |
219 |
220 |
221 | library\lib\armeabi-v7a
222 | 1
223 |
224 |
225 |
226 |
227 | res\drawable
228 | 1
229 |
230 |
231 | res\drawable
232 | 1
233 |
234 |
235 |
236 |
237 | res\values
238 | 1
239 |
240 |
241 | res\values
242 | 1
243 |
244 |
245 |
246 |
247 | res\values-v21
248 | 1
249 |
250 |
251 | res\values-v21
252 | 1
253 |
254 |
255 |
256 |
257 | res\values
258 | 1
259 |
260 |
261 | res\values
262 | 1
263 |
264 |
265 |
266 |
267 | res\drawable
268 | 1
269 |
270 |
271 | res\drawable
272 | 1
273 |
274 |
275 |
276 |
277 | res\drawable-xxhdpi
278 | 1
279 |
280 |
281 | res\drawable-xxhdpi
282 | 1
283 |
284 |
285 |
286 |
287 | res\drawable-ldpi
288 | 1
289 |
290 |
291 | res\drawable-ldpi
292 | 1
293 |
294 |
295 |
296 |
297 | res\drawable-mdpi
298 | 1
299 |
300 |
301 | res\drawable-mdpi
302 | 1
303 |
304 |
305 |
306 |
307 | res\drawable-hdpi
308 | 1
309 |
310 |
311 | res\drawable-hdpi
312 | 1
313 |
314 |
315 |
316 |
317 | res\drawable-xhdpi
318 | 1
319 |
320 |
321 | res\drawable-xhdpi
322 | 1
323 |
324 |
325 |
326 |
327 | res\drawable-mdpi
328 | 1
329 |
330 |
331 | res\drawable-mdpi
332 | 1
333 |
334 |
335 |
336 |
337 | res\drawable-hdpi
338 | 1
339 |
340 |
341 | res\drawable-hdpi
342 | 1
343 |
344 |
345 |
346 |
347 | res\drawable-xhdpi
348 | 1
349 |
350 |
351 | res\drawable-xhdpi
352 | 1
353 |
354 |
355 |
356 |
357 | res\drawable-xxhdpi
358 | 1
359 |
360 |
361 | res\drawable-xxhdpi
362 | 1
363 |
364 |
365 |
366 |
367 | res\drawable-xxxhdpi
368 | 1
369 |
370 |
371 | res\drawable-xxxhdpi
372 | 1
373 |
374 |
375 |
376 |
377 | res\drawable-small
378 | 1
379 |
380 |
381 | res\drawable-small
382 | 1
383 |
384 |
385 |
386 |
387 | res\drawable-normal
388 | 1
389 |
390 |
391 | res\drawable-normal
392 | 1
393 |
394 |
395 |
396 |
397 | res\drawable-large
398 | 1
399 |
400 |
401 | res\drawable-large
402 | 1
403 |
404 |
405 |
406 |
407 | res\drawable-xlarge
408 | 1
409 |
410 |
411 | res\drawable-xlarge
412 | 1
413 |
414 |
415 |
416 |
417 | res\values
418 | 1
419 |
420 |
421 | res\values
422 | 1
423 |
424 |
425 |
426 |
427 | 1
428 |
429 |
430 | Contents\MacOS
431 | 1
432 |
433 |
434 | 0
435 |
436 |
437 |
438 |
439 | Contents\MacOS
440 | 1
441 | .framework
442 |
443 |
444 | Contents\MacOS
445 | 1
446 | .framework
447 |
448 |
449 | 0
450 |
451 |
452 |
453 |
454 | 1
455 | .dylib
456 |
457 |
458 | 1
459 | .dylib
460 |
461 |
462 | 1
463 | .dylib
464 |
465 |
466 | Contents\MacOS
467 | 1
468 | .dylib
469 |
470 |
471 | Contents\MacOS
472 | 1
473 | .dylib
474 |
475 |
476 | 0
477 | .dll;.bpl
478 |
479 |
480 |
481 |
482 | 1
483 | .dylib
484 |
485 |
486 | 1
487 | .dylib
488 |
489 |
490 | 1
491 | .dylib
492 |
493 |
494 | Contents\MacOS
495 | 1
496 | .dylib
497 |
498 |
499 | Contents\MacOS
500 | 1
501 | .dylib
502 |
503 |
504 | 0
505 | .bpl
506 |
507 |
508 |
509 |
510 | 0
511 |
512 |
513 | 0
514 |
515 |
516 | 0
517 |
518 |
519 | 0
520 |
521 |
522 | 0
523 |
524 |
525 | Contents\Resources\StartUp\
526 | 0
527 |
528 |
529 | Contents\Resources\StartUp\
530 | 0
531 |
532 |
533 | 0
534 |
535 |
536 |
537 |
538 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
539 | 1
540 |
541 |
542 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
543 | 1
544 |
545 |
546 |
547 |
548 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
549 | 1
550 |
551 |
552 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
553 | 1
554 |
555 |
556 |
557 |
558 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
559 | 1
560 |
561 |
562 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
563 | 1
564 |
565 |
566 |
567 |
568 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
569 | 1
570 |
571 |
572 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
573 | 1
574 |
575 |
576 |
577 |
578 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
579 | 1
580 |
581 |
582 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
583 | 1
584 |
585 |
586 |
587 |
588 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
589 | 1
590 |
591 |
592 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
593 | 1
594 |
595 |
596 |
597 |
598 | 1
599 |
600 |
601 | 1
602 |
603 |
604 |
605 |
606 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
607 | 1
608 |
609 |
610 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
611 | 1
612 |
613 |
614 |
615 |
616 | 1
617 |
618 |
619 | 1
620 |
621 |
622 |
623 |
624 | ..\
625 | 1
626 |
627 |
628 | ..\
629 | 1
630 |
631 |
632 |
633 |
634 | 1
635 |
636 |
637 | 1
638 |
639 |
640 | 1
641 |
642 |
643 |
644 |
645 | ..\$(PROJECTNAME).launchscreen
646 | 64
647 |
648 |
649 | ..\$(PROJECTNAME).launchscreen
650 | 64
651 |
652 |
653 |
654 |
655 | 1
656 |
657 |
658 | 1
659 |
660 |
661 | 1
662 |
663 |
664 |
665 |
666 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
667 | 1
668 |
669 |
670 |
671 |
672 | ..\
673 | 1
674 |
675 |
676 | ..\
677 | 1
678 |
679 |
680 |
681 |
682 | Contents
683 | 1
684 |
685 |
686 | Contents
687 | 1
688 |
689 |
690 |
691 |
692 | Contents\Resources
693 | 1
694 |
695 |
696 | Contents\Resources
697 | 1
698 |
699 |
700 |
701 |
702 | library\lib\armeabi-v7a
703 | 1
704 |
705 |
706 | library\lib\arm64-v8a
707 | 1
708 |
709 |
710 | 1
711 |
712 |
713 | 1
714 |
715 |
716 | 1
717 |
718 |
719 | 1
720 |
721 |
722 | Contents\MacOS
723 | 1
724 |
725 |
726 | Contents\MacOS
727 | 1
728 |
729 |
730 | 0
731 |
732 |
733 |
734 |
735 | library\lib\armeabi-v7a
736 | 1
737 |
738 |
739 |
740 |
741 | 1
742 |
743 |
744 | 1
745 |
746 |
747 |
748 |
749 | Assets
750 | 1
751 |
752 |
753 | Assets
754 | 1
755 |
756 |
757 |
758 |
759 | Assets
760 | 1
761 |
762 |
763 | Assets
764 | 1
765 |
766 |
767 |
768 |
769 |
770 |
771 |
772 |
773 |
774 |
775 |
776 |
777 |
778 |
779 | 12
780 |
781 |
782 |
783 |
784 |
785 |
--------------------------------------------------------------------------------
/Demo/Demo.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JensBorrisholt/Delphi-REST-Orm/01cbb0ead71d3a98125e7613058e226ce76f330f/Demo/Demo.res
--------------------------------------------------------------------------------
/Demo/MainU.dfm:
--------------------------------------------------------------------------------
1 | object Form59: TForm59
2 | Left = 0
3 | Top = 0
4 | Caption = 'Form59'
5 | ClientHeight = 411
6 | ClientWidth = 852
7 | Color = clBtnFace
8 | Font.Charset = DEFAULT_CHARSET
9 | Font.Color = clWindowText
10 | Font.Height = -11
11 | Font.Name = 'Tahoma'
12 | Font.Style = []
13 | OldCreateOrder = False
14 | OnCreate = FormCreate
15 | PixelsPerInch = 96
16 | TextHeight = 13
17 | object Memo1: TMemo
18 | Left = 0
19 | Top = 0
20 | Width = 852
21 | Height = 411
22 | Align = alClient
23 | Lines.Strings = (
24 | 'Memo1')
25 | TabOrder = 0
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/Demo/MainU.pas:
--------------------------------------------------------------------------------
1 | unit MainU;
2 |
3 | interface
4 |
5 | uses
6 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
7 | Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,
8 |
9 | DelphiRestOrm.ORM.Helper.ObjectContainer;
10 |
11 | type
12 | TForm59 = class(TForm)
13 | Memo1: TMemo;
14 | procedure FormCreate(Sender: TObject);
15 | private
16 | { Private declarations }
17 |
18 | public
19 | { Public declarations }
20 | end;
21 |
22 | var
23 | Form59: TForm59;
24 |
25 | implementation
26 |
27 | uses
28 | System.Generics.Collections,
29 | DelphiRestOrm.ORM.IRequest, DelphiRestOrm.ORM.Response, DelphiRestOrm.ORM.Helper.Azure,
30 |
31 | RootU, PersonU;
32 | {$R *.dfm}
33 |
34 | procedure TForm59.FormCreate(Sender: TObject);
35 | var
36 | Container: TObjectContainer;
37 | AzureAuthenticator: TAzureAuthenticator;
38 | Person: TPerson;
39 | Persons: TObjectList;
40 | s: string;
41 | Root: TPersons;
42 | begin
43 | Memo1.Clear;
44 | Memo1.Lines.Add('** Get all **');
45 | Memo1.Lines.Add('');
46 |
47 | s := NewRequest('https://localhost:44303/Contact').Credentials('test', 'test').GET.ToString;
48 | Memo1.Lines.Add(s.Substring(0, 1000) + ' ...');
49 |
50 | Memo1.Lines.Add('');
51 | Memo1.Lines.Add('** Get single **');
52 | Memo1.Lines.Add('');
53 |
54 | s := NewRequest('https://localhost:44303/Contact').GET(8).ToString;
55 | Memo1.Lines.Add(s);
56 |
57 | Memo1.Lines.Add('');
58 | Memo1.Lines.Add('** Get All AsType **');
59 | Memo1.Lines.Add('');
60 |
61 | Persons := NewRequest('https://localhost:44303/Contact').ObjectContainer(Container).Credentials('test', 'test').GET.AsType>;
62 | Memo1.Lines.Add('(Random) Person.Address :' + Persons[Random(Persons.Count)].Address);
63 |
64 | Memo1.Lines.Add('');
65 | Memo1.Lines.Add('** Get Single AsType **');
66 | Memo1.Lines.Add('');
67 |
68 | Person := NewRequest('https://localhost:44303/Contact').ObjectContainer(Container).Credentials('test', 'test').GET(5).AsType;
69 | Memo1.Lines.Add('Person.Address :' + Person.Address);
70 |
71 |
72 | Memo1.Lines.Add('');
73 | Memo1.Lines.Add('** TJsonDTO test **');
74 | Memo1.Lines.Add('');
75 |
76 | Root := NewRequest('https://localhost:44303/Contact').ObjectContainer(Container).Credentials('test', 'test').GET.AsType;
77 | Memo1.Lines.Add('(Random) Person.Address :' + Persons.Items[Random(Root.Items.Count)].Address);
78 | (*
79 | Replace with your own Azure credentials
80 | AzureAuthenticator := TAzureAuthenticator.Create('aTenantID', 'aClientID', 'aClientSecret', 'aResourceId');
81 | Memo1.Lines.Add('');
82 | Memo1.Lines.Add('** Azure test **');
83 | Memo1.Lines.Add('');
84 | s := NewRequest('').Param(17794452).QueryParam('country', 'DK').AzureCredentials(AzureAuthenticator).GET.ToString;
85 | Memo1.Lines.Add(s);
86 |
87 | Memo1.Lines.Add('');
88 | Memo1.Lines.Add('** Azure test async **');
89 | Memo1.Lines.Add('');
90 |
91 | NewRequestAsync('',
92 | procedure(const Response: TResponse)
93 | begin
94 | Memo1.Lines.Add(Response.ToString)
95 | end).Param(17794452).QueryParam('country', 'DK').AzureCredentials((aTenantID', 'aClientID', 'aClientSecret', 'aResourceId').GET;
96 | *)
97 | Container.Free;
98 | end;
99 |
100 | end.
101 |
--------------------------------------------------------------------------------
/Demo/PersonU.pas:
--------------------------------------------------------------------------------
1 | unit PersonU;
2 |
3 | interface
4 |
5 | {$M+}
6 |
7 | type
8 | TPerson = class
9 | private
10 | FAbout: string;
11 | FAddress: string;
12 | FAge: Integer;
13 | FBalance: string;
14 | FCompany: string;
15 | FEmail: string;
16 | FEyeColor: string;
17 | FFavoriteFruit: string;
18 | FGender: string;
19 | FGreeting: string;
20 | FGuId: string;
21 | FId: string;
22 | FIndex: Integer;
23 | FIsActive: Boolean;
24 | FLatitude: Double;
25 | FLongitude: Double;
26 | FName: string;
27 | FPhone: string;
28 | FPicture: string;
29 | FRegistered: string;
30 | published
31 | property About: string read FAbout write FAbout;
32 | property Address: string read FAddress write FAddress;
33 | property Age: Integer read FAge write FAge;
34 | property Balance: string read FBalance write FBalance;
35 | property Company: string read FCompany write FCompany;
36 | property Email: string read FEmail write FEmail;
37 | property EyeColor: string read FEyeColor write FEyeColor;
38 | property FavoriteFruit: string read FFavoriteFruit write FFavoriteFruit;
39 | property Gender: string read FGender write FGender;
40 | property Greeting: string read FGreeting write FGreeting;
41 | property GuId: string read FGuId write FGuId;
42 | property Id: string read FId write FId;
43 | property Index: Integer read FIndex write FIndex;
44 | property IsActive: Boolean read FIsActive write FIsActive;
45 | property Latitude: Double read FLatitude write FLatitude;
46 | property Longitude: Double read FLongitude write FLongitude;
47 | property Name: string read FName write FName;
48 | property Phone: string read FPhone write FPhone;
49 | property Picture: string read FPicture write FPicture;
50 | property Registered: string read FRegistered write FRegistered;
51 | end;
52 |
53 | implementation
54 |
55 | end.
56 |
--------------------------------------------------------------------------------
/Demo/Pkg.Json.DTO.pas:
--------------------------------------------------------------------------------
1 | unit Pkg.Json.DTO;
2 |
3 |
4 |
5 | interface
6 |
7 | uses
8 | System.Classes, System.Json, Rest.Json, System.Generics.Collections, Rest.JsonReflect;
9 |
10 | type
11 | TArrayMapper = class
12 | protected
13 | procedure RefreshArray(aSource: TList; var aDestination: TArray);
14 | function List(var aList: TList; aSource: TArray): TList;
15 | function ObjectList(var aList: TObjectList; aSource: TArray): TObjectList;
16 | public
17 | constructor Create; virtual;
18 | end;
19 |
20 | TJsonDTO = class(TArrayMapper)
21 | private
22 | FOptions: TJsonOptions;
23 | class procedure PrettyPrintPair(aJSONValue: TJSONPair; aOutputStrings: TStrings; Last: Boolean; Indent: Integer);
24 | class procedure PrettyPrintJSON(aJSONValue: TJsonValue; aOutputStrings: TStrings; Indent: Integer = 0); overload;
25 | class procedure PrettyPrintArray(aJSONValue: TJSONArray; aOutputStrings: TStrings; Last: Boolean; Indent: Integer);
26 | protected
27 | function GetAsJson: string; virtual;
28 | procedure SetAsJson(aValue: string); virtual;
29 | public
30 | constructor Create; override;
31 | class function PrettyPrintJSON(aJson: string): string; overload;
32 | function ToString : string; override;
33 | property AsJson: string read GetAsJson write SetAsJson;
34 | end;
35 |
36 | GenericListReflectAttribute = class(JsonReflectAttribute)
37 | public
38 | constructor Create;
39 | end;
40 |
41 | implementation
42 |
43 | uses
44 | System.Sysutils, System.JSONConsts, System.Rtti;
45 |
46 | { TJsonDTO }
47 |
48 | constructor TJsonDTO.Create;
49 | begin
50 | inherited;
51 | FOptions := [joDateIsUTC, joDateFormatISO8601];
52 | end;
53 |
54 | function TJsonDTO.GetAsJson: string;
55 | begin
56 | Result := TJson.ObjectToJsonString(Self, FOptions);
57 | end;
58 |
59 | const
60 | INDENT_SIZE = 2;
61 |
62 | class procedure TJsonDTO.PrettyPrintJSON(aJSONValue: TJsonValue; aOutputStrings: TStrings; Indent: Integer);
63 | var
64 | i: Integer;
65 | Ident: Integer;
66 | begin
67 | Ident := Indent + INDENT_SIZE;
68 | i := 0;
69 |
70 | if aJSONValue is TJSONObject then
71 | begin
72 | aOutputStrings.Add(StringOfChar(' ', Ident) + '{');
73 | for i := 0 to TJSONObject(aJSONValue).Count - 1 do
74 | PrettyPrintPair(TJSONObject(aJSONValue).Pairs[i], aOutputStrings, i = TJSONObject(aJSONValue).Count - 1, Ident);
75 |
76 | aOutputStrings.Add(StringOfChar(' ', Ident) + '}');
77 | end
78 | else if aJSONValue is TJSONArray then
79 | PrettyPrintArray(TJSONArray(aJSONValue), aOutputStrings, i = TJSONObject(aJSONValue).Count - 1, Ident)
80 | else
81 | aOutputStrings.Add(StringOfChar(' ', Ident) + aJSONValue.ToString);
82 | end;
83 |
84 | class procedure TJsonDTO.PrettyPrintArray(aJSONValue: TJSONArray; aOutputStrings: TStrings; Last: Boolean; Indent: Integer);
85 | var
86 | i: Integer;
87 | begin
88 | aOutputStrings.Add(StringOfChar(' ', Indent + INDENT_SIZE) + '[');
89 |
90 | for i := 0 to aJSONValue.Count - 1 do
91 | begin
92 | PrettyPrintJSON(aJSONValue.Items[i], aOutputStrings, Indent);
93 | if i < aJSONValue.Count - 1 then
94 | aOutputStrings[aOutputStrings.Count - 1] := aOutputStrings[aOutputStrings.Count - 1] + ',';
95 | end;
96 |
97 | aOutputStrings.Add(StringOfChar(' ', Indent + INDENT_SIZE - 2) + ']');
98 | end;
99 |
100 | class function TJsonDTO.PrettyPrintJSON(aJson: string): string;
101 | var
102 | StringList: TStringlist;
103 | JSONValue: TJsonValue;
104 | begin
105 | StringList := TStringlist.Create;
106 | try
107 | JSONValue := TJSONObject.ParseJSONValue(aJson);
108 | try
109 | if JSONValue <> nil then
110 | PrettyPrintJSON(JSONValue, StringList);
111 | finally
112 | JSONValue.Free;
113 | end;
114 |
115 | Result := StringList.Text;
116 | finally
117 | StringList.Free;
118 | end;
119 | end;
120 |
121 | class procedure TJsonDTO.PrettyPrintPair(aJSONValue: TJSONPair; aOutputStrings: TStrings; Last: Boolean; Indent: Integer);
122 | const
123 | TEMPLATE = '%s:%s';
124 | var
125 | Line: string;
126 | NewList: TStringlist;
127 | begin
128 | NewList := TStringlist.Create;
129 | try
130 | PrettyPrintJSON(aJSONValue.JSONValue, NewList, Indent);
131 | Line := Format(TEMPLATE, [aJSONValue.JsonString.ToString, Trim(NewList.Text)]);
132 | finally
133 | NewList.Free;
134 | end;
135 |
136 | Line := StringOfChar(' ', Indent + INDENT_SIZE) + Line;
137 | if not Last then
138 | Line := Line + ',';
139 | aOutputStrings.Add(Line);
140 | end;
141 |
142 | procedure TJsonDTO.SetAsJson(aValue: string);
143 | var
144 | JSONValue: TJsonValue;
145 | JSONObject: TJSONObject;
146 | begin
147 | JSONValue := TJSONObject.ParseJSONValue(aValue);
148 | try
149 | if not Assigned(JSONValue) then
150 | Exit;
151 |
152 | if (JSONValue is TJSONArray) then
153 | begin
154 | with TJSONUnMarshal.Create do
155 | try
156 | SetFieldArray(Self, 'Items', (JSONValue as TJSONArray));
157 | finally
158 | Free;
159 | end;
160 |
161 | Exit;
162 | end;
163 |
164 | if (JSONValue is TJSONObject) then
165 | JSONObject := JSONValue as TJSONObject
166 | else
167 | begin
168 | aValue := aValue.Trim;
169 | if (aValue = '') and not Assigned(JSONValue) or (aValue <> '') and Assigned(JSONValue) and JSONValue.Null then
170 | Exit
171 | else
172 | raise EConversionError.Create(SCannotCreateObject);
173 | end;
174 |
175 | TJson.JsonToObject(Self, JSONObject, FOptions);
176 | finally
177 | JSONValue.Free;
178 | end;
179 | end;
180 |
181 | function TJsonDTO.ToString: string;
182 | begin
183 | Result := AsJson;
184 | end;
185 |
186 | { TArrayMapper }
187 |
188 | constructor TArrayMapper.Create;
189 | begin
190 | inherited;
191 | end;
192 |
193 | function TArrayMapper.List(var aList: TList; aSource: TArray): TList;
194 | begin
195 | if aList = nil then
196 | begin
197 | aList := TList.Create;
198 | aList.AddRange(aSource);
199 | end;
200 |
201 | Exit(aList);
202 | end;
203 |
204 | function TArrayMapper.ObjectList(var aList: TObjectList; aSource: TArray): TObjectList;
205 | var
206 | Element: T;
207 | begin
208 | if aList = nil then
209 | begin
210 | aList := TObjectList.Create;
211 | for Element in aSource do
212 | aList.Add(Element);
213 | end;
214 |
215 | Exit(aList);
216 | end;
217 |
218 | procedure TArrayMapper.RefreshArray(aSource: TList; var aDestination: TArray);
219 | begin
220 | if aSource <> nil then
221 | aDestination := aSource.ToArray;
222 | end;
223 |
224 | type
225 | TGenericListFieldInterceptor = class(TJSONInterceptor)
226 | public
227 | function ObjectsConverter(Data: TObject; Field: string): TListOfObjects; override;
228 | end;
229 |
230 | { TListFieldInterceptor }
231 |
232 | function TGenericListFieldInterceptor.ObjectsConverter(Data: TObject; Field: string): TListOfObjects;
233 | var
234 | ctx: TRttiContext;
235 | List: TList;
236 | RttiProperty: TRttiProperty;
237 | begin
238 | RttiProperty := ctx.GetType(Data.ClassInfo).GetProperty(Copy(Field, 2, MAXINT));
239 | List := TList(RttiProperty.GetValue(Data).AsObject);
240 | Result := TListOfObjects(List.List);
241 | SetLength(Result, List.Count);
242 | end;
243 |
244 | constructor GenericListReflectAttribute.Create;
245 | begin
246 | inherited Create(ctObjects, rtObjects, TGenericListFieldInterceptor, nil, false);
247 | end;
248 |
249 | end.
250 |
251 |
252 |
--------------------------------------------------------------------------------
/Demo/RootU.pas:
--------------------------------------------------------------------------------
1 | unit RootU;
2 |
3 | interface
4 |
5 | uses
6 | Pkg.Json.DTO, System.Generics.Collections, REST.Json.Types;
7 |
8 | {$M+}
9 |
10 | type
11 | TPersonDTO = class
12 | private
13 | FAbout: string;
14 | FAddress: string;
15 | FAge: Integer;
16 | FBalance: string;
17 | FCompany: string;
18 | FEmail: string;
19 | FEyeColor: string;
20 | FFavoriteFruit: string;
21 | FGender: string;
22 | FGreeting: string;
23 | FGuId: string;
24 | FId: string;
25 | FIndex: Integer;
26 | FIsActive: Boolean;
27 | FLatitude: Double;
28 | FLongitude: Double;
29 | FName: string;
30 | FPhone: string;
31 | FPicture: string;
32 | FRegistered: string;
33 | published
34 | property About: string read FAbout write FAbout;
35 | property Address: string read FAddress write FAddress;
36 | property Age: Integer read FAge write FAge;
37 | property Balance: string read FBalance write FBalance;
38 | property Company: string read FCompany write FCompany;
39 | property Email: string read FEmail write FEmail;
40 | property EyeColor: string read FEyeColor write FEyeColor;
41 | property FavoriteFruit: string read FFavoriteFruit write FFavoriteFruit;
42 | property Gender: string read FGender write FGender;
43 | property Greeting: string read FGreeting write FGreeting;
44 | property GuId: string read FGuId write FGuId;
45 | property Id: string read FId write FId;
46 | property Index: Integer read FIndex write FIndex;
47 | property IsActive: Boolean read FIsActive write FIsActive;
48 | property Latitude: Double read FLatitude write FLatitude;
49 | property Longitude: Double read FLongitude write FLongitude;
50 | property Name: string read FName write FName;
51 | property Phone: string read FPhone write FPhone;
52 | property Picture: string read FPicture write FPicture;
53 | property Registered: string read FRegistered write FRegistered;
54 | end;
55 |
56 | TPersons = class(TJsonDTO)
57 | private
58 | [JSONName('Items'), JSONMarshalled(False)]
59 | FItemsArray: TArray;
60 | [GenericListReflect]
61 | FItems: TObjectList;
62 | function GeTPersonDTO: TObjectList;
63 | published
64 | property Items: TObjectList read GeTPersonDTO;
65 | public
66 | destructor Destroy; override;
67 | end;
68 |
69 | implementation
70 |
71 | { TRoot }
72 |
73 | destructor TPersons.Destroy;
74 | begin
75 | GeTPersonDTO.Free;
76 | inherited;
77 | end;
78 |
79 | function TPersons.GeTPersonDTO: TObjectList;
80 | begin
81 | Result := ObjectList(FItems, FItemsArray);
82 | end;
83 |
84 | end.
85 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/ORM/DelphiRestOrm.ORM.IRequest.pas:
--------------------------------------------------------------------------------
1 | unit DelphiRestOrm.ORM.IRequest;
2 |
3 | interface
4 |
5 | uses
6 | System.Classes, System.Rtti, Rest.Client, Rest.Types,
7 |
8 | DelphiRestOrm.ORM.Response, DelphiRestOrm.ORM.Helper.ObjectContainer, DelphiRestOrm.ORM.Helper.Azure;
9 |
10 | const
11 | ctDefault = ctAPPLICATION_JSON;
12 |
13 | type
14 | TOrmCompletionHandler = reference to procedure(const Response: TResponse);
15 |
16 | IRestRequest = interface
17 | ['{C117D3C1-B571-4CD9-A571-3C720DE689CE}']
18 |
19 | ///
20 | /// Adds ABodyContent as Body parameter to the request.
21 | ///
22 | ///
23 | /// An already existing body parameter will NOT be replaced/deleted!
24 | ///
25 | function AddBody(const aBodyContent: string; aContentType: TRESTContentType = ctNone): IRestRequest; overload;
26 |
27 | ///
28 | /// Encodes the string representation of a JSON Object and adds it to the request body.
29 | ///
30 | /// The object to serialize, uning the objects ToString method
31 | /// Defines who will own the object.
32 | ///
33 | /// An already existing body parameter will be replaced/deleted!
34 | ///
35 | function AddBody(AObject: TObject; aContentType: TRESTContentType = ctDefault): IRestRequest; overload;
36 |
37 | ///
38 | /// Add an authentication parameter
39 | ///
40 | function AddAuthParameter(const AName, aValue: string; const AKind: TRESTRequestParameterKind = TRESTRequestParameterKind.pkGetOrPost; const AOptions: TRESTRequestParameterOptions = [])
41 | : IRestRequest;
42 |
43 | ///
44 | /// Adds ABodyContent as Body parameter to the request.
45 | ///
46 | ///
47 | /// An already existing body parameter will be replaced/deleted!
48 | ///
49 | function AddBody(aBodyContent: TStream; aContentType: TRESTContentType = ctNone; AOwnsStream: TRESTObjectOwnership = ooCopy): IRestRequest; overload;
50 |
51 | ///
52 | /// Adds ABodyContent as Body parameter to the request.
53 | ///
54 | ///
55 | /// An already existing body parameter will be replaced/deleted!
56 | ///
57 | function AddBody(AObject: TObject): IRestRequest; overload;
58 |
59 | ///
60 | /// Removes all body parameters (TRESTRequestParameterKind.pkREQUESTBODY) from the request.
61 | ///
62 | function ClearBody: IRestRequest;
63 |
64 | ///
65 | /// Adds file content to the request. If same AName parameter already exists, then the previous content
66 | /// will be replaced by new one.
67 | ///
68 | /// Name of the parameter
69 | /// Path to the file
70 | /// Content type of the file, for HTTP body parameter.
71 | /// If AContentType=ctNone program automatically define the Content type of the file
72 | function AddFile(const AName, AFileName: string; aContentType: TRESTContentType = TRESTContentType.ctNone): IRestRequest; overload;
73 |
74 | ///
75 | /// Adds file content to the request. Only one file can be added.
76 | /// If this function is executed second time, then previous content will be replaced by new one.
77 | ///
78 | /// Path to the file
79 | /// Content type of the file, for HTTP body parameter.
80 | /// If AContentType=ctNone program automatically define the Content type of the file
81 | function AddFile(const AFileName: string; aContentType: TRESTContentType = TRESTContentType.ctNone): IRestRequest; overload;
82 |
83 | ///
84 | /// Adds a parameter to the header. If a parameter of the same name already exists, then the previous parameter
85 | /// will be removed and freed.
There are five kinds of parameters: - GetOrPost: Either a QueryString
86 | /// value or encoded form value based on method - HttpHeader: Adds the name/value pair to the HTTP request's
87 | /// Headers collection - UrlSegment: Inserted into URL if there is a matching url token e.g. {AccountId} -
88 | /// Cookie: Adds the name/value pair to the HTTP request's Cookies collection - RequestBody: Used by AddBody()
89 | /// (not recommended to use directly)
90 | ///
91 | ///
92 | /// Name of the parameter
93 | ///
94 | ///
95 | /// Value of the parameter
96 | ///
97 | ///
98 | /// The kind of parameter to add
99 | ///
100 | ///
101 | /// Options for processing the parameter
102 | ///
103 | function AddHeader(const AName, aValue: string; const AOptions: TRESTRequestParameterOptions = [poDoNotEncode]): IRestRequest; overload;
104 |
105 | ///
106 | /// Sets all fields to their default value. No state information is kept. If Response
107 | /// is assigned, then Response.ResetToDefaults is called too.
108 | ///
109 | function ResetToDefaults: IRestRequest;
110 |
111 | ///
112 | /// Cancels REST request. This will not raise an exception.
113 | /// Check ARequest.IsCancelled that the request was cancelled.
114 | ///
115 | function Cancel: IRestRequest;
116 | ///
117 | /// Scpecifies when the request was cancalled using Cancel call.
118 | ///
119 |
120 | function Accept(aContentType: TRESTContentType = ctDefault; const AOptions: TRESTRequestParameterOptions = [poDoNotEncode]): IRestRequest;
121 | function ContentType(aContentType: TRESTContentType = ctDefault; const AOptions: TRESTRequestParameterOptions = [poDoNotEncode]): IRestRequest;
122 | function AzureCredentials(const aTennantID, aClientID, aClientSecret, aResourceId: string): IRestRequest; overload;
123 | function AzureCredentials(const aAzureAuthenticator: TAzureAuthenticator): IRestRequest; overload;
124 | function Credentials(const aUsername, aPassword: string): IRestRequest;
125 | function ConnectionTimeOut(const aValue: Integer = 30000): IRestRequest;
126 | function ObjectContainer(var aObjectContainer: TObjectContainer): IRestRequest;
127 | function OwnsObjects(const aValue: Boolean = True): IRestRequest;
128 | function QueryParam(const AName: string; aValue: TValue): IRestRequest;
129 | function Param(aValue: TValue): IRestRequest;
130 |
131 | function IsCancelled: Boolean;
132 | ///
133 | /// Sends a NEW object/entity to the server.
134 | ///
135 | function Post: TResponse; overload;
136 |
137 | ///
138 | /// Sends a NEW object/entity to the server.
139 | ///
140 | function Post(AObject: TObject): TResponse; overload;
141 |
142 | ///
143 | /// Sends a NEW object/entity to the server.
144 | ///
145 | function Post(aValue: TValue; AObject: TObject): TResponse; overload;
146 |
147 | ///
148 | /// Updates an already existing object/entity on the server. PUT may also
149 | /// allow for sending a new entity (depends on the actual server/API
150 | /// implementation).
151 | ///
152 | function Put: TResponse; overload;
153 |
154 | ///
155 | /// Updates an already existing object/entity on the server. PUT may also
156 | /// allow for sending a new entity (depends on the actual server/API implementation).
157 | ///
158 | function Put(AObject: TObject): TResponse; overload;
159 |
160 | ///
161 | /// Updates an already existing object/entity on the server. PUT may also
162 | /// allow for sending a new entity (depends on the actual server/API implementation).
163 | ///
164 | function Put(aValue: TValue; AObject: TObject): TResponse; overload;
165 |
166 | ///
167 | /// Retrieves an object/entity from the server.
168 | ///
169 | function GET: TResponse; overload;
170 |
171 | ///
172 | /// Retrieves an object/entity from the server.
173 | ///
174 | function GET(AObject: TObject): TResponse; overload;
175 |
176 | ///
177 | /// Retrieves an object/entity from the server.
178 | ///
179 | function GET(aValue: TValue): TResponse; overload;
180 |
181 | ///
182 | /// Deletes an object/entity from the server.
183 | ///
184 | function DELETE: TResponse; overload;
185 |
186 | ///
187 | /// Deletes an object/entity from the server.
188 | ///
189 | function DELETE(AObject: TObject): TResponse; overload;
190 |
191 | ///
192 | /// Deletes an object/entity from the server.
193 | ///
194 | function DELETE(aValue: TValue): TResponse; overload;
195 |
196 | ///
197 | /// Patches an object/entity on the server, by only updating the pairs that are sent within that PATCH body.
198 | ///
199 | function PATCH: TResponse; overload;
200 |
201 | ///
202 | /// Patches an object/entity on the server, by only updating the pairs that are sent within that PATCH body.
203 | ///
204 | function PATCH(AObject: TObject): TResponse; overload;
205 |
206 | ///
207 | /// Patches an object/entity on the server, by only updating the pairs that are sent within that PATCH body.
208 | ///
209 | function PATCH(aValue: TValue; AObject: TObject): TResponse; overload;
210 |
211 | function BaseApiURL: string;
212 | end;
213 |
214 | function NewRequest(aBaseApiURL: string; aOwnsObjects: Boolean = True): IRestRequest; overload;
215 | function NewRequestAsync(aBaseApiURL: string; aCompletionHandler: TOrmCompletionHandler; aOwnsObjects: Boolean = True): IRestRequest; overload;
216 |
217 | implementation
218 |
219 | uses
220 | DelphiRestOrm.ORM.Request;
221 |
222 | function NewRequest(aBaseApiURL: string; aOwnsObjects: Boolean = True): IRestRequest; overload;
223 | begin
224 | Result := TRestRequest.Create(aBaseApiURL).OwnsObjects(aOwnsObjects);
225 | end;
226 |
227 | function NewRequestAsync(aBaseApiURL: string; aCompletionHandler: TOrmCompletionHandler; aOwnsObjects: Boolean = True): IRestRequest; overload;
228 | begin
229 | Result := TRestRequest.Create(aBaseApiURL, aCompletionHandler).OwnsObjects(aOwnsObjects);
230 | end;
231 |
232 | end.
233 |
--------------------------------------------------------------------------------
/ORM/DelphiRestOrm.ORM.Request.pas:
--------------------------------------------------------------------------------
1 | unit DelphiRestOrm.ORM.Request;
2 |
3 | interface
4 |
5 | uses
6 | System.Classes, System.Rtti, System.Generics.Collections, System.Threading, REST.Client, REST.Types,
7 |
8 | DelphiRestOrm.ORM.Helper.ObjectContainer, DelphiRestOrm.ORM.Helper.Azure, DelphiRestOrm.ORM.IRequest, DelphiRestOrm.ORM.Response;
9 | {$M+}
10 |
11 | type
12 | TRestRequest = class(TInterfacedObject, IRestRequest)
13 | private
14 | FObjectContainer: TObjectContainer;
15 | FExternalObjectContainer: TObjectContainer;
16 | FDTOObjectContainer: TObjectContainer;
17 | FClient: TRESTClient;
18 | FRequest: TCustomRESTRequest;
19 | FResponse: TRESTResponse;
20 | FBaseURL: string;
21 | FAsyncCall: Boolean;
22 |
23 | FQueryParams: TDictionary;
24 | FCompletionHandler: TOrmCompletionHandler;
25 | function SetAuthenticator(aCustomAuthenticator: TCustomAuthenticator): IRestRequest;
26 | function DoExecute(aRESTRequestMethod: TRESTRequestMethod): TResponse; overload;
27 | function DoExecute(aObject: TObject; aRESTRequestMethod: TRESTRequestMethod): TResponse; overload;
28 | function InternalParam(aValue: TValue): TRestRequest;
29 | public
30 | constructor Create(const aBaseApiURL: string; aCompletionHandler: TOrmCompletionHandler = nil); reintroduce;
31 | destructor Destroy; override;
32 | function Param(aValue: TValue): IRestRequest;
33 |
34 | function AddAuthParameter(const AName, aValue: string; const AKind: TRESTRequestParameterKind = TRESTRequestParameterKind.pkGetOrPost; const AOptions: TRESTRequestParameterOptions = [])
35 | : IRestRequest;
36 | function AddBody(const aBodyContent: string; aContentType: TRESTContentType = ctNone): IRestRequest; overload;
37 | function AddBody(aObject: TObject; aContentType: TRESTContentType = ctDefault): IRestRequest; overload;
38 | function AddBody(aBodyContent: TStream; aContentType: TRESTContentType = ctNone; AOwnsStream: TRESTObjectOwnership = ooCopy): IRestRequest; overload;
39 | function AddBody(aObject: TObject): IRestRequest; overload;
40 | function ClearBody: IRestRequest;
41 | function AddFile(const AName, AFileName: string; aContentType: TRESTContentType = TRESTContentType.ctNone): IRestRequest; overload;
42 | function AddFile(const AFileName: string; aContentType: TRESTContentType = TRESTContentType.ctNone): IRestRequest; overload;
43 | function AddHeader(const AName, aValue: string; const AOptions: TRESTRequestParameterOptions = [poDoNotEncode]): IRestRequest; overload;
44 | function ResetToDefaults: IRestRequest;
45 | function Cancel: IRestRequest;
46 | function Accept(aContentType: TRESTContentType = ctDefault; const AOptions: TRESTRequestParameterOptions = [poDoNotEncode]): IRestRequest;
47 | function ContentType(aContentType: TRESTContentType = ctDefault; const AOptions: TRESTRequestParameterOptions = [poDoNotEncode]): IRestRequest;
48 | function AzureCredentials(const aTennantID, aClientID, aClientSecret, aResourceId: string): IRestRequest; overload;
49 | function AzureCredentials(const aAzureAuthenticator: TAzureAuthenticator): IRestRequest; overload;
50 | function Credentials(const aUsername, aPassword: string): IRestRequest;
51 | function ObjectContainer(var aObjectContainer: TObjectContainer): IRestRequest;
52 | function IsCancelled: Boolean;
53 | function Post: TResponse; overload;
54 | function Post(aObject: TObject): TResponse; overload;
55 | function Post(aValue: TValue; aObject: TObject): TResponse; overload;
56 | function Put: TResponse; overload;
57 | function Put(aObject: TObject): TResponse; overload;
58 | function Put(aValue: TValue; aObject: TObject): TResponse; overload;
59 | function GET: TResponse; overload;
60 | function GET(aObject: TObject): TResponse; overload;
61 | function GET(aValue: TValue): TResponse; overload;
62 | function DELETE: TResponse; overload;
63 | function DELETE(aObject: TObject): TResponse; overload;
64 | function DELETE(aValue: TValue): TResponse; overload;
65 | function PATCH: TResponse; overload;
66 | function PATCH(aObject: TObject): TResponse; overload;
67 | function PATCH(aValue: TValue; aObject: TObject): TResponse; overload;
68 |
69 | function BaseApiURL: string;
70 | function ConnectionTimeOut(const aValue: Integer = 30000): IRestRequest;
71 | function OwnsObjects(const aValue: Boolean = True): IRestRequest;
72 | function QueryParam(const AName: string; aValue: TValue): IRestRequest;
73 | end;
74 |
75 | implementation
76 |
77 | uses
78 | System.SysUtils, System.IOUtils,
79 |
80 | REST.Authenticator.Basic, DelphiRestOrm.ORM.Helper.ThreadingEx;
81 |
82 | { TRestRequest }
83 |
84 | function TRestRequest.Accept(aContentType: TRESTContentType = ctDefault; const AOptions: TRESTRequestParameterOptions = [poDoNotEncode]): IRestRequest;
85 | begin
86 | AddHeader('Accept', ContentTypeToString(aContentType), AOptions);
87 | Result := Self;
88 | end;
89 |
90 | function TRestRequest.AddBody(aBodyContent: TStream; aContentType: TRESTContentType; AOwnsStream: TRESTObjectOwnership): IRestRequest;
91 | begin
92 | FRequest.AddBody(aBodyContent, aContentType, AOwnsStream);
93 | Result := Self;
94 | end;
95 |
96 | function TRestRequest.AddBody(aObject: TObject; aContentType: TRESTContentType): IRestRequest;
97 | begin
98 | AddBody(aObject.ToString, aContentType);
99 | Result := Self;
100 | end;
101 |
102 | function TRestRequest.AddBody(const aBodyContent: string; aContentType: TRESTContentType): IRestRequest;
103 | begin
104 | FRequest.AddBody(aBodyContent, aContentType);
105 | Result := Self;
106 | end;
107 |
108 | function TRestRequest.AddFile(const AFileName: string; aContentType: TRESTContentType): IRestRequest;
109 | begin
110 | FRequest.AddFile(AFileName, aContentType);
111 | Result := Self;
112 | end;
113 |
114 | function TRestRequest.AddHeader(const AName, aValue: string; const AOptions: TRESTRequestParameterOptions): IRestRequest;
115 | begin
116 | FRequest.AddParameter(AName, aValue, TRESTRequestParameterKind.pkHTTPHEADER, AOptions);
117 | Result := Self;
118 | end;
119 |
120 | function TRestRequest.AzureCredentials(const aAzureAuthenticator: TAzureAuthenticator): IRestRequest;
121 | begin
122 | Result := SetAuthenticator(aAzureAuthenticator);
123 | end;
124 |
125 | function TRestRequest.Param(aValue: TValue): IRestRequest;
126 | begin
127 | Result := QueryParam('', aValue);
128 | end;
129 |
130 | function TRestRequest.AzureCredentials(const aTennantID, aClientID, aClientSecret, aResourceId: string): IRestRequest;
131 | begin
132 | Result := SetAuthenticator(TAzureAuthenticator.Create(aTennantID, aClientID, aClientSecret, aResourceId));
133 | end;
134 |
135 | function TRestRequest.BaseApiURL: string;
136 | begin
137 | Result := FBaseURL;
138 | end;
139 |
140 | function TRestRequest.AddFile(const AName, AFileName: string; aContentType: TRESTContentType): IRestRequest;
141 | begin
142 | FRequest.AddFile(AName, AFileName, aContentType);
143 | Result := Self;
144 | end;
145 |
146 | function TRestRequest.Cancel: IRestRequest;
147 | begin
148 | FRequest.Cancel;
149 | Result := Self;
150 | end;
151 |
152 | function TRestRequest.ClearBody: IRestRequest;
153 | begin
154 | FRequest.ClearBody;
155 | Result := Self;
156 | end;
157 |
158 | constructor TRestRequest.Create(const aBaseApiURL: string; aCompletionHandler: TOrmCompletionHandler = nil);
159 | begin
160 | FObjectContainer := TObjectContainer.Create;
161 | FBaseURL := aBaseApiURL;
162 |
163 | FClient := TRESTClient.Create(aBaseApiURL);
164 | FRequest := TCustomRESTRequest.Create(FClient);
165 | FResponse := TRESTResponse.Create(FClient);
166 | FRequest.Response := FResponse;
167 |
168 | FDTOObjectContainer := FObjectContainer.Add(TObjectContainer.Create(False));
169 | FQueryParams := FObjectContainer.Add(TDictionary.Create);
170 | FCompletionHandler := aCompletionHandler;
171 | FAsyncCall := Assigned(aCompletionHandler);
172 |
173 | FExternalObjectContainer := nil;
174 | end;
175 |
176 | function TRestRequest.DELETE: TResponse;
177 | begin
178 | Result := DoExecute(rmDELETE);
179 | end;
180 |
181 | function TRestRequest.DELETE(aObject: TObject): TResponse;
182 | begin
183 | Result := DoExecute(aObject, rmDELETE);
184 | end;
185 |
186 | function TRestRequest.DELETE(aValue: TValue): TResponse;
187 | begin
188 | Result := InternalParam(aValue).DoExecute(rmDELETE);
189 | end;
190 |
191 | destructor TRestRequest.Destroy;
192 | begin
193 | if not FAsyncCall then
194 | FreeAndNil(FClient);
195 |
196 | FreeAndNil(FObjectContainer);
197 | inherited;
198 | end;
199 |
200 | function TRestRequest.DoExecute(aObject: TObject; aRESTRequestMethod: TRESTRequestMethod): TResponse;
201 | begin
202 | FDTOObjectContainer.Add(aObject);
203 | AddBody(aObject.ToString, ctDefault);
204 | Result := DoExecute(aRESTRequestMethod);
205 | end;
206 |
207 | function TRestRequest.DoExecute(aRESTRequestMethod: TRESTRequestMethod): TResponse;
208 | function GetURL: string;
209 | var
210 | Value: string;
211 | Pair: TPair;
212 | begin
213 | Result := FBaseURL;
214 | if not Result.EndsWith('/') then
215 | Result := Result + '/';
216 |
217 | if FQueryParams.TryGetValue('', Value) then
218 | begin
219 | Result := Result + Value;
220 | FQueryParams.Remove('');
221 | end
222 | else
223 | Result := Result.Substring(0, Length(Result) - 1);
224 |
225 | if FQueryParams.Count > 0 then
226 | Result := Result + '?';
227 |
228 | for Pair in FQueryParams do
229 | Result := Result + Pair.Key + '=' + Pair.Value;
230 |
231 | end;
232 |
233 | var
234 | LCLient: TRESTClient;
235 | LRequest: TCustomRESTRequest;
236 | LCompletionHandler: TOrmCompletionHandler;
237 |
238 | begin
239 | LCLient := FClient;
240 | LRequest := FRequest;
241 | LCompletionHandler := FCompletionHandler;
242 |
243 | FClient.BaseURL := GetURL;
244 | FRequest.Method := aRESTRequestMethod;
245 |
246 | if not FAsyncCall then
247 | begin
248 | LRequest.Execute;
249 | Exit(FObjectContainer.Add(TResponse.Create(LRequest.Response, FExternalObjectContainer)));
250 | end;
251 |
252 | Result := nil;
253 |
254 | LRequest.ExecuteAsync(
255 | procedure
256 | var
257 | Response: TResponse;
258 | ObjectContainer: TObjectContainer;
259 | begin
260 | ObjectContainer := TObjectContainer.Create;
261 | ObjectContainer.Add(FClient);
262 |
263 | if Assigned(LCompletionHandler) then
264 | begin
265 | Response := ObjectContainer.Add(TResponse.Create(LRequest.Response, ObjectContainer));
266 | LCompletionHandler(Response);
267 | end;
268 |
269 | FreeAndNil(ObjectContainer);
270 | end, True, True,
271 | procedure(aErrorObject: TObject)
272 | begin
273 | FreeAndNil(LCLient);
274 | end);
275 |
276 | end;
277 |
278 | function TRestRequest.GET(aObject: TObject): TResponse;
279 | begin
280 | Result := DoExecute(aObject, rmGET);
281 | end;
282 |
283 | function TRestRequest.GET: TResponse;
284 | begin
285 | Result := DoExecute(rmGET);
286 | end;
287 |
288 | function TRestRequest.InternalParam(aValue: TValue): TRestRequest;
289 | begin
290 | Result := Param(aValue) as TRestRequest;
291 | end;
292 |
293 | function TRestRequest.IsCancelled: Boolean;
294 | begin
295 | Result := FRequest.IsCancelled;
296 | end;
297 |
298 | function TRestRequest.ObjectContainer(var aObjectContainer: TObjectContainer): IRestRequest;
299 | begin
300 | if not Assigned(aObjectContainer) then
301 | aObjectContainer := TObjectContainer.Create;
302 |
303 | FExternalObjectContainer := aObjectContainer;
304 | Result := Self;
305 | end;
306 |
307 | function TRestRequest.OwnsObjects(const aValue: Boolean): IRestRequest;
308 | begin
309 | FDTOObjectContainer.OwnsObjects := aValue;
310 | Result := Self;
311 | end;
312 |
313 | function TRestRequest.SetAuthenticator(aCustomAuthenticator: TCustomAuthenticator): IRestRequest;
314 | begin
315 | FObjectContainer.Remove;
316 | FClient.Authenticator := FObjectContainer.Add(aCustomAuthenticator);
317 | Result := Self;
318 | end;
319 |
320 | function TRestRequest.PATCH: TResponse;
321 | begin
322 | Result := DoExecute(rmPATCH);
323 | end;
324 |
325 | function TRestRequest.Post: TResponse;
326 | begin
327 | Result := DoExecute(rmPOST);
328 | end;
329 |
330 | function TRestRequest.Put: TResponse;
331 | begin
332 | Result := DoExecute(rmPUT);
333 | end;
334 |
335 | function TRestRequest.ResetToDefaults: IRestRequest;
336 | begin
337 | FRequest.ResetToDefaults;
338 | Result := Self;
339 | end;
340 |
341 | function TRestRequest.Credentials(const aUsername, aPassword: string): IRestRequest;
342 | begin
343 | Result := SetAuthenticator(THTTPBasicAuthenticator.Create(aUsername, aPassword))
344 | end;
345 |
346 | function TRestRequest.ConnectionTimeOut(const aValue: Integer): IRestRequest;
347 | begin
348 | FClient.ConnectTimeout := aValue;
349 | end;
350 |
351 | function TRestRequest.ContentType(aContentType: TRESTContentType; const AOptions: TRESTRequestParameterOptions): IRestRequest;
352 | begin
353 | AddHeader('Content-Type', ContentTypeToString(aContentType), AOptions);
354 | Result := Self;
355 | end;
356 |
357 | function TRestRequest.PATCH(aObject: TObject): TResponse;
358 | begin
359 | Result := DoExecute(aObject, rmPATCH);
360 | end;
361 |
362 | function TRestRequest.Post(aObject: TObject): TResponse;
363 | begin
364 | Result := DoExecute(aObject, rmPOST);
365 | end;
366 |
367 | function TRestRequest.Put(aObject: TObject): TResponse;
368 | begin
369 | Result := DoExecute(aObject, rmPUT);
370 | end;
371 |
372 | function TRestRequest.AddAuthParameter(const AName, aValue: string; const AKind: TRESTRequestParameterKind; const AOptions: TRESTRequestParameterOptions): IRestRequest;
373 | begin
374 | FRequest.AddAuthParameter(AName, aValue, AKind, AOptions);
375 | Result := Self;
376 | end;
377 |
378 | function TRestRequest.AddBody(aObject: TObject): IRestRequest;
379 | begin
380 | FDTOObjectContainer.Add(aObject);
381 | Result := AddBody(aObject.ToString, ctDefault);
382 | end;
383 |
384 | function TRestRequest.GET(aValue: TValue): TResponse;
385 | begin
386 | Result := InternalParam(aValue).DoExecute(TRESTRequestMethod.rmGET);
387 | end;
388 |
389 | function TRestRequest.PATCH(aValue: TValue; aObject: TObject): TResponse;
390 | begin
391 | Result := InternalParam(aValue).DoExecute(aObject, rmPATCH);
392 | end;
393 |
394 | function TRestRequest.Post(aValue: TValue; aObject: TObject): TResponse;
395 | begin
396 | Result := InternalParam(aValue).DoExecute(aObject, rmPOST);
397 | end;
398 |
399 | function TRestRequest.Put(aValue: TValue; aObject: TObject): TResponse;
400 | begin
401 | Result := InternalParam(aValue).DoExecute(aObject, rmPUT);
402 | end;
403 |
404 | function TRestRequest.QueryParam(const AName: string; aValue: TValue): IRestRequest;
405 | var
406 | s: string;
407 | begin
408 | if FQueryParams.TryGetValue(AName, s) then
409 | FQueryParams[AName] := aValue.ToString
410 | else
411 | FQueryParams.Add(AName, aValue.ToString);
412 |
413 | Result := Self;
414 | end;
415 |
416 | end.
417 |
--------------------------------------------------------------------------------
/ORM/DelphiRestOrm.ORM.Response.pas:
--------------------------------------------------------------------------------
1 | unit DelphiRestOrm.ORM.Response;
2 |
3 | interface
4 |
5 | uses
6 | REST.Client, DelphiRestOrm.ORM.Helper.ObjectContainer;
7 |
8 | type
9 | TResponse = class abstract
10 | strict protected
11 | FResponse: TCustomRESTResponse;
12 | FExternalObjectContainer: TObjectContainer;
13 | class function FromString(aContent: string; aObject: TObject): TObject; virtual;
14 | public
15 | constructor Create(aResponse: TCustomRESTResponse; aExternalObjectContainer: TObjectContainer);
16 | destructor Destroy; override;
17 | function AsType: T; overload;
18 | function AsType(aObject: T): T; overload;
19 | function ToString: string; override;
20 | end;
21 |
22 | TJsonResponse = class(TResponse)
23 | public
24 | class function FromString(aContent: string; aObject: TObject): TObject; override;
25 | end;
26 |
27 | implementation
28 |
29 | uses
30 | System.SysUtils, System.Generics.Collections, System.RTTI, System.JSONConsts, System.Json,
31 | REST.JsonReflect, REST.Json, REST.Types,
32 |
33 | DelphiRestOrm.ORM.Helper.GenericListHelper;
34 |
35 | { TResponse }
36 | function TResponse.AsType: T;
37 | begin
38 | Result := AsType(T.Create);
39 | end;
40 |
41 | function TResponse.AsType(aObject: T): T;
42 | begin
43 | if Assigned(FExternalObjectContainer) then
44 | FExternalObjectContainer.Add(aObject);
45 |
46 | case ContentTypeFromString(FResponse.ContentType) of
47 | ctAPPLICATION_JSON, ctAPPLICATION_VND_EMBARCADERO_FIREDAC_JSON:
48 | Result := TJsonResponse.FromString(FResponse.Content, aObject) as T;
49 | else
50 | raise ENotImplemented.Create('AsType are not implemented for content kind ' + FResponse.ContentType)
51 | end
52 | end;
53 |
54 | constructor TResponse.Create(aResponse: TCustomRESTResponse; aExternalObjectContainer: TObjectContainer);
55 | begin
56 | inherited Create;
57 | FResponse := aResponse;
58 | FExternalObjectContainer := aExternalObjectContainer;
59 | end;
60 |
61 | destructor TResponse.Destroy;
62 | begin
63 | inherited;
64 | end;
65 |
66 | class function TResponse.FromString(aContent: string; aObject: TObject): TObject;
67 | begin
68 | raise ENotImplemented.Create('Not Imlemented')
69 | end;
70 |
71 | function TResponse.ToString: string;
72 | begin
73 | Result := FResponse.Content;
74 | end;
75 |
76 | { TJsonResponse }
77 |
78 | class function TJsonResponse.FromString(aContent: string; aObject: TObject): TObject;
79 | const
80 | DefaultOptions = [joDateIsUTC, joDateFormatISO8601];
81 | var
82 | JSONValue: TJsonValue;
83 | JSONObject: TJSONObject;
84 | RttiProperty: TRttiProperty;
85 | begin
86 | Result := aObject;
87 |
88 | (*
89 | Yes! I favor my own lib Delphi-JsonToDelphiClass.
90 | https://github.com/JensBorrisholt/Delphi-JsonToDelphiClass
91 | *)
92 | RttiProperty := TRttiContext.Create.GetType(aObject.ClassType).GetProperty('AsJson');
93 |
94 | if (RttiProperty <> nil) and (RttiProperty.IsWritable) then
95 | begin
96 | RttiProperty.SetValue(aObject, aContent);
97 | exit;
98 | end;
99 |
100 | JSONValue := TJSONObject.ParseJSONValue(aContent);
101 |
102 | try
103 | if not Assigned(JSONValue) then
104 | exit;
105 |
106 | if (JSONValue is TJSONArray) then
107 | begin
108 | GenericListHelper.UnMarshall(aObject, JSONValue as TJSONArray);
109 | exit;
110 | end;
111 |
112 | if (JSONValue is TJSONObject) then
113 | JSONObject := JSONValue as TJSONObject
114 | else
115 | begin
116 | if (aContent = '') and not Assigned(JSONValue) or (aContent <> '') and Assigned(JSONValue) and JSONValue.Null then
117 | exit
118 | else
119 | raise EConversionError.Create(SCannotCreateObject);
120 | end;
121 |
122 | TJson.JsonToObject(Result, JSONObject, DefaultOptions);
123 | finally
124 | JSONValue.Free;
125 | end;
126 | end;
127 |
128 | end.
129 |
--------------------------------------------------------------------------------
/ORM/Helpers/DelphiRestOrm.ORM.Helper.Azure.pas:
--------------------------------------------------------------------------------
1 | unit DelphiRestOrm.ORM.Helper.Azure;
2 |
3 | interface
4 |
5 | uses
6 | System.SysUtils, System.Classes, Data.Bind.ObjectScope,
7 | REST.Authenticator.Basic, REST.Client, REST.Types, REST.Json.Types;
8 |
9 | {$M+}
10 |
11 | type
12 | TCustomBindAuthenticator = class(TCustomAuthenticator)
13 | private
14 | FBindSource: TSubHTTPBasicAuthenticationBindSource;
15 | protected
16 | function CreateBindSource: TBaseObjectBindSource; override;
17 | published
18 | property BindSource: TSubHTTPBasicAuthenticationBindSource read FBindSource;
19 | end;
20 |
21 | TAccessToken = class
22 | strict private
23 | FContainsToken: Boolean;
24 | [JSONName('token_type')]
25 | FTokenType: string;
26 | [JSONName('expires_in')]
27 | FExpiresIn: Integer;
28 | [JSONName('ext_expires_in')]
29 | FResource: string;
30 | [JSONName('access_token')]
31 | FAccessToken: string;
32 | public
33 | property ContainsToken: Boolean read FContainsToken write FContainsToken;
34 | property TokenType: string read FTokenType write FTokenType;
35 | property ExpiresIn: Integer read FExpiresIn write FExpiresIn;
36 | property Resource: string read FResource write FResource;
37 | property AccessToken: string read FAccessToken write FAccessToken;
38 | end;
39 |
40 | TAzureAuthenticator = class(TCustomBindAuthenticator)
41 | private
42 | FClientId: string;
43 | FClientSecret: string;
44 | FTenantId: string;
45 | FResourceId: string;
46 | FAuthorizeEndPoint: string;
47 | procedure SetTenantId(const Value: string);
48 | procedure SetAuthorizeEndPoint(const Value: string);
49 | procedure SetClientId(const Value: string);
50 | procedure SetClientSecret(const Value: string);
51 | procedure SetResourceId(const Value: string);
52 | function GetAccessToken: TAccessToken;
53 | protected
54 | procedure DoAuthenticate(ARequest: TCustomRESTRequest); override;
55 | published
56 | property AuthorizeEndPoint: string read FAuthorizeEndPoint write SetAuthorizeEndPoint;
57 | property ClientId: string read FClientId write SetClientId;
58 | property TenantId: string read FTenantId write SetTenantId;
59 | property ClientSecret: string read FClientSecret write SetClientSecret;
60 | property ResourceId: string read FResourceId write SetResourceId;
61 | public
62 | constructor Create(const aTenantID, aClientID, aClientSecret, aResourceId: string); reintroduce; overload;
63 | end;
64 |
65 | implementation
66 |
67 | uses
68 | DelphiRestOrm.ORM.IRequest;
69 |
70 | { TAzureAuthenticator }
71 |
72 | constructor TAzureAuthenticator.Create(const aTenantID, aClientID, aClientSecret, aResourceId: string);
73 | begin
74 | inherited Create(nil);
75 | TenantId := aTenantID;
76 | ClientId := aClientID;
77 | ClientSecret := aClientSecret;
78 | ResourceId := aResourceId;
79 | end;
80 |
81 | procedure TAzureAuthenticator.DoAuthenticate(ARequest: TCustomRESTRequest);
82 | var
83 | AccessToken: TAccessToken;
84 | Param: TRESTRequestParameter;
85 | BodyParam: TRESTRequestParameter;
86 | begin
87 | AccessToken := GetAccessToken;
88 | ARequest.Params.AddItem('Authorization', AccessToken.TokenType + ' ' + AccessToken.AccessToken, TRESTRequestParameterKind.pkHTTPHEADER, [poDoNotEncode]);
89 | ARequest.AddParameter('Content-Type', ContentTypeToString(ctAPPLICATION_JSON), TRESTRequestParameterKind.pkHTTPHEADER, [poDoNotEncode]);
90 | ARequest.AddParameter('Accept', ContentTypeToString(ctAPPLICATION_JSON), TRESTRequestParameterKind.pkHTTPHEADER, [poDoNotEncode]);
91 |
92 | BodyParam := nil;
93 | for Param in ARequest.Params do
94 | if Param.Kind = TRESTRequestParameterKind.pkREQUESTBODY then
95 | begin
96 | BodyParam := Param;
97 | Break;
98 | end;
99 |
100 | if (BodyParam <> nil) and (BodyParam.Value <> '') then
101 | ARequest.Params.AddItem('Content-Length', (BodyParam.Value.Length).ToString, TRESTRequestParameterKind.pkHTTPHEADER);
102 |
103 | FreeAndNil(AccessToken);
104 | end;
105 |
106 | function TAzureAuthenticator.GetAccessToken: TAccessToken;
107 | begin
108 | Result :=
109 | NewRequest(AuthorizeEndPoint)
110 | .AddAuthParameter('grant_type', 'client_credentials')
111 | .AddAuthParameter('client_id', ClientId)
112 | .AddAuthParameter('client_secret', ClientSecret)
113 | .AddAuthParameter('resource', ResourceId)
114 | .Post.AsType;
115 |
116 | Result.ContainsToken := (Result.TokenType = 'Bearer') and (Result.AccessToken.Length > 0);
117 | end;
118 |
119 | procedure TAzureAuthenticator.SetAuthorizeEndPoint(const Value: string);
120 | begin
121 | if (Value <> FAuthorizeEndPoint) then
122 | begin
123 | FAuthorizeEndPoint := Value;
124 | PropertyValueChanged;
125 | end;
126 | end;
127 |
128 | procedure TAzureAuthenticator.SetClientId(const Value: string);
129 | begin
130 | if (Value <> FClientId) then
131 | begin
132 | FClientId := Value;
133 | PropertyValueChanged;
134 | end;
135 | end;
136 |
137 | procedure TAzureAuthenticator.SetClientSecret(const Value: string);
138 | begin
139 | if (Value <> FClientSecret) then
140 | begin
141 | FClientSecret := Value;
142 | PropertyValueChanged;
143 | end;
144 | end;
145 |
146 | procedure TAzureAuthenticator.SetResourceId(const Value: string);
147 | begin
148 | if (Value <> FResourceId) then
149 | begin
150 | FResourceId := Value;
151 | PropertyValueChanged;
152 | end;
153 | end;
154 |
155 | procedure TAzureAuthenticator.SetTenantId(const Value: string);
156 | const
157 | AuthorizeEndPointTemplate = 'https://login.microsoftonline.com/{tenant}/oauth2/token';
158 | begin
159 | if (Value <> FTenantId) then
160 | begin
161 | FTenantId := Value;
162 | PropertyValueChanged;
163 | end;
164 |
165 | AuthorizeEndPoint := AuthorizeEndPointTemplate.Replace('{tenant}', FTenantId);
166 | end;
167 |
168 | { TCustomBindAuthenticator }
169 |
170 | function TCustomBindAuthenticator.CreateBindSource: TBaseObjectBindSource;
171 | begin
172 | FBindSource := TSubHTTPBasicAuthenticationBindSource.Create(Self);
173 | FBindSource.Name := 'BindSource'; { Do not localize }
174 | FBindSource.SetSubComponent(True);
175 | FBindSource.Authenticator := Self;
176 | Result := FBindSource;
177 | end;
178 |
179 | end.
180 |
--------------------------------------------------------------------------------
/ORM/Helpers/DelphiRestOrm.ORM.Helper.GenericListHelper.pas:
--------------------------------------------------------------------------------
1 | unit DelphiRestOrm.ORM.Helper.GenericListHelper;
2 |
3 | // CREDIT : Some of the code in this unit is heavly inspired by code found in Stefan Glienke DSharp project.
4 |
5 | interface
6 |
7 | uses
8 | System.Types, System.JSON;
9 |
10 | type
11 | GenericListHelper = record
12 | private
13 | {$IFDEF VER210 }
14 | function SplitString(const S: string; const Delimiter: Char): TStringDynArray;
15 | {$ENDIF}
16 | public
17 | class function IsGenericList(aObject: TObject): boolean; static;
18 | class function GetGenericType(aGenericList: TObject): TClass; static;
19 | class procedure UnMarshall(aGenericList: TObject; aJSONArray: TJSONArray); static;
20 | end;
21 |
22 | implementation
23 |
24 | uses
25 | System.Rtti, System.SysUtils, System.Classes, System.StrUtils, System.TypInfo, System.Generics.Collections,
26 |
27 | REST.JsonReflect;
28 |
29 | var
30 | Context: TRttiContext;
31 |
32 | type
33 | TJSONUnMarshallAcess = class(TJSONUnMarshal)
34 |
35 | end;
36 |
37 | TRttiTypeHelper = class helper for TRttiType
38 | private
39 | function ExtractGenericArguments(ATypeInfo: pTypeInfo): string;
40 | function FindType(const AName: string; out aType: TRttiType): boolean;
41 | public
42 | function GetGenericArguments: TArray;
43 | end;
44 |
45 | class function GenericListHelper.GetGenericType(aGenericList: TObject): TClass;
46 | var
47 | RttiTypes: TArray;
48 | begin
49 | if not IsGenericList(aGenericList) then
50 | raise Exception.Create('Provided object is either nil or is not a GenericList');
51 |
52 | RttiTypes := Context.GetType(aGenericList.ClassType).GetGenericArguments;
53 | if (Length(RttiTypes) = 0) or (not RttiTypes[0].IsInstance) then
54 | raise Exception.Create('Provided object is either nil or is not a GenericList');
55 | Result := RttiTypes[0].AsInstance.MetaclassType;
56 | end;
57 |
58 | class function GenericListHelper.IsGenericList(aObject: TObject): boolean;
59 | var
60 | RttiType: TRttiType;
61 | RttiField: TRttiField;
62 | begin
63 | Result := False;
64 |
65 | if aObject = nil then
66 | exit;
67 |
68 | RttiType := Context.GetType(aObject.ClassType);
69 | for RttiField in RttiType.GetFields do
70 | if RttiField.Visibility = TMemberVisibility.mvPrivate then
71 | if RttiField.FieldType.IsRecord then
72 | if RttiField.Name = 'FListHelper' then
73 | exit(True);
74 | end;
75 |
76 | class procedure GenericListHelper.UnMarshall(aGenericList: TObject; aJSONArray: TJSONArray);
77 | var
78 | Objects: TListOfObjects;
79 | Obj: TObject;
80 | begin
81 | with TJSONUnMarshallAcess.Create do
82 | try
83 | Objects := GetArgObjects(GetGenericType(aGenericList), aJSONArray);
84 |
85 | for Obj in Objects do
86 | TList(aGenericList).Add(Obj);
87 | finally
88 | Free;
89 | end;
90 | end;
91 |
92 | {$IFDEF VER210 }
93 |
94 | function TGenericListHelper.SplitString(const S: string; const Delimiter: Char): TStringDynArray;
95 | var
96 | Strings: TStrings;
97 | i: Integer;
98 | begin
99 | with TStringList.Create do
100 | try
101 | StrictDelimiter := True;
102 | Delimiter := Delimiter;
103 | DelimitedText := S;
104 | SetLength(Result, Count);
105 | for i := Low(Result) to High(Result) do
106 | Result[i] := Strings[i];
107 | finally
108 | Free;
109 | end;
110 | end;
111 | {$ENDIF }
112 | { TRttiTypeHelper }
113 |
114 | function TRttiTypeHelper.ExtractGenericArguments(ATypeInfo: pTypeInfo): string;
115 | var
116 | i: Integer;
117 | S: string;
118 | begin
119 | S := UTF8ToString(ATypeInfo.Name);
120 | i := Pos('<', S);
121 | if i > 0 then
122 | Result := Copy(S, Succ(i), Length(S) - Succ(i))
123 | else
124 | Result := ''
125 | end;
126 |
127 | function TRttiTypeHelper.FindType(const AName: string; out aType: TRttiType): boolean;
128 | var
129 | LType: TRttiType;
130 | begin
131 | Result := True;
132 |
133 | aType := Context.FindType(AName);
134 | if Assigned(aType) then
135 | exit;
136 |
137 | for LType in Context.GetTypes do
138 | if SameText(LType.Name, AName) then
139 | exit;
140 |
141 | Result := False;
142 | end;
143 |
144 | function TRttiTypeHelper.GetGenericArguments: TArray;
145 | var
146 | i: Integer;
147 | args: TStringDynArray;
148 | begin
149 | args := SplitString(ExtractGenericArguments(Handle), ',');
150 | if Length(args) > 0 then
151 | begin
152 | SetLength(Result, Length(args));
153 | for i := 0 to Pred(Length(args)) do
154 | FindType(args[i], Result[i]);
155 | end
156 | else
157 | begin
158 | if Assigned(BaseType) then
159 | Result := BaseType.GetGenericArguments;
160 | end;
161 | end;
162 |
163 | initialization
164 |
165 | Context := TRttiContext.Create;
166 |
167 | end.
168 |
--------------------------------------------------------------------------------
/ORM/Helpers/DelphiRestOrm.ORM.Helper.ObjectContainer.pas:
--------------------------------------------------------------------------------
1 | unit DelphiRestOrm.ORM.Helper.ObjectContainer;
2 |
3 | interface
4 |
5 | uses
6 | System.Classes, System.Generics.Collections;
7 |
8 | type
9 | TObjectContainer = class(TObjectList)
10 | public
11 | function Add: T; reintroduce; overload;
12 | function Add(aObject: T): T; overload;
13 | function Instance: T;
14 | procedure Remove;
15 | end;
16 |
17 | implementation
18 |
19 | uses
20 | System.TypInfo;
21 | { TObjectContainer }
22 |
23 | function TObjectContainer.Add: T;
24 | begin
25 | Result := Add(T.Create);
26 | end;
27 |
28 | function TObjectContainer.Add(aObject: T): T;
29 | begin
30 | inherited Add(aObject);
31 | Result := aObject;
32 | end;
33 |
34 | function TObjectContainer.Instance: T;
35 | var
36 | Obj: TObject;
37 | begin
38 | for Obj in Self do
39 | if (Obj is T) then
40 | exit(Obj as T);
41 | exit(nil);
42 | end;
43 |
44 | procedure TObjectContainer.Remove;
45 | var
46 | Obj: T;
47 | i: Integer;
48 | begin
49 | Obj := Instance;
50 | i := IndexOf(Obj);
51 | if i >= 0 then
52 | Delete(i);
53 | end;
54 |
55 | end.
56 |
--------------------------------------------------------------------------------
/ORM/Helpers/DelphiRestOrm.ORM.Helper.ThreadingEx.pas:
--------------------------------------------------------------------------------
1 | unit DelphiRestOrm.ORM.Helper.ThreadingEx;
2 |
3 | interface
4 |
5 | uses
6 | SysUtils,
7 | Threading;
8 |
9 | type
10 | TAction = reference to procedure(const arg: T);
11 |
12 | TTaskContinuationOptions = (NotOnCompleted, NotOnFaulted, NotOnCanceled, OnlyOnCompleted, OnlyOnFaulted, OnlyOnCanceled);
13 |
14 | ITaskEx = interface(ITask)
15 | ['{3AE1A614-27AA-4B5A-BC50-42483650E20D}']
16 | function GetExceptObj: Exception;
17 | function GetStatus: TTaskStatus;
18 | function ContinueWith(const continuationAction: TAction; continuationOptions: TTaskContinuationOptions): ITaskEx;
19 | function ContinueWithInMainThread(const continuationAction: TAction; continuationOptions: TTaskContinuationOptions): ITaskEx;
20 | property ExceptObj: Exception read GetExceptObj;
21 | property Status: TTaskStatus read GetStatus;
22 | end;
23 |
24 | TTaskEx = class(TTask, ITaskEx)
25 | private
26 | fExceptObj: Exception;
27 | function GetExceptObj: Exception;
28 | function InternalContinueWith(const continuationAction: TAction; continuationOptions: TTaskContinuationOptions; aMainThread: boolean): ITaskEx;
29 |
30 | protected
31 | function ContinueWith(const continuationAction: TAction; continuationOptions: TTaskContinuationOptions): ITaskEx;
32 | function ContinueWithInMainThread(const continuationAction: TAction; continuationOptions: TTaskContinuationOptions): ITaskEx;
33 | public
34 | destructor Destroy; override;
35 | class function Construct(const Proc: TProc): ITaskEx; overload; static; inline;
36 | class function Run(const action: TProc): ITaskEx; static;
37 | class function QueueMainThread(aDelay: Integer; const action: TProc): ITaskEx; overload;
38 | end;
39 |
40 | implementation
41 |
42 | uses
43 | Classes;
44 |
45 | { TTaskEx }
46 |
47 | function TTaskEx.ContinueWith(const continuationAction: TAction; continuationOptions: TTaskContinuationOptions): ITaskEx;
48 | begin
49 | Result := InternalContinueWith(continuationAction, continuationOptions, false);
50 |
51 | end;
52 |
53 | function TTaskEx.ContinueWithInMainThread(const continuationAction: TAction; continuationOptions: TTaskContinuationOptions): ITaskEx;
54 | begin
55 | Result := InternalContinueWith(continuationAction, continuationOptions, true);
56 | end;
57 |
58 | class function TTaskEx.Construct(const Proc: TProc): ITaskEx;
59 | begin
60 | Result := TTaskEx.Create(nil, TNotifyEvent(nil), Proc, TThreadPool.Default, nil);
61 | end;
62 |
63 | destructor TTaskEx.Destroy;
64 | begin
65 | fExceptObj.Free;
66 | inherited;
67 | end;
68 |
69 | function TTaskEx.GetExceptObj: Exception;
70 | begin
71 | Result := fExceptObj;
72 | end;
73 |
74 | function TTaskEx.InternalContinueWith(const continuationAction: TAction; continuationOptions: TTaskContinuationOptions; aMainThread: boolean): ITaskEx;
75 | begin
76 | Result := TTaskEx.Run(
77 | procedure
78 | var
79 | task: ITaskEx;
80 | doContinue: boolean;
81 | begin
82 | task := Self;
83 | if not IsComplete then
84 | DoneEvent.WaitFor;
85 | fExceptObj := GetExceptionObject;
86 | case continuationOptions of
87 | NotOnCompleted:
88 | doContinue := GetStatus <> TTaskStatus.Completed;
89 | NotOnFaulted:
90 | doContinue := GetStatus <> TTaskStatus.Exception;
91 | NotOnCanceled:
92 | doContinue := GetStatus <> TTaskStatus.Canceled;
93 | OnlyOnCompleted:
94 | doContinue := GetStatus = TTaskStatus.Completed;
95 | OnlyOnFaulted:
96 | doContinue := GetStatus = TTaskStatus.Exception;
97 | OnlyOnCanceled:
98 | doContinue := GetStatus = TTaskStatus.Canceled;
99 | else
100 | doContinue := false;
101 | end;
102 |
103 | if doContinue then
104 | if aMainThread then
105 | TThread.Synchronize(nil,
106 | procedure
107 | begin
108 | continuationAction(task);
109 | end)
110 | else
111 | continuationAction(task);
112 | end);
113 | end;
114 |
115 | class function TTaskEx.QueueMainThread(aDelay: Integer; const action: TProc): ITaskEx;
116 | begin
117 | Result := Run(
118 | procedure
119 | begin
120 | TThread.Sleep(aDelay);
121 | TThread.Queue(nil,
122 | procedure
123 | begin
124 | action;
125 | end);
126 | end);
127 | end;
128 |
129 | class function TTaskEx.Run(const action: TProc): ITaskEx;
130 | var
131 | task: TTaskEx;
132 | begin
133 | task := TTaskEx.Create(nil, TNotifyEvent(nil), action, TThreadPool.Default, nil);
134 | Result := task.Start as ITaskEx;
135 | end;
136 |
137 | end.
138 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Delphi-REST-Orm
2 | Delphi Rest Orm - At simple yet powerful ORM to query a WebService
3 |
4 | ## syntax Examples ##
5 |
6 | ``` pascal
7 |
8 | type
9 | TPerson = class
10 | private
11 | ...
12 | FAddress: string;
13 | ...
14 | published
15 | ...
16 | property Address: string read FAddress write FAddress;
17 | ...
18 | end;
19 |
20 |
21 | // Make the GET- requeest to a webservice, singin using basic authentication, and then parses the result into a type strong ObjecttList.
22 | var
23 | Persons: TObjectList;
24 | begin
25 | Persons := NewRequest('https://localhost:44303/Contact').Credentials('test', 'test').GET.AsType>;
26 | Memo1.Lines.Text := '(Random) Person.Address :' + Persons[Random(Persons.Count)].Address;
27 | Persons.Free;
28 | end;
29 |
30 |
31 | // Make a GET request, add a paramater, and return the raw content from the call
32 | var
33 | s: string;
34 | begin
35 | s := NewRequest('https://localhost:44303/Contact').GET(8).ToString;
36 | Memo1.Lines.Add(s);
37 | end;
38 |
39 |
40 | // Make a GET request to a Azure service. Using both a paramater and a query parameter. Returns the ras content
41 | var
42 | s: string;
43 | AzureAuthenticator: TAzureAuthenticator;
44 | begin
45 | AzureAuthenticator := TAzureAuthenticator.Create('', '', '', '');
46 | s := NewRequest('').Param(17794452).QueryParam('country', 'DK').AzureCredentials(AzureAuthenticator).GET.ToString;
47 | Memo1.Lines.Add(s);
48 | end;
49 |
50 | // Make an async GET request to a Azure service. Using both a paramater and a query parameter. The response are recived inside a callback function
51 | var
52 | AzureAuthenticator: TAzureAuthenticator;
53 | begin
54 | AzureAuthenticator := TAzureAuthenticator.Create('', '', '', '');
55 |
56 | NewRequestAsync('',
57 | procedure(const Response: TResponse)
58 | begin
59 | Memo1.Lines.Add(Response.ToString)
60 | end).Param(17794452).QueryParam('country', 'DK').AzureCredentials(AzureAuthenticator).GET;
61 | end;
62 |
63 | ```
64 |
65 |
66 |
67 | Features :
68 |
69 | This OrM can easy query a WEB Service. Featuring automatic serialization and deserialization, request and response type detection, variety of authentications and other useful features-
70 |
71 | ## Serialization ##
72 | JSON serialization and deserialization
73 |
74 | ## Authentication ##
75 | Basic, Azure are supported. Not enough? Write your own!
76 |
77 | ## Sync and Async ##
78 | Variety of overloads to make synchronous and asynchronous HTTP calls
79 |
80 | ## Parameters ##
81 | Add query, URL segment, body, form or header parameter using an easy and fluent API
82 |
--------------------------------------------------------------------------------
/RestServer/.vs/RestServer/DesignTimeBuild/.dtbcache.v2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JensBorrisholt/Delphi-REST-Orm/01cbb0ead71d3a98125e7613058e226ce76f330f/RestServer/.vs/RestServer/DesignTimeBuild/.dtbcache.v2
--------------------------------------------------------------------------------
/RestServer/.vs/RestServer/v16/.suo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JensBorrisholt/Delphi-REST-Orm/01cbb0ead71d3a98125e7613058e226ce76f330f/RestServer/.vs/RestServer/v16/.suo
--------------------------------------------------------------------------------
/RestServer/Demo Data/Create Table.sql:
--------------------------------------------------------------------------------
1 | drop table Persons
2 | drop table #Persons
3 |
4 | Declare @JSON varchar(max)
5 | SELECT @JSON=BulkColumn
6 | FROM OPENROWSET (BULK 'C:\aa\DemoData.json', SINGLE_CLOB) import
7 | SELECT *
8 | into #Persons
9 | FROM OPENJSON (@JSON)
10 | WITH
11 | (
12 | [id] NVARCHAR(24),
13 | [index] INT,
14 | [guid] NVARCHAR(36),
15 | [isActive] NVARCHAR(10),
16 | [balance] NVARCHAR(15),
17 | [picture] NVARCHAR(25),
18 | [age] INT,
19 | [eyeColor] NVARCHAR(5),
20 | [name] NVARCHAR(21),
21 | [gender] NVARCHAR(10),
22 | [company] NVARCHAR(7),
23 | [email] NVARCHAR(22),
24 | [phone] NVARCHAR(17),
25 | [address] NVARCHAR(100),
26 | [about] NVARCHAR(MAX),
27 | [registered] NVARCHAR(26),
28 | [latitude] float,
29 | [longitude] float,
30 | [greeting] NVARCHAR(47),
31 | [favoriteFruit] NVARCHAR(10)
32 | )
33 |
34 |
35 |
36 | create table Persons
37 | (
38 | [id] NVARCHAR(24) not null,
39 | [index] INT,
40 | [guid] NVARCHAR(36),
41 | [isActive] NVARCHAR(10),
42 | [balance] NVARCHAR(15),
43 | [picture] NVARCHAR(25),
44 | [age] INT,
45 | [eyeColor] NVARCHAR(5),
46 | [name] NVARCHAR(21),
47 | [gender] NVARCHAR(10),
48 | [company] NVARCHAR(7),
49 | [email] NVARCHAR(22),
50 | [phone] NVARCHAR(17),
51 | [address] NVARCHAR(100),
52 | [about] NVARCHAR(MAX),
53 | [registered] NVARCHAR(26),
54 | [latitude] float,
55 | [longitude] float,
56 | [greeting] NVARCHAR(47),
57 | [favoriteFruit] NVARCHAR(10),
58 | CONSTRAINT PK_Person PRIMARY KEY (ID)
59 | )
60 |
61 |
62 | insert into Persons
63 | select * from #Persons
--------------------------------------------------------------------------------
/RestServer/Demo Data/DemoData.json:
--------------------------------------------------------------------------------
1 | [{"id":"5fe30f37d7c04c9673a2c2a2","index":1,"guid":"2e71b858-a141-4ac6-8c7f-1d0c9d02d76d","isActive":"false","balance":"$2,464.88","picture":"http://placehold.it/32x32","age":34,"eyeColor":"green","name":"Mai Cherry","gender":"female","company":"QUORDAT","email":"maicherry@quordate.com","phone":"+1 (998) 403-3581","address":"934 Moore Street, Cucumber, Michigan, 182","about":"Laborum duis anim irure magna do laborum qui eu nisi. Nulla labore amet ullamco qui laborum. Labore dolor incididunt in tempor consequat eu laborum minim cillum fugiat ipsum aliqua ipsum. Proident cillum ex ex labore ad enim ipsum occaecat id in. Culpa sunt ullamco labore dolore quis eiusmod id. Aliqua ea consequat voluptate et do.\r\n","registered":"2015-08-26T08:36:30 -02:00","latitude":-51.445388,"longitude":-91.834623,"greeting":"Hello, Mai Cherry! You have 4 unread messages.","favoriteFruit":"apple"}]
2 |
--------------------------------------------------------------------------------
/RestServer/RestServer.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30320.27
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RestServer", "RestServer\RestServer.csproj", "{35A89729-461B-48BD-A944-360D4B271EB8}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {35A89729-461B-48BD-A944-360D4B271EB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {35A89729-461B-48BD-A944-360D4B271EB8}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {35A89729-461B-48BD-A944-360D4B271EB8}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {35A89729-461B-48BD-A944-360D4B271EB8}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {BA6514C3-4C16-4ABE-BA8E-36B088D87A1F}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/RestServer/RestServer/Controllers/ContactController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text.Json;
5 | using Microsoft.AspNetCore.Authorization;
6 | using Microsoft.AspNetCore.Mvc;
7 | using Microsoft.AspNetCore.Mvc.Infrastructure;
8 | using Newtonsoft.Json;
9 | using RestServer.Models;
10 |
11 | // For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
12 |
13 | namespace RestServer.Controllers
14 | {
15 | [Route("[controller]")]
16 | [ApiController]
17 | public class ContactController : ControllerBase
18 | {
19 | private static readonly Random _random = new Random();
20 | private static string RandomString(int length)
21 | {
22 | const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
23 | return new string(Enumerable.Repeat(chars, length)
24 | .Select(s => s[_random.Next(s.Length)]).ToArray());
25 | }
26 |
27 | // GET:
28 | [Authorize, RequireHttps, HttpGet]
29 | public IEnumerable Get() => new DemoDataContext().Persons.ToList();
30 |
31 |
32 | // GET /5
33 | [HttpGet("{id}")]
34 | public Person Get(int id) => new DemoDataContext().Persons.SingleOrDefault(e => e.Index == id);
35 |
36 |
37 | // POST
38 | [HttpPost]
39 | public Person Post([FromBody] JsonElement value)
40 | {
41 | var context = new DemoDataContext();
42 | var person = JsonConvert.DeserializeObject(value.ToString());
43 | person.Id = RandomString(24);
44 | person.Index = (context.Persons.Max(e => e.Index) ?? 0) + 1;
45 | context.Add(person);
46 | context.SaveChanges();
47 | return person;
48 | }
49 |
50 | // PUT /5
51 | [HttpPut("{id}")]
52 | public Person Put(int id, [FromBody] Person value)
53 | {
54 | var context = new DemoDataContext();
55 | var dbPerson = context.Persons.SingleOrDefault(e => e.Index == id);
56 |
57 | if (dbPerson == default(Person))
58 | throw new AmbiguousActionException($"No person by that id {id} found in the database");
59 |
60 | dbPerson.UpdateValues(value);
61 | context.Update(dbPerson);
62 | context.SaveChanges();
63 | return dbPerson;
64 | }
65 |
66 | // DELETE /5
67 | [HttpDelete("{id}")]
68 | public void Delete(int id)
69 | {
70 | var context = new DemoDataContext();
71 | var dbPerson = context.Persons.SingleOrDefault(e => e.Index == id);
72 |
73 | if (dbPerson == default(Person))
74 | throw new AmbiguousActionException($"No person by that id {id} found in the database");
75 |
76 | context.Persons.Remove(dbPerson);
77 | context.SaveChanges();
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/RestServer/RestServer/Helpers/BasicAuthenticationHandler.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net.Http.Headers;
3 | using System.Security.Claims;
4 | using System.Text;
5 | using System.Text.Encodings.Web;
6 | using System.Threading.Tasks;
7 | using Microsoft.AspNetCore.Authentication;
8 | using Microsoft.AspNetCore.Authorization;
9 | using Microsoft.AspNetCore.Http;
10 | using Microsoft.Extensions.Logging;
11 | using Microsoft.Extensions.Options;
12 | using RestServer.Models;
13 | using RestServer.Services;
14 |
15 | namespace RestServer.Helpers
16 | {
17 | public class BasicAuthenticationHandler : AuthenticationHandler
18 | {
19 | private readonly IUserService _userService;
20 |
21 | public BasicAuthenticationHandler(
22 | IOptionsMonitor options,
23 | ILoggerFactory logger,
24 | UrlEncoder encoder,
25 | ISystemClock clock,
26 | IUserService userService)
27 | : base(options, logger, encoder, clock)
28 | {
29 | _userService = userService;
30 | }
31 |
32 | protected override async Task HandleAuthenticateAsync()
33 | {
34 | // skip authentication if endpoint has [AllowAnonymous] attribute
35 | var endpoint = Context.GetEndpoint();
36 | if (endpoint?.Metadata?.GetMetadata() != null)
37 | return AuthenticateResult.NoResult();
38 |
39 | if (!Request.Headers.ContainsKey("Authorization"))
40 | return AuthenticateResult.Fail("Missing Authorization Header");
41 |
42 | User user = null;
43 | try
44 | {
45 | var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
46 | var credentialBytes = Convert.FromBase64String(authHeader.Parameter);
47 | var credentials = Encoding.UTF8.GetString(credentialBytes).Split(new[] { ':' }, 2);
48 | var username = credentials[0];
49 | var password = credentials[1];
50 | user = await _userService.Authenticate(username, password);
51 | }
52 | catch
53 | {
54 | return AuthenticateResult.Fail("Invalid Authorization Header");
55 | }
56 |
57 | if (user == null)
58 | return AuthenticateResult.Fail("Invalid Username or Password");
59 |
60 | var claims = new[] {
61 | new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
62 | new Claim(ClaimTypes.Name, user.Username),
63 | };
64 | var identity = new ClaimsIdentity(claims, Scheme.Name);
65 | var principal = new ClaimsPrincipal(identity);
66 | var ticket = new AuthenticationTicket(principal, Scheme.Name);
67 |
68 | return AuthenticateResult.Success(ticket);
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/RestServer/RestServer/Helpers/ExtensionMethods.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using RestServer.Models;
4 |
5 | namespace RestServer.Helpers
6 | {
7 | public static class ExtensionMethods
8 | {
9 | public static IEnumerable WithoutPasswords(this IEnumerable users) => users.Select(x => x.WithoutPassword());
10 |
11 | public static User WithoutPassword(this User user)
12 | {
13 | user.Password = null;
14 | return user;
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/RestServer/RestServer/Models/DemoDataContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.EntityFrameworkCore;
3 | using Microsoft.EntityFrameworkCore.Metadata;
4 |
5 | #nullable disable
6 |
7 | namespace RestServer.Models
8 | {
9 | public partial class DemoDataContext : DbContext
10 | {
11 | public DemoDataContext()
12 | {
13 | }
14 |
15 | public DemoDataContext(DbContextOptions options)
16 | : base(options)
17 | {
18 | }
19 |
20 | public virtual DbSet Persons { get; set; }
21 |
22 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
23 | {
24 | if (!optionsBuilder.IsConfigured)
25 | {
26 | #warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see http://go.microsoft.com/fwlink/?LinkId=723263.
27 | optionsBuilder.UseSqlServer("Server=Dellserver;Database=DemoData;Integrated Security=True;");
28 | }
29 | }
30 |
31 | protected override void OnModelCreating(ModelBuilder modelBuilder)
32 | {
33 | modelBuilder.HasAnnotation("Relational:Collation", "Danish_Norwegian_CI_AS");
34 |
35 | modelBuilder.Entity(entity =>
36 | {
37 | entity.Property(e => e.Id)
38 | .HasMaxLength(24)
39 | .HasColumnName("id");
40 |
41 | entity.Property(e => e.About).HasColumnName("about");
42 |
43 | entity.Property(e => e.Address)
44 | .HasMaxLength(43)
45 | .HasColumnName("address");
46 |
47 | entity.Property(e => e.Age).HasColumnName("age");
48 |
49 | entity.Property(e => e.Balance)
50 | .HasMaxLength(9)
51 | .HasColumnName("balance");
52 |
53 | entity.Property(e => e.Company)
54 | .HasMaxLength(7)
55 | .HasColumnName("company");
56 |
57 | entity.Property(e => e.Email)
58 | .HasMaxLength(22)
59 | .HasColumnName("email");
60 |
61 | entity.Property(e => e.EyeColor)
62 | .HasMaxLength(5)
63 | .HasColumnName("eyeColor");
64 |
65 | entity.Property(e => e.FavoriteFruit)
66 | .HasMaxLength(6)
67 | .HasColumnName("favoriteFruit");
68 |
69 | entity.Property(e => e.Gender)
70 | .HasMaxLength(10)
71 | .HasColumnName("gender");
72 |
73 | entity.Property(e => e.Greeting)
74 | .HasMaxLength(47)
75 | .HasColumnName("greeting");
76 |
77 | entity.Property(e => e.Guid)
78 | .HasMaxLength(36)
79 | .HasColumnName("guid");
80 |
81 | entity.Property(e => e.Index).HasColumnName("index");
82 |
83 | entity.Property(e => e.IsActive)
84 | .HasMaxLength(4)
85 | .HasColumnName("isActive");
86 |
87 | entity.Property(e => e.Latitude).HasColumnName("latitude");
88 |
89 | entity.Property(e => e.Longitude).HasColumnName("longitude");
90 |
91 | entity.Property(e => e.Name)
92 | .HasMaxLength(21)
93 | .HasColumnName("name");
94 |
95 | entity.Property(e => e.Phone)
96 | .HasMaxLength(17)
97 | .HasColumnName("phone");
98 |
99 | entity.Property(e => e.Picture)
100 | .HasMaxLength(25)
101 | .HasColumnName("picture");
102 |
103 | entity.Property(e => e.Registered)
104 | .HasMaxLength(26)
105 | .HasColumnName("registered");
106 | });
107 |
108 | OnModelCreatingPartial(modelBuilder);
109 | }
110 |
111 | partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/RestServer/RestServer/Models/Person.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Microsoft.EntityFrameworkCore;
4 |
5 | #nullable disable
6 |
7 | namespace RestServer.Models
8 | {
9 | public partial class Person
10 | {
11 | public string Id { get; set; }
12 | public int? Index { get; set; }
13 | public string Guid { get; set; }
14 | public string IsActive { get; set; }
15 | public string Balance { get; set; }
16 | public string Picture { get; set; }
17 | public int? Age { get; set; }
18 | public string EyeColor { get; set; }
19 | public string Name { get; set; }
20 | public string Gender { get; set; }
21 | public string Company { get; set; }
22 | public string Email { get; set; }
23 | public string Phone { get; set; }
24 | public string Address { get; set; }
25 | public string About { get; set; }
26 | public string Registered { get; set; }
27 | public double? Latitude { get; set; }
28 | public double? Longitude { get; set; }
29 | public string Greeting { get; set; }
30 | public string FavoriteFruit { get; set; }
31 |
32 | public Person UpdateValues(Person from)
33 | {
34 | if (Id != from.Id)
35 | throw new ApplicationException();
36 |
37 | foreach (var property in from.GetType().GetProperties())
38 | property.SetValue(this, property.GetValue(from));
39 |
40 | return this;
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/RestServer/RestServer/Models/User.cs:
--------------------------------------------------------------------------------
1 | namespace RestServer.Models
2 | {
3 | public class User
4 | {
5 | public int Id { get; set; }
6 | public string FirstName { get; set; }
7 | public string LastName { get; set; }
8 | public string Username { get; set; }
9 | public string Password { get; set; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/RestServer/RestServer/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Hosting;
6 | using Microsoft.Extensions.Configuration;
7 | using Microsoft.Extensions.Hosting;
8 | using Microsoft.Extensions.Logging;
9 |
10 | namespace RestServer
11 | {
12 | public class Program
13 | {
14 | public static void Main(string[] args)
15 | {
16 | CreateHostBuilder(args).Build().Run();
17 | }
18 |
19 | public static IHostBuilder CreateHostBuilder(string[] args) =>
20 | Host.CreateDefaultBuilder(args)
21 | .ConfigureWebHostDefaults(webBuilder =>
22 | {
23 | webBuilder.UseStartup();
24 | });
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/RestServer/RestServer/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json.schemastore.org/launchsettings.json",
3 | "iisSettings": {
4 | "windowsAuthentication": false,
5 | "anonymousAuthentication": true,
6 | "iisExpress": {
7 | "applicationUrl": "http://localhost:51155",
8 | "sslPort": 44303
9 | }
10 | },
11 | "profiles": {
12 | "IIS Express": {
13 | "commandName": "IISExpress",
14 | "launchBrowser": true,
15 | "launchUrl": "Contact/1",
16 | "environmentVariables": {
17 | "ASPNETCORE_ENVIRONMENT": "Development"
18 | }
19 | },
20 | "RestServer": {
21 | "commandName": "Project",
22 | "launchBrowser": true,
23 | "launchUrl": "Contact/1",
24 | "applicationUrl": "https://localhost:5001;http://localhost:5000",
25 | "environmentVariables": {
26 | "ASPNETCORE_ENVIRONMENT": "Development"
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/RestServer/RestServer/RestServer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | all
13 | runtime; build; native; contentfiles; analyzers; buildtransitive
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/RestServer/RestServer/RestServer.csproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MvcControllerEmptyScaffolder
5 | root/Common/MVC/Controller
6 |
7 |
--------------------------------------------------------------------------------
/RestServer/RestServer/Services/UserService.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 | using RestServer.Helpers;
5 | using RestServer.Models;
6 |
7 | namespace RestServer.Services
8 | {
9 | public interface IUserService
10 | {
11 | Task Authenticate(string username, string password);
12 | }
13 |
14 | public class UserService : IUserService
15 | {
16 | // users hardcoded for simplicity, store in a db with hashed passwords in production applications
17 | private readonly List _users = new List
18 | {
19 | new User { Id = 1, FirstName = "Test", LastName = "User", Username = "test", Password = "test" }
20 | };
21 |
22 | public async Task Authenticate(string username, string password)
23 | {
24 | var user = await Task.Run(() => _users.SingleOrDefault(x => x.Username == username && x.Password == password));
25 |
26 | // return null if user not found
27 | return user?.WithoutPassword();
28 |
29 | // authentication successful so return user details without password
30 | }
31 |
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/RestServer/RestServer/Startup.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Authentication;
2 | using Microsoft.AspNetCore.Builder;
3 | using Microsoft.AspNetCore.Hosting;
4 | using Microsoft.Extensions.Configuration;
5 | using Microsoft.Extensions.DependencyInjection;
6 | using Microsoft.Extensions.Hosting;
7 | using RestServer.Helpers;
8 | using RestServer.Services;
9 |
10 | namespace RestServer
11 | {
12 | public class Startup
13 | {
14 | public Startup(IConfiguration configuration)
15 | {
16 | Configuration = configuration;
17 | }
18 |
19 | public IConfiguration Configuration { get; }
20 |
21 | // This method gets called by the runtime. Use this method to add services to the container.
22 | public void ConfigureServices(IServiceCollection services)
23 | {
24 | // configure basic authentication
25 | services.AddAuthentication("BasicAuthentication")
26 | .AddScheme("BasicAuthentication", null);
27 |
28 | // configure DI for application services
29 | services.AddScoped();
30 |
31 | services.AddControllers();
32 | }
33 |
34 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
35 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
36 | {
37 | if (env.IsDevelopment())
38 | {
39 | app.UseDeveloperExceptionPage();
40 | }
41 |
42 | app.UseHttpsRedirection();
43 |
44 | app.UseRouting();
45 |
46 | app.UseAuthentication();
47 | app.UseAuthorization();
48 |
49 | app.UseEndpoints(endpoints =>
50 | {
51 | endpoints.MapControllers();
52 | });
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/RestServer/RestServer/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/RestServer/RestServer/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "AllowedHosts": "*"
10 | }
11 |
--------------------------------------------------------------------------------