Qore RestClient Module Reference 1.9.3
Loading...
Searching...
No Matches
RestClient.qm.dox.h
1// -*- mode: c++; indent-tabs-mode: nil -*-
3
4/* RestClient.qm Copyright (C) 2013 - 2023 Qore Technologies, s.r.o.
5
6 Permission is hereby granted, free of charge, to any person obtaining a
7 copy of this software and associated documentation files (the "Software"),
8 to deal in the Software without restriction, including without limitation
9 the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 and/or sell copies of the Software, and to permit persons to whom the
11 Software is furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 DEALINGS IN THE SOFTWARE.
23*/
24
25// minimum qore version
26
27// require type definitions everywhere
28
29// enable all warnings
30
31// don't use "$" for vars, members, and methods, assume local variable scope
32
33
34
35
36
37
38}
39
40/* Version History - see below in docs
41*/
42
208namespace RestClient {
211
212public:
214 const DataSerializationSupport = {
215%ifndef NoJson
216 "json": MimeTypeJson,
217%endif
218%ifndef NoYaml
219 "yaml": MimeTypeYaml,
220%endif
221%ifndef NoXml
222 "xml": MimeTypeXml,
223 "rawxml": MimeTypeXmlApp,
224%endif
225 "url": MimeTypeFormUrlEncoded,
226 "text": MimeTypeText,
227 "bin": MimeTypeOctetStream,
228 };
229
230 const DeserializeYaml = {
231 "code": "yaml",
232 "in": \parse_yaml(),
233 };
234 const DeserializeXml = {
235 "code": "xml",
236 "arg": True,
237 "in": hash<auto> sub (string xml, reference<string> type) {
238 try {
239 on_success type = "xml";
240 return parse_xmlrpc_value(xml);
241 } catch (hash<ExceptionInfo> ex) {
242 try {
243 on_success type = "rawxml";
244 return parse_xml(xml);
245 } catch () {
246 rethrow;
247 }
248 }
249 },
250 };
251
253 const AcceptList = ...;
254
255
257 const Accept = AcceptList.join(",");
258
260 const AcceptMap = map {$1: True}, AcceptList;
261
263 const Version = "1.7";
264
266 const VersionString = sprintf("Qore-RestClient/%s", RestClient::Version);
267
269 const DefaultHeaders = {
270 "Accept": Accept,
271 "User-Agent": RestClient::VersionString,
272 };
273
275
285 const DataSerializationOptions = {
286 "auto": True,
287%ifndef NoJson
288 "json": True,
289%endif
290%ifndef NoYaml
291 "yaml": True,
292%endif
293%ifndef NoXml
294 "rawxml": True,
295 "xml": True,
296%endif
297 "url": True,
298 "text": True,
299 "bin": True,
300 };
301
303
309 const EncodingSupport = {
310 "gzip": {
311 "ce": "gzip",
312 "func": \gzip(),
313 },
314 "bzip2": {
315 "ce": "bzip2",
316 "func": \bzip2(),
317 },
318 "deflate": {
319 "ce": "deflate",
320 "func": \compress(),
321 },
322 "identity": {
323 "ce": NOTHING,
324 },
325 };
326
328 const CompressionThreshold = 1024;
329
330protected:
331 // headers to send with every request
332 hash<auto> headers;
333 // data serialization code
334 string ds;
335 // serialization content type
336 string sct;
337 // send content encoding hash
338 *hash<auto> seh;
339 // REST schema validator
341 // no_charset option
342 *bool noCharset;
343
344public:
345
347
408 constructor(*hash<auto> opts, *softbool do_not_connect) : HTTPClient(opts + ((opts.url || !opts.validator)
409 ? NOTHING
410 ;
411
412
414
416 clearConnectionPath();
417
418
420
431 setSerialization(string data = 'auto');
432
433
435
450 setSendEncoding(string enc = 'auto');
451
452
454
469 setContentEncoding(string enc = 'auto');
470
471
473
487 addDefaultHeaders(hash<auto> h);
488
489
491
504 hash<auto> getDefaultHeaders();
505
506
508
521 *string getSendEncoding();
522
523
525
534 string getSerialization();
535
536
538
579 hash<auto> get(string path, auto body, *reference<hash<auto>> info, *hash<auto> hdr);
580
581
583
623 hash<auto> put(string path, auto body, *reference<hash<auto>> info, *hash<auto> hdr);
624
625
627
667 hash<auto> patch(string path, auto body, *reference<hash<auto>> info, *hash<auto> hdr);
668
669
671
722 hash<auto> post(string path, auto body, *reference<hash<auto>> info, *hash<auto> hdr);
723
724
726
777 hash<auto> del(string path, auto body, *reference<hash<auto>> info, *hash<auto> hdr);
778
779
781
786
787
789 private nothing prepareMsg(string method, string path, reference<auto> body, reference<hash<auto>> hdr,
790 string ct = "Content-Type") {
791 // use {} + ... here to ensure that hdr stays "hash<auto>"
792 hdr = {} + headers + hdr;
793
794 // must get the path from the HTTPClient object if not given in the request
795 if (!path.val() && (*string p = getConnectionPath()))
796 path = p;
797
798 hash<RestRequestClientInfo> req = validator.processRequest(method, path, body, hdr, sct);
799
800 if (exists body);
801
802 }
803
805protected:
806 nothing preparePath(reference<string> path);
807public:
808
809
811
871 hash<auto> doRequest(string m, string path, auto body, *reference<hash<auto>> info, softbool decode_errors = True,
872 *hash<auto> hdr) {
873 prepareMsg(m, path, \body, \hdr);
874
875 on_exit if (exists body);
876
877
878 // prepare path
879 preparePath(\path);
880
881 on_error rethrow $1.err, sprintf("%s (REST URL %y)", $1.desc, getSafeURL());
882
883 return sendAndDecodeResponse(body, m, path, hdr, \info, decode_errors);
884 }
885
887
889 hash<auto> doValidatedRequest(string m, string path, auto body, *reference<hash<auto>> info,
890 softbool decode_errors = True, *hash<auto> hdr) {
891 // use {} + ... here to ensure that hdr stays "hash<auto>"
892 hdr = {} + headers + hdr;
893
894 on_exit if (exists body);
895
896
897 return sendAndDecodeResponse(body, m, path, hdr, \info, decode_errors);
898 }
899
901 private hash<auto> sendAndDecodeResponse(*data body, string m, string path, hash<auto> hdr,
902 *reference<hash<auto>> info, *softbool decode_errors) {
903 hash<auto> h;
904 try {
905 h = send(body, m, path, hdr, False, \info);
906 info."response-code" = h.status_code;
907 } catch (hash<ExceptionInfo> ex) {
908 info."response-code" = info."response-headers".status_code;
909 if (ex.arg) {
910 if (decode_errors && ex.arg.body) {
911 decodeError(ex.arg, \info);
912 ex.arg.deserialized_body = info."response-body";
913 }
914 }
915
916 rethrow ex.err, ex.desc, ex.arg;
917 }
918
919 on_error {
920 if (exists h.body && !exists info."response-body") {
921 info."response-body" = h.body;
922 }
923 }
924
925 return processRestResponse(h, m, path, \info);
926 }
927
929
936protected:
937 hash<auto> processRestResponse(hash<auto> resp, string method, string path, *reference<hash<auto>> info);
938public:
939
940
942protected:
943 static decodeError(hash<auto> h, *reference<hash<auto>> info);
944public:
945
946
948private:
949 static tryDecodeErrorResponse(reference<hash<auto>> h, *reference<hash<auto>> info);
950public:
951
952
953}; // class RestClient
954
956
997
998public:
1000 hash<auto> real_opts;
1001
1003 const ConnectionScheme = <ConnectionSchemeInfo>{
1004 "cls": Class::forName("RestConnection"),
1005 "options": HttpConnection::ConnectionScheme.options + {
1006 "content_encoding": <ConnectionOptionInfo>{
1007 "type": "string",
1008 "desc": "this sets the send encoding (if the `send_encoding` option is not set) and the "
1009 "response encoding to request",
1010 "allowed_values": (
1011 <AllowedValueInfo>{
1012 "value": "gzip",
1013 "desc": "use GNU zip encoding ([RFC 1952](https://tools.ietf.org/html/rfc1952))",
1014 }, <AllowedValueInfo>{
1015 "value": "bzip2",
1016 "desc": "use bzip2 encoding",
1017 }, <AllowedValueInfo>{
1018 "value": "deflate",
1019 "desc": "use the deflate algorithm ([RFC 1951](https://tools.ietf.org/html/rfc1951))",
1020 }, <AllowedValueInfo>{
1021 "value": "identity",
1022 "desc": "use no content encoding",
1023 },
1024 ),
1025 },
1026 "data": <ConnectionOptionInfo>{
1027 "type": "string",
1028 "desc": "data serialization options",
1029 "allowed_values": (
1030 <AllowedValueInfo>{
1031 "value": "auto",
1032 "desc": "prefers in this order: `json`, `yaml`, `rawxml`, `xml`, `url`, and `text`",
1033 }, <AllowedValueInfo>{
1034 "value": "bin",
1035 "desc": "for binary message bodies without data serialization",
1036 }, <AllowedValueInfo>{
1037 "value": "json",
1038 "desc": "use JSON serialization",
1039 }, <AllowedValueInfo>{
1040 "value": "rawxml",
1041 "desc": "use raw XML serialization",
1042 }, <AllowedValueInfo>{
1043 "value": "text",
1044 "desc": "use only plain text; no serialization is used",
1045 }, <AllowedValueInfo>{
1046 "value": "url",
1047 "desc": "for URL-encoded message bodies",
1048 }, <AllowedValueInfo>{
1049 "value": "xml",
1050 "desc": "use only XML-RPC serialization",
1051 }, <AllowedValueInfo>{
1052 "value": "yaml",
1053 "desc": "use only YAML serialization",
1054 },
1055 ),
1056 "default_value": "auto",
1057 },
1058 "headers": <ConnectionOptionInfo>{
1059 "type": "hash",
1060 "desc": "an optional hash of headers to send with every request, these can also be "
1061 "overridden in request method calls",
1062 },
1063 "ping_method": <ConnectionOptionInfo>{
1064 "type": "string",
1065 "desc": "The HTTP method to use for an advanced ping; this and `ping_path` must be set to make an "
1066 "HTTP request as a part of the socket polling ping operation; must be a valid HTTP method name",
1067 },
1068 "ping_path": <ConnectionOptionInfo>{
1069 "type": "string",
1070 "desc": "The URI path to use for an advanced ping; this and `ping_method` must be made to make an "
1071 "HTTP request as a part of the socket polling ping operation",
1072 },
1073 "ping_headers": <ConnectionOptionInfo>{
1074 "type": "hash",
1075 "desc": "Any HTTP headers to send when performing an advanced ping operation; ignored if either "
1076 "one of `ping_method` and `ping_path` are not set",
1077 },
1078 "ping_body": <ConnectionOptionInfo>{
1079 "type": "auto",
1080 "desc": "Any message body to send when performing an advanced ping operation; ignored if either "
1081 "one of `ping_method` and `ping_path` are not set or if `ping_method` is `GET`",
1082 },
1083 "send_encoding": <ConnectionOptionInfo>{
1084 "type": "string",
1085 "desc": "this sets the send encoding",
1086 "allowed_values": (
1087 <AllowedValueInfo>{
1088 "value": "gzip",
1089 "desc": "use GNU zip encoding ([RFC 1952](https://tools.ietf.org/html/rfc1952))",
1090 }, <AllowedValueInfo>{
1091 "value": "bzip2",
1092 "desc": "use bzip2 encoding",
1093 }, <AllowedValueInfo>{
1094 "value": "deflate",
1095 "desc": "use the deflate algorithm ([RFC 1951](https://tools.ietf.org/html/rfc1951))",
1096 }, <AllowedValueInfo>{
1097 "value": "identity",
1098 "desc": "use no content encoding",
1099 },
1100 ),
1101 },
1102 "swagger": <ConnectionOptionInfo>{
1103 "type": "file-as-string",
1104 "desc": "the location of a Swagger schema to use for message validation; processed with "
1105 "`FileLocationHandler::getTextFileFromLocation()` "
1106 "(ex: `file:///path/to/swagger-schema.json`); conflicts with `validator`",
1107 "freeform": True,
1108 },
1109 "swagger_base_path": <ConnectionOptionInfo>{
1110 "type": "string",
1111 "desc": "in case a REST validator is used, the base path in the schema can be overridden "
1112 "with this option (applies to any REST validator; not just Swagger validators)",
1113 },
1114 "validator": <ConnectionOptionInfo>{
1115 "type": "any",
1116 "desc": "an `AbstractRestSchemaValidator` object for REST message validation; conflicts with "
1117 "`swagger`",
1118 },
1119 },
1120 };
1121
1123 const Options = map {$1: True}, keys ConnectionScheme.options;
1124
1126 const DefaultOptions = ...;
1127
1128
1130 const OptionList = keys ConnectionScheme.options;
1131
1133
1146 constructor(string name, string description, string url, hash<auto> attributes = {}, hash<auto> options = {})
1147 ;
1148
1149
1151
1159protected:
1160 RestClient getImpl(bool connect = True, *hash<auto> rtopts);
1161public:
1162
1163
1165
1169 object getPollImpl();
1170
1171
1173
1204 hash<auto> getOptions();
1205
1206
1208 *hash<auto> getDefaultOptions();
1209
1210
1212 string getType();
1213
1214
1216
1223
1224
1226
1231
1232
1234
1240
1241
1243
1245 static hash<auto> processOptions(*hash<auto> opts);
1246
1248
1250protected:
1252public:
1253
1254
1256protected:
1258public:
1259
1260
1262protected:
1263 hash<ConnectionSchemeInfo> getConnectionSchemeInfoImpl();
1264public:
1265
1266};
1267
1269
1272
1273public:
1274protected:
1276 AbstractPollOperation poller;
1277
1279 bool goal_reached = False;
1280
1282 Mutex m();
1283
1284public:
1285
1287 constructor(AbstractPollOperation poller);
1288
1289
1291
1293 string getGoal();
1294
1295
1297
1299 string getState();
1300
1301
1303
1306
1307
1309 *hash<SocketPollInfo> continuePoll();
1310
1311};
1312};
const VersionString
RestClient Version String.
Definition: RestClient.qm.dox.h:266
const Version
RestClient Version.
Definition: RestClient.qm.dox.h:263
class for REST HTTP connections; returns RestClient::RestClient objects
Definition: RestClient.qm.dox.h:996
bool hasDataProvider()
returns True, as this connection always returns a data provider with the getDataProvider() method
*hash< auto > getDefaultOptions()
returns default options
pingImpl()
performs the internal ping
const OptionList
object connection option list
Definition: RestClient.qm.dox.h:1130
constructor(string name, string description, string url, hash< auto > attributes={}, hash< auto > options={})
creates the RestConnection connection object
hash< auto > real_opts
real options used when creating an object
Definition: RestClient.qm.dox.h:1000
const Options
object connection options
Definition: RestClient.qm.dox.h:1123
const DefaultOptions
default options
Definition: RestClient.qm.dox.h:1126
hash< ConnectionSchemeInfo > getConnectionSchemeInfoImpl()
Returns the ConnectionSchemeInfo hash for this object.
Qore::AbstractPollOperation startPollConnect()
Called to start a non-blocking polling ping operation on the remote REST server.
object getPollImpl()
Returns an unconnected object for a non-blocking poll operation.
setChildCapabilities()
Sets child data provider capabilities.
RestClient getImpl(bool connect=True, *hash< auto > rtopts)
returns a RestClient object
static hash< auto > processOptions(*hash< auto > opts)
processes options for the constructor
hash< auto > getOptions()
gets options
const ConnectionScheme
Connection entry info.
Definition: RestClient.qm.dox.h:1003
string getType()
returns "rest"
DataProvider::AbstractDataProvider getDataProvider()
returns a data provider object for this connection
REST ping polling class.
Definition: RestClient.qm.dox.h:1271
constructor(AbstractPollOperation poller)
Creates the object with the send/receive poller.
*hash< SocketPollInfo > continuePoll()
Returns a hash to be used for I/O polling or NOTHING in case the poll operation is complete.
string getGoal()
Returns the goal.
bool goalReached()
Returns True when the goal as been reached.
AbstractPollOperation poller
The polling object.
Definition: RestClient.qm.dox.h:1276
bool goal_reached
Goal reached flag.
Definition: RestClient.qm.dox.h:1279
string getState()
Returns the current state.
Mutex m()
Lock for atomicity.
hash< RestRequestClientInfo > processRequest(string method, string path, auto body, *hash< auto > headers, *softlist< string > content_types)
string type(auto arg)
the RestClient namespace contains all the objects in the RestClient module
Definition: RestClient.qm.dox.h:208