-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathClient-API.html
executable file
·800 lines (749 loc) · 57.1 KB
/
Client-API.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
<!DOCTYPE html>
<html lang="en">
<head>
<!--__GOLF_REDIRECT__-->
<title>Client API</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="HandheldFriendly" content="True"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<link rel="canonical" href="https://golf-lang.com/Client-API.html" />
<style>
body, html {
color:black;
text-rendering: optimizelegibility;
background-color: white;
min-height: 150%;
font-family: "Times New Roman";
font-weight:400;
font-size:18px;
line-height:27px;
letter-spacing: 2px;
z-index: 1;
height: 100%;
text-align:left;
width:80%;
margin-left:auto;
margin-right:auto;
padding:0;
/*font-family: Helvetica, Arial, sans-serif;*/
}
body {
padding-left:1vw;
padding-right:1vw;
}
.ncode {
line-height:20px;
letter-spacing: 0px;
font-size:14px;
font-family: monospace;
display:inline-block;
max-width:100%;
min-width:90%;
margin:0;
padding:0;
padding-left:5px;
padding-top:3px;
padding-bottom:3px;
margin-bottom:15px;
border: 2px solid #d6d6d6;
background-color:#f5f7f4;
white-space:nowrap;
}
.shcode {
line-height:23px;
letter-spacing: 0px;
font-size:14px;
font-family: monospace;
display:inline-block;
max-width:100%;
min-width:90%;
margin:0;
padding:0;
padding-left:5px;
padding-top:3px;
padding-bottom:3px;
margin-bottom:15px;
border: 2px solid #d6d6d6;
background-color:#f5f7f4;
white-space:nowrap;
}
.sqlcode {
line-height:23px;
letter-spacing: 0px;
font-size:14px;
font-family: monospace;
display:inline-block;
max-width:100%;
min-width:90%;
margin:0;
padding:0;
padding-left:5px;
padding-top:3px;
padding-bottom:3px;
margin-bottom:15px;
border: 2px solid #d6d6d6;
background-color:#f5f7f4;
white-space:nowrap;
}
.htmlcode {
line-height:23px;
letter-spacing: 0px;
font-size:14px;
font-family: monospace;
display:inline-block;
max-width:100%;
min-width:90%;
margin:0;
padding:0;
padding-left:5px;
padding-top:3px;
padding-bottom:3px;
margin-bottom:15px;
border: 2px solid #d6d6d6;
background-color:#f5f7f4;
white-space:nowrap;
}
.code {
line-height:23px;
letter-spacing: 0px;
font-size:14px;
font-family: monospace;
display:inline-block;
max-width:100%;
min-width:90%;
margin:0;
padding:0;
padding-left:5px;
padding-top:3px;
padding-bottom:3px;
margin-bottom:15px;
border: 2px solid #d6d6d6;
background-color:#f5f7f4;
white-space:nowrap;
}
/*Just like h1 but for pdf conversion it would be indented this way it's not*/
.vhub {
display: block;
font-size: 1.6em;
margin-top: 0.63em;
margin-bottom: 0.63em;
margin-left: 0;
margin-right: 0;
font-weight: bold;
}
/*Just like h2 but for pdf conversion it would be indented this way it's not*/
.vsub {
display: block;
font-size: 1.25em;
margin-top: 0.53em;
margin-bottom: 0.53em;
margin-left: 0;
margin-right: 0;
font-weight: bold;
}
ul {
margin-left: 0.75vw;
padding-left: 0;
}
li {
margin-left: 0.75vw;
padding-left: 0;
}
/* this must be last, as it overrides previous settings, for mobile */
@media (hover: none) {
a {
display: inline-block;
padding-top: 3px;
padding-bottom: 2px;
}
body {
padding-left:2vw;
padding-right:2vw;
font-size:14px;
line-height:22px;
letter-spacing: 1px;
}
}
/*The following is for code snippets that are highlighted by 2html vim*/
pre { overflow-x: scroll; margin:0; padding:0; font-family:monospace; }
.Identifier { color: #008b8b; }
.Statement { color: #af5f00; }
.PreProc { color: #5fd7ff; }
.Type { color: #005f00; }
.Comment { color: blue ; }
.Constant { color: #ff00ff; }
/*end of highlighted snippets*/
a {
text-decoration:none;
padding-bottom: 0px;
color:inherit;
border-bottom: 2px solid #6cb8f0;
}
a:hover {
text-decoration: none;
color:black;
border-bottom: 1px solid red;
}
/*do not underline links nor should they be active*/
pre a {
text-decoration:none;
color:black;
border-bottom: none;
pointer-events: none;
cursor: default;
}
.golfSnippet {display:none;}
ul {
list-style-type:square;
list-style-position: outside;
}
</style>
</head>
<body>
<script>
function gg_copy(gt, eid, gc) {
gt.textContent = eid.textContent;
gt.select();
document.execCommand("copy");
gc.style.visibility="visible"
setTimeout(()=>{ gc.style.visibility="hidden"; }, 1000);
}
</script>
<!--GOLFMENU13-->
<!--GOLFENDMENU13-->
<!--BEGVDOC90-->
<div class='vhub' style='margin-top:10px;margin-right:20px;text-align:right;background-color:white;'><a href='https://golf-lang.com' style='border-bottom:0px'><img src='https://golf-lang.com/golf.png'/></a></div><div class='vhub' style='margin-top:10px;'> Client API</div><hr/>You can use C API client library to connect to Golf:<br/>
<ul><li>The API has only a few functions, and the main one is "gg_cli_request()", which makes a call to the service.<br/>
</li><li>There is only a single data type used, which is "gg_cli" and it is used to specify a request and its options, as well as to retrieve results.<br/>
</li><li>There is a single include file ("gcli.h"). <br/>
</li><li>When building your client executable, you can either specify build flags by using the result of "gg -i" (if you have Golf installed), or use self-contained source files directly.<br/>
</li><li>It is MT-safe, so you can use it in multi-threaded applications, such as to make many requests in parallel.</li></ul>
See Examples section below for detailed examples.<br/>
<div class="vsub"><a id="Sending a request to Golf service"></a>Sending a request to Golf service</div>
The following function is used to make a call using C API:<br/>
<div class='code' style='position:relative;padding-right:16px;'>
<pre id='code_285'>
<span class="Type">int</span> gg_cli_request (gg_cli *req);</pre>
<span id=golf_copied_285 style='position:absolute;right:-14px;top:-30px; cursor: pointer;visibility:hidden;background:white;'>Copied!</span>
<textarea id='golft_285' style='position: absolute;left: -500%;'></textarea>
<img src='https://golf-lang.com/golf-copy-small-1.png' id='golfb' onclick='gg_copy(golft_285, code_285, golf_copied_285)' style='position:absolute;right:0;top:0; cursor: pointer;opacity:0.5;'/>
</div><br/>
All input and output is contained in a single variable of type "gg_cli", the pointer to which is passed to "gg_cli_request()" function that sends a request to the service. A variable of type "gg_cli" must be initialized to zero before using it (such as with {0} initialization, "memset()" or "calloc()"), or otherwise some of its members may have random values:<br/>
<div class='code' style='position:relative;padding-right:16px;'>
<pre id='code_288'>
<span class="Comment">// Define and initialize request variable</span>
gg_cli req = {<span class="Constant">0</span>};
<span class="Comment">// You could also do:</span>
<span class="Comment">// memset ((char*)&req, </span><span class="Constant">0</span><span class="Comment">, sizeof(gg_cli));</span>
<span class="Statement"> .</span>..
<span class="Comment">// Set members of 'req' variable (see below)</span>
<span class="Statement"> .</span>..
<span class="Comment">// Make a call</span>
<span class="Type">int</span> result = gg_cli_request (&req);</pre>
<span id=golf_copied_288 style='position:absolute;right:-14px;top:-30px; cursor: pointer;visibility:hidden;background:white;'>Copied!</span>
<textarea id='golft_288' style='position: absolute;left: -500%;'></textarea>
<img src='https://golf-lang.com/golf-copy-small-1.png' id='golfb' onclick='gg_copy(golft_288, code_288, golf_copied_288)' style='position:absolute;right:0;top:0; cursor: pointer;opacity:0.5;'/>
</div><br/>
Type "gg_cli" is defined as (i.e. public members of it):<br/>
<div class='code' style='position:relative;padding-right:16px;'>
<pre id='code_290'>
<span class="Type">typedef</span> <span class="Type">struct</span> {
<span class="Type">const</span> <span class="Type">char</span> *server; <span class="Comment">// the IP:port/socket_path to server</span>
<span class="Type">const</span> <span class="Type">char</span> *req_method; <span class="Comment">// request method</span>
<span class="Type">const</span> <span class="Type">char</span> *app_path; <span class="Comment">// application path</span>
<span class="Type">const</span> <span class="Type">char</span> *req; <span class="Comment">// request name</span>
<span class="Type">const</span> <span class="Type">char</span> *url_params; <span class="Comment">// URL params (path+query string)</span>
<span class="Type">const</span> <span class="Type">char</span> *content_type; <span class="Comment">// content type</span>
<span class="Type">int</span> content_len; <span class="Comment">// content len</span>
<span class="Type">const</span> <span class="Type">char</span> *req_body; <span class="Comment">// request body (i.e. content)</span>
<span class="Type">char</span> **env; <span class="Comment">// environment to pass to servicde</span>
<span class="Type">int</span> timeout; <span class="Comment">// timeout for request</span>
<span class="Type">int</span> req_status; <span class="Comment">// status of request from service</span>
<span class="Type">int</span> data_len; <span class="Comment">// length of response from service</span>
<span class="Type">int</span> error_len; <span class="Comment">// length of error from service</span>
<span class="Type">char</span> *errm; <span class="Comment">// error message when gg_cli_request returns other than GG_OKAY</span>
gg_cli_out_hook out_hook; <span class="Comment">// hook to get data output as soon as it arrives</span>
gg_cli_err_hook err_hook; <span class="Comment">// hook get error output as soon as it arrives</span>
gg_cli_done_hook done_hook; <span class="Comment">// get all data when request is complete</span>
<span class="Type">int</span> thread_id; <span class="Comment">// custom ID when executing in a multithreaded fashion</span>
<span class="Type">volatile</span> <span class="Type">char</span> done; <span class="Comment">// indicator that the request has completed</span>
<span class="Type">int</span> return_code; <span class="Comment">// the return code from gg_cli_request()</span>
<span class="Statement"> }</span> gg_cli;</pre>
<span id=golf_copied_290 style='position:absolute;right:-14px;top:-30px; cursor: pointer;visibility:hidden;background:white;'>Copied!</span>
<textarea id='golft_290' style='position: absolute;left: -500%;'></textarea>
<img src='https://golf-lang.com/golf-copy-small-1.png' id='golfb' onclick='gg_copy(golft_290, code_290, golf_copied_290)' style='position:absolute;right:0;top:0; cursor: pointer;opacity:0.5;'/>
</div><br/>
<br/>
<span style="font-weight:bold;">- Mandatory input</span><br/>
The following members of "gg_cli" type must be supplied in order to make a call to a service:<br/>
<ul><li>"server" represents either a Unix socket or a TCP socket, and is:<br/>
<ul><li>for a Unix socket, a fully qualified name to a Unix socket file used to communicate with the service (for a Golf service, it's "/var/lib/gg/<app name>/sock/sock", where <app name> is the application name), or<br/>
</li><li>for a TCP socket, a host name and port name in the form of "<host name>:<port number>", specifying where is the server listening on (for instance "127.0.0.1:2301" if the Golf service is local and runs on TCP port 2301).</li></ul>
</li><li>"req_method" is a request method, such as "GET", "POST", "PUT", "DELETE" or any other.<br/>
</li><li>"app_path" is an application path (see <a href='https://golf-lang.com/request.html'>request</a>). By default it's "/<application name>". <br/>
</li><li>"req" is a request path, i.e. a request name preceded by a forward slash, as in "/<request name>" (see <a href='https://golf-lang.com/request.html'>request</a>).</li></ul>
<span style="font-weight:bold;">- URL parameters</span><br/>
"url_params" is the URL parameters, meaning input parameters (as path segments and query string, see <a href='https://golf-lang.com/request.html'>request</a>). URL parameters can be NULL or empty, in which case it is not used.<br/>
<br/>
<span style="font-weight:bold;">- Request body (content)</span><br/>
"req_body" is the request body, which can be any text or binary data. "content_type" is the content type of request body (for instance "application/json" or "image/jpg"). "content_len" is the length of request body in bytes. A request body is sent only if "content_type" and "req_body" are not NULL and not empty, and if "content_len" is greater than zero.<br/>
<br/>
<span style="font-weight:bold;">- Passing environment to service</span><br/>
"env" is any environment variables that should be passed along to the service. You can access those in Golf via "environment" clause of <a href='https://golf-lang.com/get-sys.html'>get-sys</a> statement. This is an array of strings, where name/value pairs are specified one after the other, and which always must end with NULL. For example, if you want to use variable "REMOTE_USER" with value "John" and variable "MY_VARIABLE" with value "8000", then it might look like this:<br/>
<div class='code' style='position:relative;padding-right:16px;'>
<pre id='code_292'>
<span class="Type">char</span> *env[<span class="Constant">5</span>];
env[<span class="Constant">0</span>] = <span class="Constant">"REMOTE_USER"</span>;
env[<span class="Constant">1</span>] = <span class="Constant">"John"</span>
env[<span class="Constant">2</span>] = <span class="Constant">"MY_VARIABLE"</span>;
env[<span class="Constant">3</span>] = <span class="Constant">"8000"</span>
env[<span class="Constant">4</span>] = <span class="Constant">NULL</span>;</pre>
<span id=golf_copied_292 style='position:absolute;right:-14px;top:-30px; cursor: pointer;visibility:hidden;background:white;'>Copied!</span>
<textarea id='golft_292' style='position: absolute;left: -500%;'></textarea>
<img src='https://golf-lang.com/golf-copy-small-1.png' id='golfb' onclick='gg_copy(golft_292, code_292, golf_copied_292)' style='position:absolute;right:0;top:0; cursor: pointer;opacity:0.5;'/>
</div><br/>
Thus, if you are passing N environment variables to the service, you must size "env" as "char*" array with 2*N+1 elements. <br/>
<br/>
Note that in order to suppress output of HTTP headers from the service, you can include environment variable "GG_SILENT_HEADER" with value "yes"; to let the service control headers output (either by default, with "-z" option of <a href='https://golf-lang.com/mgrg.html'>mgrg</a> or with <a href='https://golf-lang.com/silent-header.html'>silent-header</a>) simply omit this environment variable.<br/>
<br/>
<span style="font-weight:bold;">- Timeout</span><br/>
"timeout" is the number of seconds a call to the service should not exceed. For instance if the remote service is taking too long or if the network connection is too slow, you can limit how long to wait for a reply. If there is no timeout, then "timeout" value should be zero. Note that DNS resolution of the host name (in case you are using a TCP socket) is not counted in timeout. Maximum value for timeout is 86400.<br/>
<br/>
Even if timeout is set to 0, a service call may eventually timeout due to underlying socket and network settings. Note that even if your service call times out, the actual service executing may continue until it's done.<br/>
<span style="font-weight:bold;">- Thread ID</span><br/>
"thread_id" is an integer that you can set and use when your program is multithreaded. By default it's 0. This number is set by you and passed to hooks (your functions called when request is complete or data available). You can use this number to differentiate the data with regards to which thread it belongs to.<br/>
<br/>
<span style="font-weight:bold;">- Completion indicator and return code</span><br/>
When your program is multithreaded, it may be useful to know when (and if) a request has completed. "done" is set to to "true" when a request completes, and "return_code" is the return value from gg_cli_request() (see below for a list). In a single-threaded program, this information is self-evident, but if you are running more than one request at the same time (in different threads), you can use these to check on each request executing in parallel (for instance in a loop in the main thread).<br/>
<br/>
Note that "done" is "true" specifically when all the results of a request are available and the request is about to be completed. In a multithreaded program, it means the thread is very soon to terminate or has already terminated; it does not mean that thread has positively terminated. Use standard "pthread_join()" function to make sure the thread has terminated if that is important to you. <br/>
<div class="vsub"><a id="Return value of gg_cli_request()"></a>Return value of gg_cli_request()</div>
The following are possible return values from "gg_cli_request()" (available in "return_code" member of "gg_cli" type):<br/>
<ul><li>GG_OKAY if request succeeded,<br/>
</li><li>GG_CLI_ERR_RESOLVE_ADDR if host name for TCP connection cannot be resolved,<br/>
</li><li>GG_CLI_ERR_PATH_TOO_LONG if path name of Unix socket is too long,<br/>
</li><li>GG_CLI_ERR_SOCKET if cannot create a socket (for instance they are exhausted for the process or system),<br/>
</li><li>GG_CLI_ERR_CONNECT if cannot connect to server (TCP or Unix alike),<br/>
</li><li>GG_CLI_ERR_SOCK_WRITE if cannot write data to server (for instance if server has encountered an error or is down, or if network connection is no longer available),<br/>
</li><li>GG_CLI_ERR_SOCK_READ if cannot read data from server (for instance if server has encountered an error or is down, or if network connection is no longer available),<br/>
</li><li>GG_CLI_ERR_PROT_ERR if there is a protocol error, which indicates a protocol issue on either or both sides,<br/>
</li><li>GG_CLI_ERR_BAD_VER if either side does not support protocol used by the other,<br/>
</li><li>GG_CLI_ERR_SRV if server cannot complete the request,<br/>
</li><li>GG_CLI_ERR_UNK if server does not recognize record types used by the client,<br/>
</li><li>GG_CLI_ERR_OUT_MEM if client is out of memory,<br/>
</li><li>GG_CLI_ERR_ENV_TOO_LONG if the combined length of all environment variables is too long,<br/>
</li><li>GG_CLI_ERR_ENV_ODD if the number of supplied environment name/value pairs is incorrect,<br/>
</li><li>GG_CLI_ERR_BAD_TIMEOUT if the value for timeout is incorrect,<br/>
</li><li>GG_CLI_ERR_TIMEOUT if the request timed out based on "timeout" parameter or otherwise if the underlying Operating System libraries declared their own timeout.</li></ul>
You can obtain the error message (corresponding to the above return values) in "errm" member of "gg_cli" type.<br/>
<div class="vsub"><a id="Server reply"></a>Server reply</div>
The service reply is split in two. One part is the actual result of processing (called "stdout" or standard output), and that is "data". The other is the error messages (called "stderr" or standard error), and that's "error". All of service output goes to "data", except from <a href='https://golf-lang.com/report-error.html'>report-error</a> and <a href='https://golf-lang.com/pf-out.html'>pf-out</a>/<a href='https://golf-lang.com/pf-url.html'>pf-url</a>/<a href='https://golf-lang.com/pf-web.html'>pf-web</a> (with "to-error" clause) which goes to "error". Note that "data" and "error" streams can be co-mingled when output by the service, but they will be obtained separately. This allows for clean separation of output from any error messages.<br/>
<br/>
You can obtain service reply when it's ready in its entirety (likely most often used), or as it comes alone bit by bit (see more about asynchronous hooks futher here).<br/>
<div class="vsub"><a id="Status of request execution"></a>Status of request execution</div>
"req_status" member of "gg_cli" type is the request status when a request had executed; it is somewhat similar to an exit status of a program. A Golf service request returns status by means of <a href='https://golf-lang.com/handler-status.html'>handler-status</a> statement. Note that "req_status" is valid only if "gg_cli_request()" returned GG_OKAY (or if "return_code" is GG_OKAY for multi-threaded programs).<br/>
<div class="vsub"><a id="Getting data reply (stdout)"></a>Getting data reply (stdout)</div>
Data returned from a request is valid only if "gg_cli_request()" returned GG_OKAY (or if "return_code" is GG_OKAY for multi-threaded programs). In that case, use "gg_cli_data()" function, for example:<br/>
<div class='code' style='position:relative;padding-right:16px;'>
<pre id='code_294'>
<span class="Comment">// Declare and initialize request variable</span>
gg_cli req = {<span class="Constant">0</span>};
<span class="Comment">// Setup the req variable</span>
<span class="Statement"> .</span>..
<span class="Comment">// Execute request</span>
<span class="Statement">if</span> (gg_cli_request (&req) == GG_OKAY) {
<span class="Type">char</span> *data = gg_cli_data (req); <span class="Comment">// data response</span>
<span class="Type">int</span> data_len = req->data_len; <span class="Comment">// length of data response in bytes</span>
<span class="Statement"> }</span></pre>
<span id=golf_copied_294 style='position:absolute;right:-14px;top:-30px; cursor: pointer;visibility:hidden;background:white;'>Copied!</span>
<textarea id='golft_294' style='position: absolute;left: -500%;'></textarea>
<img src='https://golf-lang.com/golf-copy-small-1.png' id='golfb' onclick='gg_copy(golft_294, code_294, golf_copied_294)' style='position:absolute;right:0;top:0; cursor: pointer;opacity:0.5;'/>
</div><br/>
"data_len" member of "gg_cli" type will have the length of data response in bytes. The reply is always null-terminated as a courtesy, and "data_len" does not include the terminating null byte.<br/>
<br/>
"gg_cli_data()" returns the actual response (i.e. data output) from service as passed to "data" stream. Any output from service will go there, except when "to-error" clause is used in <a href='https://golf-lang.com/pf-out.html'>pf-out</a>, <a href='https://golf-lang.com/pf-url.html'>pf-url</a> and <a href='https://golf-lang.com/pf-web.html'>pf-web</a> - use these constructs to output errors without stopping the service execution. Additionaly, the output of <a href='https://golf-lang.com/report-error.html'>report-error</a> will also not go to data output.<br/>
<div class="vsub"><a id="Getting error reply (stderr)"></a>Getting error reply (stderr)</div>
An error reply returned from a service is valid only if "gg_cli_request()" returned GG_OKAY (or if "return_code" is GG_OKAY for multi-threaded programs). In that case, use "gg_cli_error()" function, for example:<br/>
<div class='code' style='position:relative;padding-right:16px;'>
<pre id='code_296'>
<span class="Comment">// Declare and initialize request variable</span>
gg_cli req = {<span class="Constant">0</span>};
<span class="Comment">// Setup the req variable</span>
<span class="Statement"> .</span>..
<span class="Comment">// Execute request</span>
<span class="Statement">if</span> (gg_cli_request (&req) == GG_OKAY) {
<span class="Type">char</span> *err = gg_cli_error (req); <span class="Comment">// error response</span>
<span class="Type">int</span> err_len = req->error_len; <span class="Comment">// length of error response in bytes</span>
<span class="Statement"> }</span></pre>
<span id=golf_copied_296 style='position:absolute;right:-14px;top:-30px; cursor: pointer;visibility:hidden;background:white;'>Copied!</span>
<textarea id='golft_296' style='position: absolute;left: -500%;'></textarea>
<img src='https://golf-lang.com/golf-copy-small-1.png' id='golfb' onclick='gg_copy(golft_296, code_296, golf_copied_296)' style='position:absolute;right:0;top:0; cursor: pointer;opacity:0.5;'/>
</div><br/>
"gg_cli_error()" returns any error messages from a service response, i.e. data passed to "error" stream. It is comprised of any service output when "to-error" clause is used in <a href='https://golf-lang.com/pf-out.html'>pf-out</a>, <a href='https://golf-lang.com/pf-url.html'>pf-url</a> and <a href='https://golf-lang.com/pf-web.html'>pf-web</a>, as well as any output from <a href='https://golf-lang.com/report-error.html'>report-error</a>. <br/>
<br/>
"error_len" member (of "gg_cli" type above) will have the length of error response in bytes. The response is always null-terminated as a courtesy, and "error_len" does not include the terminating null byte.<br/>
<div class="vsub"><a id="Freeing the result of a request"></a>Freeing the result of a request</div>
Once you have obtained the result of a request, and when no longer needed, you should free it by using "gg_cli_delete()":<br/>
<div class='code' style='position:relative;padding-right:16px;'>
<pre id='code_298'>
<span class="Comment">// Declare and initialize request variable</span>
gg_cli req = {<span class="Constant">0</span>};
<span class="Comment">// Setup the req variable</span>
<span class="Statement"> .</span>..
<span class="Comment">// Execute request</span>
gg_cli_request (&req);
<span class="Comment">// .. Use the result ..</span>
<span class="Comment">// Free request output (data and error streams)</span>
gg_cli_delete (&req);</pre>
<span id=golf_copied_298 style='position:absolute;right:-14px;top:-30px; cursor: pointer;visibility:hidden;background:white;'>Copied!</span>
<textarea id='golft_298' style='position: absolute;left: -500%;'></textarea>
<img src='https://golf-lang.com/golf-copy-small-1.png' id='golfb' onclick='gg_copy(golft_298, code_298, golf_copied_298)' style='position:absolute;right:0;top:0; cursor: pointer;opacity:0.5;'/>
</div><br/>
If you do not free the result, your program may experience a memory leak. If your program exits right after issuing any request(s), you may skip freeing results as that is automatically done on exit by the Operating System. <br/>
<br/>
You can use "gg_cli_delete()" regardless of whether "gg_cli_request()" returned GG_OKAY or not.<br/>
<div class="vsub"><a id="Completion hook"></a>Completion hook</div>
A function you wrote can be called when a request has completed. This is useful in multithreaded invocations, where you may want to receive complete request's results as they are available. To specify a completion hook, you must write a C function with the following signature and assign it to "done_hook" member of "gg_cli" typed variable:<br/>
<div class='code' style='position:relative;padding-right:16px;'>
<pre id='code_299'>
<span class="Type">typedef</span> <span class="Type">void</span> (*gg_cli_done_hook)(<span class="Type">char</span> *recv, <span class="Type">int</span> recv_len, <span class="Type">char</span> *err, <span class="Type">int</span> err_len, gg_cli *req);</pre>
<span id=golf_copied_299 style='position:absolute;right:-14px;top:-30px; cursor: pointer;visibility:hidden;background:white;'>Copied!</span>
<textarea id='golft_299' style='position: absolute;left: -500%;'></textarea>
<img src='https://golf-lang.com/golf-copy-small-1.png' id='golfb' onclick='gg_copy(golft_299, code_299, golf_copied_299)' style='position:absolute;right:0;top:0; cursor: pointer;opacity:0.5;'/>
</div><br/>
"recv" is the request's data output, "recv_len" is its length in bytes, "err" is the request's error output, and "err_len" is its length in bytes. "req" is the request itself which you can use to obtain any other information about the request. In a single threaded environment, these are available as members of the request variable of "gg_cli" type used in the request, and there is not much use for a completion hook. <br/>
<br/>
See an example with asynchronous hooks.<br/>
<div class="vsub"><a id="Asynchronous hooks"></a>Asynchronous hooks</div>
You can obtain the service's reply as it arrives by specifying read hooks. This is useful if the service supplies partial replies over a period of time, and your application can get those partial replies as they become available.<br/>
<br/>
To specify a hook for data output (i.e. from stdout), you must write a C function with the following signature and assign it to "out_hook":<br/>
<div class='code' style='position:relative;padding-right:16px;'>
<pre id='code_300'>
<span class="Type">typedef</span> <span class="Type">void</span> (*gg_cli_out_hook)(<span class="Type">char</span> *recv, <span class="Type">int</span> recv_len, gg_cli *req);</pre>
<span id=golf_copied_300 style='position:absolute;right:-14px;top:-30px; cursor: pointer;visibility:hidden;background:white;'>Copied!</span>
<textarea id='golft_300' style='position: absolute;left: -500%;'></textarea>
<img src='https://golf-lang.com/golf-copy-small-1.png' id='golfb' onclick='gg_copy(golft_300, code_300, golf_copied_300)' style='position:absolute;right:0;top:0; cursor: pointer;opacity:0.5;'/>
</div><br/>
"recv" is the data received and "recv_len" is its length.<br/>
<br/>
To specify a hook for error output (i.e. from stderr), you must write a C function with the following signature and assign it to "err_hook":<br/>
<div class='code' style='position:relative;padding-right:16px;'>
<pre id='code_275'>
<span class="Type">typedef</span> <span class="Type">void</span> (*gg_cli_err_hook)(<span class="Type">char</span> *err, <span class="Type">int</span> err_len, gg_cli *req);</pre>
<span id=golf_copied_275 style='position:absolute;right:-14px;top:-30px; cursor: pointer;visibility:hidden;background:white;'>Copied!</span>
<textarea id='golft_275' style='position: absolute;left: -500%;'></textarea>
<img src='https://golf-lang.com/golf-copy-small-1.png' id='golfb' onclick='gg_copy(golft_275, code_275, golf_copied_275)' style='position:absolute;right:0;top:0; cursor: pointer;opacity:0.5;'/>
</div><br/>
"err" is the error received and "err_len" is its length.<br/>
<br/>
"req" (in both hooks) is the request itself which you can use to obtain any other information about the request.<br/>
<br/>
To register these functions with "gg_cli_request()" function, assign their pointers to "out_hook" and "err_hook" members of request variable of type "gg_cli" respectively. Note that the output hook (i.e. hook function of type "gg_cli_out_hook") will receive empty string ("") in "recv" and "recv_len" will be 0 when the request has completed, meaning all service output (including error) has been received. <br/>
<br/>
For example, functions "get_output()" and "get_err()" will capture data as it arrives and print it out, and get_complete() will print the final result:<br/>
<div class='code' style='position:relative;padding-right:16px;'>
<pre id='code_276'>
<span class="Comment">// Output hook</span>
<span class="Type">void</span> get_output(<span class="Type">char</span> *d, <span class="Type">int</span> l, gg_cli *req)
<span class="Statement"> {</span>
printf(<span class="Constant">"Got output of [</span><span class="Special">%.*s</span><span class="Constant">] of length [</span><span class="Special">%d</span><span class="Constant">] in thread [</span><span class="Special">%d</span><span class="Constant">]"</span>, l, d, l, req->thread_id);
<span class="Statement"> }</span>
<span class="Comment">// Error hook</span>
<span class="Type">void</span> get_err(<span class="Type">char</span> *d, <span class="Type">int</span> l, gg_cli *req)
<span class="Statement"> {</span>
printf(<span class="Constant">"Got error of [</span><span class="Special">%.*s</span><span class="Constant">] of length [</span><span class="Special">%d</span><span class="Constant">], status [</span><span class="Special">%d</span><span class="Constant">]"</span>, l, d, l, req->req_status);
<span class="Statement"> }</span>
<span class="Comment">// Completion hook</span>
<span class="Type">void</span> get_complete(<span class="Type">char</span> *data, <span class="Type">int</span> data_len, <span class="Type">char</span> *err, <span class="Type">int</span> err_len, gg_cli *req)
<span class="Statement"> {</span>
printf(<span class="Constant">"Got data [</span><span class="Special">%.*s</span><span class="Constant">] of length [</span><span class="Special">%d</span><span class="Constant">] and error of [</span><span class="Special">%.*s</span><span class="Constant">] of length [</span><span class="Special">%d</span><span class="Constant">], status [</span><span class="Special">%d</span><span class="Constant">], thread [</span><span class="Special">%d</span><span class="Constant">]</span><span class="Special">\n</span><span class="Constant">"</span>, data_len, data, data_len, err_len, err, err_len, req->req_status, req->thread_id);
<span class="Statement"> }</span>
<span class="Statement"> .</span>..
gg_cli req = {<span class="Constant">0</span>};
<span class="Statement"> .</span>..
<span class="Comment">// Register output and error hooks, as well as a completion hook</span>
req.out_hook = &get_output;
req.err_hook = &get_err;
req.done_hook = &get_complete;</pre>
<span id=golf_copied_276 style='position:absolute;right:-14px;top:-30px; cursor: pointer;visibility:hidden;background:white;'>Copied!</span>
<textarea id='golft_276' style='position: absolute;left: -500%;'></textarea>
<img src='https://golf-lang.com/golf-copy-small-1.png' id='golfb' onclick='gg_copy(golft_276, code_276, golf_copied_276)' style='position:absolute;right:0;top:0; cursor: pointer;opacity:0.5;'/>
</div><br/>
<div class="vsub"><a id="Multithreading"></a>Multithreading</div>
The Golf client is MT-safe, meaning you can use it both in single-threaded and multi-threaded programs. Note that each thread must have its own copy of "gg_cli" request variable, since it provides both input and output parameters to a request call and as such cannot be shared between the threads.<br/>
<div class="vsub"><a id="Usage"></a>Usage</div>
Do not use this API directly with Golf - use <a href='https://golf-lang.com/call-remote.html'>call-remote</a> instead which is made specifically for use in .golf files. Otherwise, you can use this API with any program.<br/>
<div class="vsub"><a id="Using API without Golf"></a>Using API without Golf</div>
You can use API without installing Golf. To do that:<br/>
<ul><li>get the Golf source code,<br/>
</li><li>copy source files "gcli.c" and "gcli.h" to where you need to build your program,<br/>
</li><li>add the content of Golf's "LICENSE" file to your own in order to include the license for these source files,<br/>
</li><li>then make your application:<br/>
<div class='code' style='position:relative;padding-right:16px;'>
<pre id='code_277'>
gcc -o cli cli.c gcli.c</pre>
<span id=golf_copied_277 style='position:absolute;right:-14px;top:-30px; cursor: pointer;visibility:hidden;background:white;'>Copied!</span>
<textarea id='golft_277' style='position: absolute;left: -500%;'></textarea>
<img src='https://golf-lang.com/golf-copy-small-1.png' id='golfb' onclick='gg_copy(golft_277, code_277, golf_copied_277)' style='position:absolute;right:0;top:0; cursor: pointer;opacity:0.5;'/>
</div><br/>
</li></ul>
Note that you do not need to install any other dependencies, as API is entirely contained in the aforementioned source files.<br/>
<div class="vsub"><a id="Examples"></a>Examples</div>
<div class="vsub"><a id="Simple example"></a>Simple example</div>
The following example is a simple demonstration, with minimum of options used. Copy the C code to file "cli.c" in a directory of its own:<br/>
<div class='code' style='position:relative;padding-right:16px;'>
<pre id='code_278'>
<span class="PreProc">#include </span><span class="Constant">"gcli.h"</span>
<span class="Type">void</span> main ()
<span class="Statement"> {</span>
<span class="Comment">// Request type gg_cli - create a request variable and zero it out</span>
gg_cli req = {<span class="Constant">0</span>};
req.server = <span class="Constant">"/var/lib/gg/helloworld/sock/sock"</span>; <span class="Comment">// Unix socket</span>
req.req_method = <span class="Constant">"GET"</span>; <span class="Comment">// GET HTTP method</span>
req.app_path = <span class="Constant">"/helloworld"</span>; <span class="Comment">// application path</span>
req.req = <span class="Constant">"/hello-simple"</span>; <span class="Comment">// request name</span>
<span class="Comment">// Make a request</span>
<span class="Type">int</span> res = gg_cli_request (&req);
<span class="Comment">// Check return status, and if there's an error, display error code and the</span>
<span class="Comment">// corresponding error message. Otherwise, print out service response.</span>
<span class="Statement">if</span> (res != GG_OKAY) printf(<span class="Constant">"Request failed [</span><span class="Special">%d</span><span class="Constant">] [</span><span class="Special">%s</span><span class="Constant">]</span><span class="Special">\n</span><span class="Constant">"</span>, res, req.errm);
<span class="Statement">else</span> printf(<span class="Constant">"</span><span class="Special">%s</span><span class="Constant">"</span>, gg_cli_data(&req));
<span class="Comment">// Free up resources so there are no memory leaks</span>
gg_cli_delete(&req);
<span class="Statement"> }</span></pre>
<span id=golf_copied_278 style='position:absolute;right:-14px;top:-30px; cursor: pointer;visibility:hidden;background:white;'>Copied!</span>
<textarea id='golft_278' style='position: absolute;left: -500%;'></textarea>
<img src='https://golf-lang.com/golf-copy-small-1.png' id='golfb' onclick='gg_copy(golft_278, code_278, golf_copied_278)' style='position:absolute;right:0;top:0; cursor: pointer;opacity:0.5;'/>
</div><br/>
To make this client application:<br/>
<div class="shcode" style='position:relative;padding-right:16px;'>
<pre id='code_287'>
gcc <span class="Special">-o</span> cli cli.c <span class="PreProc">$(</span><span class="Special">gg </span><span class="Special">-i</span><span class="PreProc">)</span></pre>
<span id=golf_copied_287 style='position:absolute;right:-14px;top:-30px; cursor: pointer;visibility:hidden;background:white;'>Copied!</span>
<textarea id='golft_287' style='position: absolute;left: -500%;'></textarea>
<img src='https://golf-lang.com/golf-copy-small-1.png' id='golfb' onclick='gg_copy(golft_287, code_287, golf_copied_287)' style='position:absolute;right:0;top:0; cursor: pointer;opacity:0.5;'/>
</div><br/>
In this case, you're using a Unix socket to communicate with the Golf service. To test with a Golf service handler, copy the following code to "hello_simple.golf" file in a separate directory:<br/>
<div class='code' style='position:relative;padding-right:16px;'>
<pre id='code_279'>
<span class="Statement"> begin-handler</span> /hello_simple<span class="Identifier"> public</span>
<span class="Statement"> silent-header</span>
<span class="Statement"> @</span>Hi there!
<span class="Statement"> end-handler</span></pre>
<span id=golf_copied_279 style='position:absolute;right:-14px;top:-30px; cursor: pointer;visibility:hidden;background:white;'>Copied!</span>
<textarea id='golft_279' style='position: absolute;left: -500%;'></textarea>
<img src='https://golf-lang.com/golf-copy-small-1.png' id='golfb' onclick='gg_copy(golft_279, code_279, golf_copied_279)' style='position:absolute;right:0;top:0; cursor: pointer;opacity:0.5;'/>
</div><br/>
Create and make the Golf application and run it via local Unix socket:<br/>
<div class="shcode" style='position:relative;padding-right:16px;'>
<pre id='code_289'>
sudo mgrg <span class="Special">-i</span> <span class="Special">-u</span> <span class="PreProc">$(</span><span class="Special">whoami</span><span class="PreProc">)</span> helloworld
gg <span class="Special">-q</span>
mgrg <span class="Special">-m</span> quit helloworld
mgrg <span class="Special">-w</span> <span class="Constant">1</span> helloworld</pre>
<span id=golf_copied_289 style='position:absolute;right:-14px;top:-30px; cursor: pointer;visibility:hidden;background:white;'>Copied!</span>
<textarea id='golft_289' style='position: absolute;left: -500%;'></textarea>
<img src='https://golf-lang.com/golf-copy-small-1.png' id='golfb' onclick='gg_copy(golft_289, code_289, golf_copied_289)' style='position:absolute;right:0;top:0; cursor: pointer;opacity:0.5;'/>
</div><br/>
Run the client:<br/>
<div class="shcode" style='position:relative;padding-right:16px;'>
<pre id='code_291'>
./cli</pre>
<span id=golf_copied_291 style='position:absolute;right:-14px;top:-30px; cursor: pointer;visibility:hidden;background:white;'>Copied!</span>
<textarea id='golft_291' style='position: absolute;left: -500%;'></textarea>
<img src='https://golf-lang.com/golf-copy-small-1.png' id='golfb' onclick='gg_copy(golft_291, code_291, golf_copied_291)' style='position:absolute;right:0;top:0; cursor: pointer;opacity:0.5;'/>
</div><br/>
The output is, as expected:<br/>
<div class='code' style='position:relative;padding-right:16px;'>
<pre id='code_280'>
Hi there!</pre>
<span id=golf_copied_280 style='position:absolute;right:-14px;top:-30px; cursor: pointer;visibility:hidden;background:white;'>Copied!</span>
<textarea id='golft_280' style='position: absolute;left: -500%;'></textarea>
<img src='https://golf-lang.com/golf-copy-small-1.png' id='golfb' onclick='gg_copy(golft_280, code_280, golf_copied_280)' style='position:absolute;right:0;top:0; cursor: pointer;opacity:0.5;'/>
</div><br/>
<div class="vsub"><a id="Example with more options"></a>Example with more options</div>
This example demonstrates using multiple options, including using TCP sockets connecting to a host and port number, environment variables, query string, request body and request execution timeout. It will also show the separation of "data" and "error" (i.e. stdout and stderr) streams from the service.<br/>
<br/>
Copy this to file "cli1.c" in a directory of its own - note that in this example a server will run on localhost (127.0.0.1) and TCP port 2301:<br/>
<div class='code' style='position:relative;padding-right:16px;'>
<pre id='code_281'>
<span class="PreProc">#include </span><span class="Constant">"gcli.h"</span>
<span class="Type">void</span> main ()
<span class="Statement"> {</span>
<span class="Comment">// Request type gg_cli - create a request variable</span>
gg_cli req;
<span class="Comment">// Initialize request</span>
memset (&req, <span class="Constant">0</span>, <span class="Statement">sizeof</span>(req));
<span class="Comment">// Add </span><span class="Constant">3</span><span class="Comment"> environment variables (in the form of name, value, name, value, ... , NULL)</span>
<span class="Type">char</span> *env[] = { <span class="Constant">"REMOTE_USER"</span>, <span class="Constant">"John"</span>, <span class="Constant">"SOME_VAR"</span>, <span class="Constant">"SOME</span><span class="Special">\n</span><span class="Constant">VALUE"</span>, <span class="Constant">"NEW_VAR"</span>, <span class="Constant">"1000"</span>, <span class="Constant">NULL</span> };
<span class="Comment">// Create a request</span>
<span class="Comment">// Environment variables to pass to service request</span>
req.env = env;
<span class="Comment">// Server IP and port</span>
req.server = <span class="Constant">"127.0.0.1:2301"</span>;
<span class="Comment">// Request method</span>
req.req_method = <span class="Constant">"GET"</span>;
<span class="Comment">// Application path</span>
req.app_path = <span class="Constant">"/helloworld"</span>;
<span class="Comment">// Request</span>
req.req = <span class="Constant">"/hello"</span>;
<span class="Comment">// URL parameters (path and query string)</span>
req.url_params = <span class="Constant">"par1=val1&par2=91"</span>;
<span class="Comment">// Content type</span>
req.content_type = <span class="Constant">"application/json"</span>;
<span class="Comment">// Content (i.e. request body)</span>
req.req_body = <span class="Constant">"This is request body"</span>;
<span class="Comment">// Content length</span>
req.content_len = strlen (req.req_body);
<span class="Comment">// No timeout (set to </span><span class="Constant">0</span><span class="Comment">)</span>
req.timeout = <span class="Constant">0</span>;
<span class="Comment">// Make a request</span>
<span class="Type">int</span> res = gg_cli_request (&req);
<span class="Comment">// Check return status, and if there's an error, display error code and the</span>
<span class="Comment">// corresponding error message</span>
<span class="Statement">if</span> (res != GG_OKAY) printf(<span class="Constant">"Request failed [</span><span class="Special">%d</span><span class="Constant">] [</span><span class="Special">%s</span><span class="Constant">]</span><span class="Special">\n</span><span class="Constant">"</span>, res, req.errm);
<span class="Statement">else</span> {
<span class="Comment">// If successful, display request results</span>
<span class="Comment">// Exit code from the service processing</span>
printf(<span class="Constant">"Server status </span><span class="Special">%d</span><span class="Special">\n</span><span class="Constant">"</span>, req.req_status);
<span class="Comment">// Length of reply from service</span>
printf(<span class="Constant">"Len of data </span><span class="Special">%d</span><span class="Special">\n</span><span class="Constant">"</span>, req.data_len);
<span class="Comment">// Length of any error from service</span>
printf(<span class="Constant">"Len of error </span><span class="Special">%d</span><span class="Special">\n</span><span class="Constant">"</span>, req.error_len);
<span class="Comment">// Reply from service</span>
printf(<span class="Constant">"Data [</span><span class="Special">%s</span><span class="Constant">]</span><span class="Special">\n</span><span class="Constant">"</span>, gg_cli_data(&req));
<span class="Comment">// Any error message from service</span>
printf(<span class="Constant">"Error [</span><span class="Special">%s</span><span class="Constant">]</span><span class="Special">\n</span><span class="Constant">"</span>, gg_cli_error(&req));
<span class="Statement"> }</span>
<span class="Comment">// Free up resources so there are no memory leaks</span>
gg_cli_delete(&req);
<span class="Statement"> }</span></pre>
<span id=golf_copied_281 style='position:absolute;right:-14px;top:-30px; cursor: pointer;visibility:hidden;background:white;'>Copied!</span>
<textarea id='golft_281' style='position: absolute;left: -500%;'></textarea>
<img src='https://golf-lang.com/golf-copy-small-1.png' id='golfb' onclick='gg_copy(golft_281, code_281, golf_copied_281)' style='position:absolute;right:0;top:0; cursor: pointer;opacity:0.5;'/>
</div><br/>
Note that the URL parameters (i.e. "req.url_params") could have been written as a combination of a path segment and query string (see <a href='https://golf-lang.com/request.html'>request</a>):<br/>
<div class='code' style='position:relative;padding-right:16px;'>
<pre id='code_282'>
req.url_params = <span class="Constant">"/par1/val1?par2=91"</span>;</pre>
<span id=golf_copied_282 style='position:absolute;right:-14px;top:-30px; cursor: pointer;visibility:hidden;background:white;'>Copied!</span>
<textarea id='golft_282' style='position: absolute;left: -500%;'></textarea>
<img src='https://golf-lang.com/golf-copy-small-1.png' id='golfb' onclick='gg_copy(golft_282, code_282, golf_copied_282)' style='position:absolute;right:0;top:0; cursor: pointer;opacity:0.5;'/>
</div><br/>
or just as a path segment:<br/>
<div class='code' style='position:relative;padding-right:16px;'>
<pre id='code_283'>
req.url_params = <span class="Constant">"/par1=val1/par2=91"</span>;</pre>
<span id=golf_copied_283 style='position:absolute;right:-14px;top:-30px; cursor: pointer;visibility:hidden;background:white;'>Copied!</span>
<textarea id='golft_283' style='position: absolute;left: -500%;'></textarea>
<img src='https://golf-lang.com/golf-copy-small-1.png' id='golfb' onclick='gg_copy(golft_283, code_283, golf_copied_283)' style='position:absolute;right:0;top:0; cursor: pointer;opacity:0.5;'/>
</div><br/>
To make this client application:<br/>
<div class="shcode" style='position:relative;padding-right:16px;'>
<pre id='code_293'>
gcc <span class="Special">-o</span> cli1 cli1.c <span class="PreProc">$(</span><span class="Special">gg </span><span class="Special">-i</span><span class="PreProc">)</span></pre>
<span id=golf_copied_293 style='position:absolute;right:-14px;top:-30px; cursor: pointer;visibility:hidden;background:white;'>Copied!</span>
<textarea id='golft_293' style='position: absolute;left: -500%;'></textarea>
<img src='https://golf-lang.com/golf-copy-small-1.png' id='golfb' onclick='gg_copy(golft_293, code_293, golf_copied_293)' style='position:absolute;right:0;top:0; cursor: pointer;opacity:0.5;'/>
</div><br/>
To test it, you can create a Golf application. Copy this to "hello.golf" file in a separate directory:<br/>
<div class='code' style='position:relative;padding-right:16px;'>
<pre id='code_284'>
<span class="Statement"> begin-handler</span> /hello<span class="Identifier"> public</span>
<span class="Statement"> silent-header</span>
<span class="Comment">// Get request body</span>
<span class="Statement"> request-body</span> rb
<span class="Comment">// Input params</span>
<span class="Statement"> get-param</span> par1
<span class="Statement"> get-param</span> par2
<span class="Comment">// Get environment variables passed on from the client</span>
<span class="Statement"> get-sys</span><span class="Identifier"> environment</span> <span class="Constant">"REMOTE_USER"</span><span class="Type"> to</span> ruser
<span class="Statement"> get-sys</span><span class="Identifier"> environment</span> <span class="Constant">"SOME_VAR"</span><span class="Type"> to</span> somev
<span class="Statement"> get-sys</span><span class="Identifier"> environment</span> <span class="Constant">"NEW_VAR"</span><span class="Type"> to</span> newv
<span class="Comment">// Output, print the environment variables, the PID of server process and the request body received from the client</span>
<span class="Statement"> get-req</span><span class="Identifier"> process-id</span><span class="Type"> to</span> pid
<span class="Statement"> @</span>Hello World! [<span class="Statement"><<p-out</span> ruser<span class="Statement">>></span>] [<span class="Statement"><<p-out</span> somev<span class="Statement">>></span>] [<span class="Statement"><<p-out</span> newv<span class="Statement">>></span>] [<span class="Statement"><<p-out</span> par1<span class="Statement">>></span>] [<span class="Statement"><<p-out</span> par2<span class="Statement">>></span>] <span class="Statement"><<p-num</span> pid<span class="Statement">>></span> <span class="Statement"><<p-out</span> rb<span class="Statement">>></span>
<span class="Comment">// Output back a number of lines, generally as </span><span class="Constant">"Output line #<num of line>"</span>
<span class="Comment">// After line #</span><span class="Constant">1418</span><span class="Comment">, print out </span><span class="Constant">"Line 1419 has an error"</span><span class="Comment"> to stderr</span>
<span class="Comment">// After line #</span><span class="Constant">4418</span><span class="Comment">, report an error and exit</span>
<span class="Comment">// This demostrates outputting data to both stdout and stderr</span>
<span class="Statement"> start-loop</span><span class="Identifier"> repeat</span> <span class="Constant">8000</span><span class="Type"> use</span> i<span class="Identifier"> start-with</span> <span class="Constant">0</span>
<span class="Statement"> @</span>Output line #<span class="Statement"><<p-num</span> i<span class="Statement">>></span>
<span class="Statement"> if-true</span> i<span class="Identifier"> equal</span> <span class="Constant">1419</span>
<span class="Statement"> pf-out</span> <span class="Constant">"Line </span><span class="Special">%ld</span><span class="Constant"> has an error</span><span class="Special">\n</span><span class="Constant">"</span>, i<span class="Identifier"> to-error</span>
<span class="Statement"> end-if</span>
<span class="Statement"> if-true</span> i<span class="Identifier"> equal</span> <span class="Constant">4419</span>
<span class="Comment">// Exit code of the service execution</span>
<span class="Statement"> handler-status</span> <span class="Constant">82</span>
<span class="Statement"> report-error</span> <span class="Constant">"</span><span class="Special">%s</span><span class="Constant">"</span>, <span class="Constant">"Some error!"</span>
<span class="Statement"> end-if</span>
<span class="Statement"> end-loop</span>
<span class="Statement"> end-handler</span></pre>
<span id=golf_copied_284 style='position:absolute;right:-14px;top:-30px; cursor: pointer;visibility:hidden;background:white;'>Copied!</span>
<textarea id='golft_284' style='position: absolute;left: -500%;'></textarea>
<img src='https://golf-lang.com/golf-copy-small-1.png' id='golfb' onclick='gg_copy(golft_284, code_284, golf_copied_284)' style='position:absolute;right:0;top:0; cursor: pointer;opacity:0.5;'/>
</div><br/>
Create and make the Golf application and run it on local TCP port 2301 to match the client above:<br/>
<div class="shcode" style='position:relative;padding-right:16px;'>
<pre id='code_295'>
sudo mgrg <span class="Special">-i</span> <span class="Special">-u</span> <span class="PreProc">$(</span><span class="Special">whoami</span><span class="PreProc">)</span> helloworld
gg <span class="Special">-q</span>
mgrg <span class="Special">-m</span> quit helloworld
mgrg <span class="Special">-w</span> <span class="Constant">1</span> <span class="Special">-p</span> <span class="Constant">2301</span> helloworld</pre>
<span id=golf_copied_295 style='position:absolute;right:-14px;top:-30px; cursor: pointer;visibility:hidden;background:white;'>Copied!</span>
<textarea id='golft_295' style='position: absolute;left: -500%;'></textarea>
<img src='https://golf-lang.com/golf-copy-small-1.png' id='golfb' onclick='gg_copy(golft_295, code_295, golf_copied_295)' style='position:absolute;right:0;top:0; cursor: pointer;opacity:0.5;'/>
</div><br/>
Run the client:<br/>
<div class="shcode" style='position:relative;padding-right:16px;'>
<pre id='code_297'>
./cli1</pre>
<span id=golf_copied_297 style='position:absolute;right:-14px;top:-30px; cursor: pointer;visibility:hidden;background:white;'>Copied!</span>
<textarea id='golft_297' style='position: absolute;left: -500%;'></textarea>
<img src='https://golf-lang.com/golf-copy-small-1.png' id='golfb' onclick='gg_copy(golft_297, code_297, golf_copied_297)' style='position:absolute;right:0;top:0; cursor: pointer;opacity:0.5;'/>
</div><br/>
The output:<br/>
<div class='ncode' style='position:relative;padding-right:16px;'>
<pre id='code_286'>
Server status 82
Len of data 78530
Len of error 35
Data [Hello World! [John] [SOME
VALUE] [1000] [val1] [91] 263002 This is request body
Output line #0
Output line #1
Output line #2
Output line #3
Output line #4
Output line #5
Output line #6
Output line #7
...
Output line #4413
Output line #4414
Output line #4415
Output line #4416
Output line #4417
Output line #4418
Output line #4419
]
Error [Line 1419 has an error
Some error!
]</pre>
<span id=golf_copied_286 style='position:absolute;right:-14px;top:-30px; cursor: pointer;visibility:hidden;background:white;'>Copied!</span>
<textarea id='golft_286' style='position: absolute;left: -500%;'></textarea>
<img src='https://golf-lang.com/golf-copy-small-1.png' id='golfb' onclick='gg_copy(golft_286, code_286, golf_copied_286)' style='position:absolute;right:0;top:0; cursor: pointer;opacity:0.5;'/>
</div><br/>
The output shows service exit code (82, see <a href='https://golf-lang.com/handler-status.html'>handler-status</a> in the Golf code above), length of data output, and other information which includes environment variables passed to the service from the client, the PID of server process, the request body from the client, and then the error output. Note that the data output (stdout) and the error output (stderr) are separated, since the protocol does use separate streams over the same connection. This makes working with the output easy, while the data transfer is fast at the same time.<br/>
<!--BEFSAL13--><div class="vsub"><a id="See also"></a>See also</div>
<a name='API'></a><span style="font-weight:bold;">API</span><br/>
<a href='https://golf-lang.com/Client-API.html'>Client-API</a> <br/>
<a href='https://golf-lang.com/Server-API.html'>Server-API</a> <br/>
<span style="font-weight:bold;">See all</span> <br/>
<a href='https://golf-lang.com/documentation.html'>documentation</a><br/>
<!--ENDVDOC90-->
<br/><div style='width:100%;clear:both;'>
<hr/>
<!--GOLFFOOT77--><span style='font-size:80%'><a href="https://golf-lang.com/copyright.html">Copyright</a> (c) 2019-2025 Gliim LLC. All contents on this web site is "AS IS" without warranties or guarantees of any kind.</span>
</div><br/></body></html>