├── README.md
├── RestRequest.pas
├── SimpleRestClient.groupproj
├── SimpleRestRequestSample.dpr
├── SimpleRestRequestSample.dproj
└── test
├── SimpleRestRequestTests.dpr
├── SimpleRestRequestTests.dproj
└── TestRestHttpWrapper.pas
/README.md:
--------------------------------------------------------------------------------
1 | ## Overview
2 | SimpleRestClient is a very simple, fluent wrapper around the Indy IdHttp client to make it easy to write RESTful clients. This client was built in Delphi XE2, but might well work in later versions.
3 |
4 | ## Usage
5 | This very simple console application creates a RESTful PUT request to add a fictional todo.
6 |
7 | ```delphi
8 | program SimpleRestRequestSample;
9 |
10 | {$APPTYPE CONSOLE}
11 |
12 | {$R *.res}
13 |
14 | uses
15 | System.SysUtils,
16 | Classes,
17 | RestRequest in 'RestRequest.pas';
18 |
19 | var RestReq: TRestRequest;
20 | RestResp: THttpResponse;
21 | putParams: TStringList;
22 | begin
23 | try
24 | try
25 | putParams := TStringList.Create();
26 | putParams.Add('title=Buy milk');
27 | putParams.Add('due-date=01/01/2013 00:00:00');
28 | RestReq := TRestRequest.Create().Domain('localhost').Path('todo').WithCredentials('test', 'test');
29 | RestResp := RestReq.Put(putParams);
30 | if RestResp.ResponseCode = 201 then WriteLn('Your todo was added!');
31 | finally
32 | RestReq.Free;
33 | end;
34 | except
35 | on E: Exception do
36 | Writeln(E.ClassName, ': ', E.Message);
37 | end;
38 | end.
39 | ```
40 |
41 | ## Limitations and improvements
42 | SimpleRestClient was thrown together pretty quickly to fill a need that I had and has limitations in areas that I didn't need or have time to do.
43 | * Test coverage - There is some test coverage but I didn't have time to mock out the Indy IdHttp client.
44 | * Patch support - The indy client doesn't support the PATCH request at present.
45 | * Accept headers - I'd like a better solution (read: more Delphi like) to Accept headers.
46 |
47 | ## Licensing
48 | Copyright (c) 2015, Jamie Ingilby
49 | All rights reserved.
50 |
51 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
52 |
53 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
54 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
55 | Neither the name of SimpleRestClient for Delphi nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
56 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/RestRequest.pas:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jamiei/SimpleRestClient/f9ceb8c48ac3f58fabe95cbfff43950770611a39/RestRequest.pas
--------------------------------------------------------------------------------
/SimpleRestClient.groupproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | {19213358-C3A3-4CA3-BBD2-6E7F92BDD92B}
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | Default.Personality.12
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/SimpleRestRequestSample.dpr:
--------------------------------------------------------------------------------
1 | program SimpleRestRequestSample;
2 |
3 | {$APPTYPE CONSOLE}
4 |
5 | {$R *.res}
6 |
7 | uses
8 | System.SysUtils,
9 | Classes,
10 | RestRequest in 'RestRequest.pas';
11 |
12 | var RestReq: TRestRequest;
13 | RestResp: THttpResponse;
14 | begin
15 | try
16 | RestReq := nil;
17 | try
18 | RestReq := TRestRequest.Create().Domain('jsonplaceholder.typicode.com').Path('todos').Path('1');
19 | RestResp := RestReq.Get();
20 | if RestResp.ResponseCode = 200 then WriteLn('Your todo was added!') else WriteLn('Failed to add your todo.');
21 | WriteLn(RestResp.ResponseStr);
22 | finally
23 | RestReq.Free;
24 | end;
25 | except
26 | on E: Exception do
27 | Writeln(E.ClassName, ': ', E.Message);
28 | end;
29 | end.
30 |
--------------------------------------------------------------------------------
/SimpleRestRequestSample.dproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | {E501D82E-B7B1-44D7-908A-52E367968669}
4 | 13.4
5 | None
6 | SimpleRestRequestSample.dpr
7 | True
8 | Debug
9 | Win32
10 | 1
11 | Console
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 | System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)
44 | bindcompfmx;fmx;rtl;dbrtl;IndySystem;DbxClientDriver;bindcomp;inetdb;DBXInterBaseDriver;xmlrtl;DbxCommonDriver;IndyProtocols;DBXMySQLDriver;dbxcds;soaprtl;bindengine;CustomIPTransport;dsnap;fmxase;IndyCore;inet;fmxobj;inetdbxpress;fmxdae;IPIndyImpl;dbexpress;$(DCC_UsePackage)
45 | .\$(Platform)\$(Config)
46 | .\$(Platform)\$(Config)
47 | false
48 | false
49 | false
50 | false
51 | false
52 |
53 |
54 | vclimg;vclactnband;vcldb;bindcompvcl;vcldsnap;vclie;vcltouch;websnap;VclSmp;vcl;dsnapcon;vclx;webdsnap;$(DCC_UsePackage)
55 |
56 |
57 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
58 | 1033
59 | vcldbx;TeeDB;vclib;inetdbbde;Tee;svnui;ibxpress;vclimg;fmi;intrawebdb_120_160;vclactnband;FMXTee;TeeUI;vcldb;bindcompvcl;vcldsnap;vclie;vcltouch;Intraweb_120_160;websnap;vclribbon;VclSmp;vcl;CloudService;CodeSiteExpressPkg;FmxTeeUI;dsnapcon;vclx;webdsnap;svn;bdertl;adortl;$(DCC_UsePackage)
60 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=
61 |
62 |
63 | DEBUG;$(DCC_Define)
64 | false
65 | true
66 | true
67 | true
68 |
69 |
70 | false
71 |
72 |
73 | false
74 | RELEASE;$(DCC_Define)
75 | 0
76 | false
77 |
78 |
79 |
80 | MainSource
81 |
82 |
83 |
84 | Cfg_2
85 | Base
86 |
87 |
88 | Base
89 |
90 |
91 | Cfg_1
92 | Base
93 |
94 |
95 |
96 | Delphi.Personality.12
97 |
98 |
99 |
100 |
101 | False
102 | False
103 | 1
104 | 0
105 | 0
106 | 0
107 | False
108 | False
109 | False
110 | False
111 | False
112 | 2057
113 | 1252
114 |
115 |
116 |
117 |
118 | 1.0.0.0
119 |
120 |
121 |
122 |
123 |
124 | 1.0.0.0
125 |
126 |
127 |
128 | SimpleRestRequestSample.dpr
129 |
130 |
131 |
132 |
133 | False
134 | False
135 | True
136 |
137 |
138 | 12
139 |
140 |
141 |
142 |
143 |
--------------------------------------------------------------------------------
/test/SimpleRestRequestTests.dpr:
--------------------------------------------------------------------------------
1 | program SimpleRestRequestTests;
2 | {
3 |
4 | Delphi DUnit Test Project
5 | -------------------------
6 | This project contains the DUnit test framework and the GUI/Console test runners.
7 | Add "CONSOLE_TESTRUNNER" to the conditional defines entry in the project options
8 | to use the console test runner. Otherwise the GUI test runner will be used by
9 | default.
10 |
11 | }
12 |
13 | {$IFDEF CONSOLE_TESTRUNNER}
14 | {$APPTYPE CONSOLE}
15 | {$ENDIF}
16 |
17 | uses
18 | TestRestHttpWrapper in 'TestRestHttpWrapper.pas',
19 | RestRequest in '..\RestRequest.pas',
20 | DUnitTestRunner;
21 |
22 | {R *.RES}
23 |
24 | begin
25 | DUnitTestRunner.RunRegisteredTests;
26 | end.
27 |
28 |
--------------------------------------------------------------------------------
/test/SimpleRestRequestTests.dproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | {371C787F-0816-46B0-8872-975520E015F1}
4 | 14.2
5 | None
6 | True
7 | Debug
8 | Win32
9 | 1
10 | Console
11 | SimpleRestRequestTests.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 | Base
34 | true
35 |
36 |
37 | true
38 | Cfg_1
39 | true
40 | true
41 |
42 |
43 | true
44 | Base
45 | true
46 |
47 |
48 | System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)
49 | $(BDS)\Source\DUnit\src;$(DCC_UnitSearchPath)
50 | _CONSOLE_TESTRUNNER;$(DCC_Define)
51 | .
52 | .\$(Platform)\$(Config)
53 | false
54 | false
55 | false
56 | false
57 | false
58 |
59 |
60 | bindcompfmx;DBXSqliteDriver;fmx;rtl;dbrtl;IndySystem;DbxClientDriver;bindcomp;inetdb;DBXInterBaseDriver;DataSnapClient;DataSnapCommon;DBXOdbcDriver;DataSnapServer;DataSnapProviderClient;xmlrtl;DbxCommonDriver;DBXSybaseASEDriver;vclimg;IndyProtocols;DBXMySQLDriver;dbxcds;bindengine;vclactnband;vcldb;soaprtl;vcldsnap;bindcompvcl;vclie;vcltouch;DBXDb2Driver;websnap;DBXOracleDriver;CustomIPTransport;VclSmp;dsnap;IndyIPServer;DBXInformixDriver;IndyCore;vcl;fmxase;IndyIPCommon;DBXMSSQLDriver;dsnapcon;DBXFirebirdDriver;inet;fmxobj;vclx;inetdbxpress;webdsnap;DBXSybaseASADriver;fmxdae;dbexpress;DataSnapIndy10ServerTransport;IndyIPClient;$(DCC_UsePackage)
61 |
62 |
63 | bindcompfmx;DBXSqliteDriver;fmx;rtl;dbrtl;IndySystem;DbxClientDriver;bindcomp;inetdb;DBXInterBaseDriver;DataSnapClient;DataSnapCommon;DataSnapServer;DataSnapProviderClient;xmlrtl;DbxCommonDriver;IndyProtocols;DBXMySQLDriver;dbxcds;bindengine;soaprtl;DBXOracleDriver;CustomIPTransport;dsnap;IndyIPServer;DBXInformixDriver;IndyCore;fmxase;IndyIPCommon;DBXFirebirdDriver;inet;fmxobj;inetdbxpress;DBXSybaseASADriver;fmxdae;dbexpress;DataSnapIndy10ServerTransport;IndyIPClient;$(DCC_UsePackage)
64 |
65 |
66 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
67 | 1033
68 | bindcompfmx;DBXSqliteDriver;vcldbx;fmx;rtl;dbrtl;IndySystem;DbxClientDriver;bindcomp;inetdb;vclib;inetdbbde;DBXInterBaseDriver;DataSnapClient;DataSnapCommon;DBXOdbcDriver;DataSnapServer;DataSnapProviderClient;xmlrtl;svnui;ibxpress;DbxCommonDriver;DBXSybaseASEDriver;vclimg;IndyProtocols;DBXMySQLDriver;dbxcds;bindengine;vclactnband;vcldb;soaprtl;vcldsnap;bindcompvcl;vclie;vcltouch;DBXDb2Driver;websnap;DBXOracleDriver;CustomIPTransport;vclribbon;VclSmp;dsnap;IndyIPServer;DBXInformixDriver;IndyCore;vcl;fmxase;DataSnapConnectors;IndyIPCommon;CloudService;DBXMSSQLDriver;dsnapcon;DBXFirebirdDriver;inet;fmxobj;vclx;inetdbxpress;webdsnap;svn;DBXSybaseASADriver;fmxdae;bdertl;dbexpress;DataSnapIndy10ServerTransport;adortl;IndyIPClient;$(DCC_UsePackage)
69 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=
70 |
71 |
72 | DEBUG;$(DCC_Define)
73 | false
74 | true
75 | true
76 | true
77 |
78 |
79 | false
80 |
81 |
82 | false
83 | RELEASE;$(DCC_Define)
84 | 0
85 | false
86 |
87 |
88 |
89 | MainSource
90 |
91 |
92 |
93 |
94 | Cfg_2
95 | Base
96 |
97 |
98 | Base
99 |
100 |
101 | Cfg_1
102 | Base
103 |
104 |
105 |
106 | Delphi.Personality.12
107 |
108 |
109 |
110 |
111 | False
112 | False
113 | 1
114 | 0
115 | 0
116 | 0
117 | False
118 | False
119 | False
120 | False
121 | False
122 | 2057
123 | 1252
124 |
125 |
126 |
127 |
128 | 1.0.0.0
129 |
130 |
131 |
132 |
133 |
134 | 1.0.0.0
135 |
136 |
137 |
138 | SimpleRestRequestTests.dpr
139 |
140 |
141 |
142 |
143 | False
144 | False
145 | True
146 |
147 |
148 | DUnit / Delphi Win32
149 | GUI
150 | D:\Dev\Delphi XE2 Projects\Waurie\Waurie.dproj
151 |
152 |
153 | 12
154 |
155 |
156 |
157 |
158 |
--------------------------------------------------------------------------------
/test/TestRestHttpWrapper.pas:
--------------------------------------------------------------------------------
1 | unit TestRestHttpWrapper;
2 | {
3 |
4 | Delphi DUnit Test Case
5 | ----------------------
6 | This unit contains a skeleton test case class generated by the Test Case Wizard.
7 | Modify the generated code to correctly setup and call the methods from the unit
8 | being tested.
9 |
10 | }
11 |
12 | interface
13 |
14 | uses
15 | TestFramework, IdHttp, Data.DBXJSON, IdAuthentication, Classes, SysUtils,
16 | RestRequest, IdMultipartFormData, IdURI;
17 |
18 | type
19 | // Test methods for class TRestRequest
20 |
21 | TestTRestRequest = class(TTestCase)
22 | strict private
23 | FRestRequest: TRestRequest;
24 | public
25 | procedure SetUp; override;
26 | procedure TearDown; override;
27 | published
28 | procedure TestDomain;
29 | procedure TestPath;
30 | procedure TestMultiPath;
31 | procedure TestSingleParam;
32 | procedure TestMultiParam;
33 | procedure TestWithCredentials;
34 | procedure TestGet;
35 | procedure TestPut;
36 | procedure TestPost;
37 | procedure TestDelete;
38 | end;
39 |
40 | implementation
41 |
42 | procedure TestTRestRequest.SetUp;
43 | begin
44 | FRestRequest := TRestRequest.Create;
45 | end;
46 |
47 | procedure TestTRestRequest.TearDown;
48 | begin
49 | FRestRequest.Free;
50 | FRestRequest := nil;
51 | end;
52 |
53 | procedure TestTRestRequest.TestDomain;
54 | var
55 | Request: TRestRequest;
56 | aDomain: string;
57 | begin
58 | aDomain := 'api.test.com';
59 | FRestRequest := FRestRequest.Domain(aDomain);
60 | Assert(FRestRequest.FullUrl = 'http://api.test.com', 'Domain test: ' + FRestRequest.FullUrl);
61 | end;
62 |
63 | procedure TestTRestRequest.TestPath;
64 | var
65 | ReturnValue: TRestRequest;
66 | aPath: string;
67 | begin
68 | aPath := 'player';
69 | FRestRequest := FRestRequest.Path(aPath);
70 | Assert(FRestRequest.FullUrl = 'http:///' + aPath, 'Single Path Test: ' + FRestRequest.FullUrl);
71 | end;
72 |
73 | procedure TestTRestRequest.TestSingleParam;
74 | var
75 | ReturnValue: TRestRequest;
76 | aValue: string;
77 | aKey: string;
78 | Expected: string;
79 | begin
80 | aKey := 'limit';
81 | aValue := '20';
82 | ReturnValue := FRestRequest.Param(aKey, aValue);
83 | Expected := 'http://?' + aKey + '=' + aValue;
84 | Assert(FRestRequest.FullUrl = Expected, 'Single Param Test: ' + FRestRequest.FullUrl + ' - Expected: ' + Expected);
85 | end;
86 |
87 | procedure TestTRestRequest.TestWithCredentials;
88 | var
89 | ReturnValue: TRestRequest;
90 | password: string;
91 | username: string;
92 | begin
93 | // TODO: Setup method call parameters
94 | ReturnValue := FRestRequest.WithCredentials(username, password);
95 | // TODO: Validate method results
96 | end;
97 |
98 |
99 | procedure TestTRestRequest.TestGet;
100 | var
101 | ReturnValue: THttpResponse;
102 | begin
103 | //ReturnValue := FRestRequest.Get;
104 | // TODO: Validate method results
105 | end;
106 |
107 | procedure TestTRestRequest.TestMultiParam;
108 | var
109 | ReturnValue: TRestRequest;
110 | aValue1, aValue2: string;
111 | aKey1, aKey2: string;
112 | Expected: string;
113 | begin
114 | // Param 1
115 | aKey1 := 'limit';
116 | aValue1 := '20';
117 | // Param 2
118 | aKey2 := 'type';
119 | aValue2 := 'member';
120 | ReturnValue := FRestRequest.Param(aKey1, aValue1).Param(aKey2, aValue2);
121 | Expected := 'http://?' + aKey1 + '=' + aValue1 + '&' + aKey2 + '=' + aValue2;
122 | Assert(FRestRequest.FullUrl = Expected, 'Single Param Test: ' + FRestRequest.FullUrl + ' - Expected: ' + Expected);
123 |
124 | end;
125 |
126 | procedure TestTRestRequest.TestMultiPath;
127 | var
128 | ReturnValue: TRestRequest;
129 | aPath, aPath2: string;
130 | begin
131 | aPath := 'player';
132 | aPath2 := '1';
133 | FRestRequest := FRestRequest.Path(aPath).Path(aPath2);
134 | Assert(FRestRequest.FullUrl = 'http:///' + aPath + '/' + aPath2, 'Double Path Test: ' + FRestRequest.FullUrl);
135 | end;
136 |
137 | procedure TestTRestRequest.TestPut;
138 | var
139 | ReturnValue: THttpResponse;
140 | aParams: TStringList;
141 | begin
142 | // TODO: Setup method call parameters
143 | //ReturnValue := FRestRequest.Put(aParams);
144 | // TODO: Validate method results
145 | end;
146 |
147 | procedure TestTRestRequest.TestPost;
148 | var
149 | ReturnValue: THttpResponse;
150 | aParams: TStringList;
151 | begin
152 | // TODO: Setup method call parameters
153 | //ReturnValue := FRestRequest.Post(aParams);
154 | // TODO: Validate method results
155 | end;
156 |
157 | procedure TestTRestRequest.TestDelete;
158 | var
159 | ReturnValue: THttpResponse;
160 | begin
161 | //ReturnValue := FRestRequest.Delete;
162 | // TODO: Validate method results
163 | end;
164 |
165 | initialization
166 | // Register any test cases with the test runner
167 | RegisterTest(TestTRestRequest.Suite);
168 | end.
169 |
170 |
--------------------------------------------------------------------------------