-
-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathindex.xml
More file actions
3921 lines (3667 loc) · 450 KB
/
index.xml
File metadata and controls
3921 lines (3667 loc) · 450 KB
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
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Home on http4k</title><link>https://http4k.org/</link><description>Recent content in Home on http4k</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Tue, 10 Mar 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://http4k.org/index.xml" rel="self" type="application/rss+xml"/><item><title>Connect Overview</title><link>https://http4k.org/ecosystem/connect/concepts/pattern/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/ecosystem/connect/concepts/pattern/</guid><description><p>The main bulk of non-operationally focussed application code in a modern Server-based HTTP microservice can be broken
down into a few broad areas:</p></description></item><item><title>Core</title><link>https://http4k.org/ecosystem/http4k/reference/core/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/ecosystem/http4k/reference/core/</guid><description><h3 id="installation-gradle">Installation (Gradle)<a class="heading-link" href="#installation-gradle" aria-label="Link to Installation (Gradle)">#</a>
</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-kotlin" data-lang="kotlin"><span style="display:flex;"><span>dependencies {
</span></span><span style="display:flex;"><span>
implementation(platform("org.http4k:http4k-bom:6.40.1.0"))
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-core&#34;</span>)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h3 id="about">About<a class="heading-link" href="#about" aria-label="Link to About">#</a>
</h3>
<p>Apart from Kotlin StdLib, the core module has ZERO dependencies and provides the following:</p></description></item><item><title>Overview</title><link>https://http4k.org/ecosystem/ai/reference/overview/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/ecosystem/ai/reference/overview/</guid><description><p>A quick reference as to what is what with the http4k AI modules.</p>
<h1 id="universal-llm-adapters">Universal LLM adapters<a class="heading-link" href="#universal-llm-adapters" aria-label="Link to Universal LLM adapters">#</a>
</h1>
<table>
<thead>
<tr>
<th>Provider</th>
<th>Chat</th>
<th>Streaming Chat</th>
<th>Image Generation</th>
<th>In-Memory Fake</th>
</tr>
</thead>
<tbody>
<tr>
<td>AnthropicAI</td>
<td>✅</td>
<td>❌</td>
<td>❌</td>
<td>http4k-connect-ai-anthropic-fake</td>
</tr>
<tr>
<td>Azure</td>
<td>✅</td>
<td>✅</td>
<td>❌</td>
<td>http4k-connect-ai-openai-fake</td>
</tr>
<tr>
<td>Gemini</td>
<td>✅</td>
<td>✅</td>
<td>❌</td>
<td>http4k-connect-ai-openai-fake</td>
</tr>
<tr>
<td>Github Models</td>
<td>✅</td>
<td>✅</td>
<td>❌</td>
<td>http4k-connect-ai-openai-fake</td>
</tr>
<tr>
<td>Open AI</td>
<td>✅</td>
<td>✅</td>
<td>✅</td>
<td>http4k-connect-ai-openai-fake</td>
</tr>
</tbody>
</table>
<h1 id="langchain4j">LangChain4J<a class="heading-link" href="#langchain4j" aria-label="Link to LangChain4J">#</a>
</h1>
<p>Plug-in http4k clients into any Langchain-compatible AI model, embedding, or vector store.</p></description></item><item><title>Overview</title><link>https://http4k.org/ecosystem/connect/reference/overview/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/ecosystem/connect/reference/overview/</guid><description><p>A quick reference as to what is what with the http4k Connect modules.</p>
<h2 id="cloud-services">Cloud Services<a class="heading-link" href="#cloud-services" aria-label="Link to Cloud Services">#</a>
</h2>
<table>
<thead>
<tr>
<th>Vendor</th>
<th>System</th>
<th>In-Memory Fake</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td>AWS</td>
<td>AppRunner</td>
<td>✅</td>
<td></td>
</tr>
<tr>
<td>AWS</td>
<td>CloudFront</td>
<td>✅</td>
<td></td>
</tr>
<tr>
<td>AWS</td>
<td>CloudWatch</td>
<td>✅</td>
<td></td>
</tr>
<tr>
<td>AWS</td>
<td>Cloudwatch Logs</td>
<td>✅</td>
<td></td>
</tr>
<tr>
<td>AWS</td>
<td>DynamoDb</td>
<td>✅</td>
<td></td>
</tr>
<tr>
<td>AWS</td>
<td>EventBridge</td>
<td>✅</td>
<td></td>
</tr>
<tr>
<td>AWS</td>
<td>Evidently</td>
<td>✅</td>
<td></td>
</tr>
<tr>
<td>AWS</td>
<td>Firehose</td>
<td>✅</td>
<td></td>
</tr>
<tr>
<td>AWS</td>
<td>IAM Identity Center</td>
<td>✅</td>
<td></td>
</tr>
<tr>
<td>AWS</td>
<td>Instance Metadata</td>
<td>✅</td>
<td></td>
</tr>
<tr>
<td>AWS</td>
<td>KMS</td>
<td>✅</td>
<td></td>
</tr>
<tr>
<td>AWS</td>
<td>Lambda</td>
<td>✅</td>
<td></td>
</tr>
<tr>
<td>AWS</td>
<td>S3</td>
<td>✅</td>
<td></td>
</tr>
<tr>
<td>AWS</td>
<td>Secrets Manager</td>
<td>✅</td>
<td></td>
</tr>
<tr>
<td>AWS</td>
<td>SES</td>
<td>✅</td>
<td></td>
</tr>
<tr>
<td>AWS</td>
<td>SNS</td>
<td>✅</td>
<td></td>
</tr>
<tr>
<td>AWS</td>
<td>SQS</td>
<td>✅</td>
<td></td>
</tr>
<tr>
<td>AWS</td>
<td>STS</td>
<td>✅</td>
<td></td>
</tr>
<tr>
<td>AWS</td>
<td>Systems Manager</td>
<td>✅</td>
<td></td>
</tr>
<tr>
<td>GitHub</td>
<td>V3 API</td>
<td>❌</td>
<td>Client Shell and WebHook Signing only</td>
</tr>
<tr>
<td>GitLab</td>
<td>API</td>
<td>❌</td>
<td>Client Shell and WebHook Signing only</td>
</tr>
<tr>
<td>Google</td>
<td>Analytics GA4</td>
<td>✅</td>
<td></td>
</tr>
<tr>
<td>Google</td>
<td>Analytics UA</td>
<td>✅</td>
<td></td>
</tr>
<tr>
<td>Kafka</td>
<td>Rest Proxy</td>
<td>✅</td>
<td></td>
</tr>
<tr>
<td>Kafka</td>
<td>Schema Registry</td>
<td>✅</td>
<td></td>
</tr>
<tr>
<td>Mattermost</td>
<td>WebHook</td>
<td>❌</td>
<td></td>
</tr>
<tr>
<td>Slack</td>
<td>Slack</td>
<td>✅</td>
<td>Minimal support for sending messages to channel and via webhook</td>
</tr>
<tr>
<td>X402</td>
<td>X402</td>
<td>✅</td>
<td>X402 payment gateway filters and facilitator client</td>
</tr>
</tbody>
</table>
<br/>
<br/>
<h3 id="ai-services">AI Services<a class="heading-link" href="#ai-services" aria-label="Link to AI Services">#</a>
</h3>
<table>
<thead>
<tr>
<th>Vendor</th>
<th>System</th>
<th>In-Memory Fake</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td>AnthropicAI</td>
<td>API</td>
<td>✅</td>
<td>Includes content generators</td>
</tr>
<tr>
<td>AzureAI</td>
<td>API</td>
<td>✅</td>
<td>Includes content generators and GitHubModels compatibility</td>
</tr>
<tr>
<td>LM Studio</td>
<td>API</td>
<td>✅</td>
<td></td>
</tr>
<tr>
<td>Ollama</td>
<td>API</td>
<td>✅</td>
<td>Includes content generators and image generation</td>
</tr>
<tr>
<td>Open AI</td>
<td>API</td>
<td>✅</td>
<td>Includes content generators and image generation</td>
</tr>
</tbody>
</table>
<br/>
<br/>
<h3 id="storage-implementations">Storage Implementations<a class="heading-link" href="#storage-implementations" aria-label="Link to Storage Implementations">#</a>
</h3>
<table>
<thead>
<tr>
<th>Implementation</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td>In-Memory</td>
<td>Included with all Fakes</td>
</tr>
<tr>
<td>File-Based</td>
<td>Included with all Fakes</td>
</tr>
<tr>
<td>JDBC</td>
<td></td>
</tr>
<tr>
<td>Redis</td>
<td></td>
</tr>
<tr>
<td>S3</td>
<td></td>
</tr>
</tbody>
</table></description></item><item><title>http4k Core</title><link>https://http4k.org/ecosystem/http4k/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/ecosystem/http4k/</guid><description/></item><item><title>TDDing http4k Part 1: Building a walking skeleton</title><link>https://http4k.org/tutorial/tdding_http4k/part1/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/tutorial/tdding_http4k/part1/</guid><description><p>Until we have an application that can be deployed, we cannot create any business value. The Walking Skeleton
model dictates that putting the most trivial endpoint into a production environment will prove our deployment
pipeline is sound, and helps to set the direction for the testing strategy that we will use going forward.</p></description></item><item><title>Your first http4k app</title><link>https://http4k.org/tutorial/your_first_http4k_app/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/tutorial/your_first_http4k_app/</guid><description><p>Welcome to the world of http4k! In this guide, we&rsquo;ll run you through the steps required to get up and running with your first Kotlin server application. We&rsquo;ll generate the project, make some requests to it and then build it into a runnable application. By the end, you&rsquo;ll have a fully working app built packaged and tested using the Gradle build tool.</p></description></item><item><title>http4k AI</title><link>https://http4k.org/ecosystem/ai/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/ecosystem/ai/</guid><description><p>http4k AI is a lightweight AI integration toolkit which provides simplified adapters for connecting to popular LLM providers and AI services using <a href="https://http4k.org">http4k</a> compatible APIs, along with comprehensive Fake implementations for deterministic testing. These are all underpinned by the uniform <a href="https://monkey.org/~marius/funsrv.pdf">Server as a Function</a> model powered by the <code>HttpHandler</code> interface exposed by <a href="https://http4k.org/ecosystem/http4k/">http4k Core</a>, so you can:</p></description></item><item><title>TDDing http4k Part 2: Adding an endpoint</title><link>https://http4k.org/tutorial/tdding_http4k/part2/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/tutorial/tdding_http4k/part2/</guid><description><p>Starting with another EndToEnd test, we can then drill-down into the functional behaviour of the system by introducing
OCT (Out of Container) tests and converting the e2e test to just test endpoint wiring (so far). The common assertions have
also been converted to reusable extension methods on Response.</p></description></item><item><title>http4k Connect</title><link>https://http4k.org/ecosystem/connect/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/ecosystem/connect/</guid><description><p>http4k Connect is a lightweight API Client toolkit which includes libraries for connecting to popular third-party cloud
services and AI backends using <a href="https://http4k.org">http4k</a> compatible APIs, along with Fake implementations for usage
during local testing. These are all underpinned by a variation on the
uniform <a href="https://monkey.org/~marius/funsrv.pdf">Server as a Function</a> model powered by the <code>HttpHandler</code> interface
exposed by <a href="https://http4k.org/ecosystem/http4k/">http4k Core</a>, so you can:</p></description></item><item><title>Serverless http4k with AWS Lambda</title><link>https://http4k.org/tutorial/serverless_http4k_with_aws_lambda/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/tutorial/serverless_http4k_with_aws_lambda/</guid><description><p>In this guide, we&rsquo;ll run you through the steps required to get an http4k application deployed and running on AWS Lambda and available to call over the internet using AWS ApiGateway. If you&rsquo;re not familiar with the http4k concepts for HTTP and Serverless apps, then we advise you read them <a href="https://http4k.org/ecosystem/http4k/concepts/http/">here</a> and <a href="https://http4k.org/ecosystem/http4k/concepts/serverless/">here</a>. To make an app you can follow the <a href="https://http4k.org/tutorial/your_first_http4k_app/">Your first http4k app</a> tutorial before tackling this guide.</p></description></item><item><title>TDDing http4k Part 3: Adding another endpoint</title><link>https://http4k.org/tutorial/tdding_http4k/part3/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/tutorial/tdding_http4k/part3/</guid><description><h3 id="requirements">Requirements:<a class="heading-link" href="#requirements" aria-label="Link to Requirements:">#</a>
</h3>
<ul>
<li>Implement a &ldquo;multiply&rdquo; service, which will find the product of a number of integer values.</li>
</ul>
<h3 id="tests">Tests:<a class="heading-link" href="#tests" aria-label="Link to Tests:">#</a>
</h3>
<div class="code-example">
<div class="code-example-header">
<span class="code-example-lang">Kotlin</span>
<span class="code-example-file">tests.kt</span>
</div>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-kotlin" data-lang="kotlin"><span style="display:flex;"><span><span style="color:#66d9ef">package</span> content.tutorial.tdding_http4k.part3
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> com.natpryce.hamkrest.and
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> com.natpryce.hamkrest.assertion.assertThat
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> content.tutorial.tdding_http4k.part3.Matchers.answerShouldBe
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.client.OkHttp
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.core.Method.GET
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.core.Request
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.core.Response
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.core.Status.Companion.BAD_REQUEST
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.core.Status.Companion.OK
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.hamkrest.hasBody
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.hamkrest.hasStatus
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.junit.jupiter.api.AfterEach
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.junit.jupiter.api.BeforeEach
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.junit.jupiter.api.Test
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">object</span> <span style="color:#a6e22e">Matchers</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">fun</span> <span style="color:#a6e22e">Response</span>.answerShouldBe(expected: Int) {
</span></span><span style="display:flex;"><span> assertThat(<span style="color:#66d9ef">this</span>, hasStatus(OK).and(hasBody(expected.toString())))
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">EndToEndTest</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">val</span> client = OkHttp()
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">val</span> server = MyMathServer(<span style="color:#ae81ff">0</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">@BeforeEach</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">fun</span> <span style="color:#a6e22e">setup</span>() {
</span></span><span style="display:flex;"><span> server.start()
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">@AfterEach</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">fun</span> <span style="color:#a6e22e">teardown</span>() {
</span></span><span style="display:flex;"><span> server.stop()
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">@Test</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">fun</span> <span style="color:#a6e22e">`all endpoints are mounted correctly`</span>() {
</span></span><span style="display:flex;"><span> assertThat(
</span></span><span style="display:flex;"><span> client(Request(GET, <span style="color:#e6db74">&#34;http://localhost:</span><span style="color:#e6db74">${server.port()}</span><span style="color:#e6db74">/ping&#34;</span>)),
</span></span><span style="display:flex;"><span> hasStatus(OK)
</span></span><span style="display:flex;"><span> )
</span></span><span style="display:flex;"><span> client(
</span></span><span style="display:flex;"><span> Request(
</span></span><span style="display:flex;"><span> GET,
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;http://localhost:</span><span style="color:#e6db74">${server.port()}</span><span style="color:#e6db74">/add?value=1&amp;value=2&#34;</span>
</span></span><span style="display:flex;"><span> )
</span></span><span style="display:flex;"><span> ).answerShouldBe(<span style="color:#ae81ff">3</span>)
</span></span><span style="display:flex;"><span> client(
</span></span><span style="display:flex;"><span> Request(
</span></span><span style="display:flex;"><span> GET,
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;http://localhost:</span><span style="color:#e6db74">${server.port()}</span><span style="color:#e6db74">/multiply?value=2&amp;value=4&#34;</span>
</span></span><span style="display:flex;"><span> )
</span></span><span style="display:flex;"><span> ).answerShouldBe(<span style="color:#ae81ff">8</span>)
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">AddFunctionalTest</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">val</span> client = MyMathsApp()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">@Test</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">fun</span> <span style="color:#a6e22e">`adds values together`</span>() {
</span></span><span style="display:flex;"><span> client(Request(GET, <span style="color:#e6db74">&#34;/add?value=1&amp;value=2&#34;</span>)).answerShouldBe(<span style="color:#ae81ff">3</span>)
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">@Test</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">fun</span> <span style="color:#a6e22e">`answer is zero when no values`</span>() {
</span></span><span style="display:flex;"><span> client(Request(GET, <span style="color:#e6db74">&#34;/add&#34;</span>)).answerShouldBe(<span style="color:#ae81ff">0</span>)
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">@Test</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">fun</span> <span style="color:#a6e22e">`bad request when some values are not numbers`</span>() {
</span></span><span style="display:flex;"><span> assertThat(
</span></span><span style="display:flex;"><span> client(Request(GET, <span style="color:#e6db74">&#34;/add?value=1&amp;value=notANumber&#34;</span>)),
</span></span><span style="display:flex;"><span> hasStatus(BAD_REQUEST)
</span></span><span style="display:flex;"><span> )
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">MultiplyFunctionalTest</span> {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">val</span> client = MyMathsApp()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">@Test</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">fun</span> <span style="color:#a6e22e">`products values together`</span>() {
</span></span><span style="display:flex;"><span> client(Request(GET, <span style="color:#e6db74">&#34;/multiply?value=2&amp;value=4&#34;</span>)).answerShouldBe(<span style="color:#ae81ff">8</span>)
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">@Test</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">fun</span> <span style="color:#a6e22e">`answer is zero when no values`</span>() {
</span></span><span style="display:flex;"><span> client(Request(GET, <span style="color:#e6db74">&#34;/multiply&#34;</span>)).answerShouldBe(<span style="color:#ae81ff">0</span>)
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">@Test</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">fun</span> <span style="color:#a6e22e">`bad request when some values are not numbers`</span>() {
</span></span><span style="display:flex;"><span> assertThat(
</span></span><span style="display:flex;"><span> client(Request(GET, <span style="color:#e6db74">&#34;/multiply?value=1&amp;value=notANumber&#34;</span>)),
</span></span><span style="display:flex;"><span> hasStatus(BAD_REQUEST)
</span></span><span style="display:flex;"><span> )
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div>
</div>
<h3 id="production">Production:<a class="heading-link" href="#production" aria-label="Link to Production:">#</a>
</h3>
<div class="code-example">
<div class="code-example-header">
<span class="code-example-lang">Kotlin</span>
<span class="code-example-file">project.kt</span>
</div>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-kotlin" data-lang="kotlin"><span style="display:flex;"><span><span style="color:#66d9ef">package</span> content.tutorial.tdding_http4k.part3
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.core.HttpHandler
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.core.Method.GET
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.core.Request
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.core.Response
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.core.Status.Companion.OK
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.core.then
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.filter.ServerFilters.CatchLensFailure
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.lens.Query
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.lens.int
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.routing.bind
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.routing.routes
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.server.Http4kServer
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.server.Jetty
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.server.asServer
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fun</span> <span style="color:#a6e22e">MyMathServer</span>(port: Int): Http4kServer = MyMathsApp().asServer(Jetty(port))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fun</span> <span style="color:#a6e22e">MyMathsApp</span>(): HttpHandler = <span style="color:#a6e22e">CatchLensFailure</span>.then(
</span></span><span style="display:flex;"><span> routes(
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;/ping&#34;</span> bind GET to { _: Request <span style="color:#f92672">-&gt;</span> Response(OK) },
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;/add&#34;</span> bind GET to calculate { <span style="color:#66d9ef">it</span>.sum() },
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;/multiply&#34;</span> bind GET to calculate { <span style="color:#66d9ef">it</span>.fold(<span style="color:#ae81ff">1</span>) { memo, next <span style="color:#f92672">-&gt;</span> memo * next } }
</span></span><span style="display:flex;"><span> )
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">private</span> <span style="color:#66d9ef">fun</span> <span style="color:#a6e22e">calculate</span>(fn: (List&lt;Int&gt;) <span style="color:#f92672">-&gt;</span> Int): (Request) <span style="color:#f92672">-&gt;</span> Response {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">val</span> values = <span style="color:#a6e22e">Query</span>.int().multi.defaulted(<span style="color:#e6db74">&#34;value&#34;</span>, listOf())
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> { request: Request <span style="color:#f92672">-&gt;</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">val</span> valuesToCalc = values(request)
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">val</span> answer = <span style="color:#66d9ef">if</span> (valuesToCalc.isEmpty()) <span style="color:#ae81ff">0</span> <span style="color:#66d9ef">else</span> fn(valuesToCalc)
</span></span><span style="display:flex;"><span> Response(OK).body(answer.toString())
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div>
</div>
<p>Next: <a href="https://http4k.org/tutorial/tdding_http4k/part4/">Part 4: Adding an external dependency</a></p></description></item><item><title>Going native with Graal on AWS Lambda</title><link>https://http4k.org/tutorial/going_native_with_graal_on_aws_lambda/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/tutorial/going_native_with_graal_on_aws_lambda/</guid><description><p>In this guide, we&rsquo;ll run you through the steps required to get an http4k application deployed and running on AWS Lambda with GraalVM and available to call over the internet using AWS ApiGateway. If you&rsquo;re not familiar with the http4k concepts for HTTP and Serverless apps, then we advise you read them <a href="https://http4k.org/ecosystem/http4k/concepts/http/">here</a> and <a href="https://http4k.org/ecosystem/http4k/concepts/serverless/">here</a>. To make an app you can follow the <a href="https://http4k.org/tutorial/your_first_http4k_app/">Your first http4k app</a> tutorial. Then follow the steps in the <a href="https://http4k.org/tutorial/serverless_http4k_with_aws_lambda/">Serverless http4k with AWS Lambda</a> tutorial before tackling this guide.</p></description></item><item><title>http4k Enterprise</title><link>https://http4k.org/ecosystem/enterprise/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/ecosystem/enterprise/</guid><description><p>The http4k Enterprise ecosystem provides the infrastructure and tooling that organisations need to use http4k with confidence in regulated and security-conscious environments. It covers authenticated repository access, build-time artifact verification, and supply chain security — ensuring that every http4k dependency in your build is traceable, signed, and verified.</p></description></item><item><title>TDDing http4k Part 4: Adding an external dependency</title><link>https://http4k.org/tutorial/tdding_http4k/part4/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/tutorial/tdding_http4k/part4/</guid><description><p>At this point, the separation of the layers starts to become clear:</p>
<ul>
<li>The server layer is responsible for taking external configuration and instantiating the app layer.</li>
<li>The application layer API is only in terms of HTTP transports - it constructs business level abstractions
which are passed down into to the individual endpoints</li>
</ul>
<p>The process here is to create fake versions of the dependency which can be tested against through the business interface.
This requires another style of testing, CDCs (Consumer Driven Contracts), to be created. These contract tests ensure that our
interactions with the external service are valid.</p></description></item><item><title>Create an MCP Server in 2 Lines of Code</title><link>https://http4k.org/tutorial/create_an_mcp_server/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/tutorial/create_an_mcp_server/</guid><description><p>This tutorial gets you from zero to a working MCP server in a few lines of Kotlin. We&rsquo;ll build a clock tool that any MCP host (like Claude Desktop) can call, and we&rsquo;ll do it with almost no ceremony. If you want to add more capabilities and testing, continue to <a href="https://http4k.org/tutorial/add_mcp_capabilities/">Add MCP Capabilities</a>. For building interactive UIs inside the host, see <a href="https://http4k.org/tutorial/build_a_simple_mcp_app/">Build an MCP App</a>.</p></description></item><item><title>Add MCP Capabilities</title><link>https://http4k.org/tutorial/add_mcp_capabilities/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/tutorial/add_mcp_capabilities/</guid><description><p>In <a href="https://http4k.org/tutorial/create_an_mcp_server/">Create an MCP Server</a> we built a working MCP server with a single tool. Now we&rsquo;ll add the full range of MCP capabilities: a tool with typed arguments, a resource, and a prompt. Then we&rsquo;ll test the whole thing in-memory — no network, no running server, no squinting at Claude&rsquo;s output.</p></description></item><item><title>Building an MCP App with http4k</title><link>https://http4k.org/tutorial/build_a_simple_mcp_app/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/tutorial/build_a_simple_mcp_app/</guid><description><p>This tutorial walks through building <strong>Repo Health Checker</strong> — an MCP App that displays an interactive UI inside an MCP host (like Claude Desktop), fetches
health metrics from the GitHub API, and lets users select metrics and a focus mode for analysis.</p></description></item><item><title>An MCP Server That Fits in a Tweet (and MCP Apps That Don't Need To)</title><link>https://http4k.org/news/an_mcp_server_in_a_tweet/</link><pubDate>Tue, 10 Mar 2026 00:00:00 +0000</pubDate><guid>https://http4k.org/news/an_mcp_server_in_a_tweet/</guid><description><img class="imageMid my-4" src="./image.webp" alt="http4k MCP SDK - an iceberg showing the depth beneath a single line of Kotlin"/>
<p>You can turn any MCP Capability - a Tool, a Resource, a Prompt - into a working, spec-compliant MCP server in fewer characters than an old-school tweet. No code generation, no YAML manifests, no runtime magic - just a function that does a thing, served over Streamable HTTP.</p></description></item><item><title>http4k AI - Because AI Without Tests is Just Expensive Random Number Generation</title><link>https://http4k.org/news/ai_without_tests_is_just_expensive_random_number_generation/</link><pubDate>Sat, 14 Jun 2025 00:00:00 +0000</pubDate><guid>https://http4k.org/news/ai_without_tests_is_just_expensive_random_number_generation/</guid><description><img class="imageMid my-4" src="./circuit.webp" alt="http4k logo"/>
<p><strong>TL;DR:</strong> We&rsquo;re launching <strong><a href="https://http4k.org/ecosystem/ai">http4k AI</a></strong> - a dedicated ecosystem for building testable, observable AI integrations on the JVM. Built on the foundation of http4k&rsquo;s 8-year track record and 50 million downloads, <strong><a href="https://github.com/http4k/http4k/releases/tag/6.14.0.0">v6.14.0.0</a></strong> ships today with universal LLM APIs, comprehensive fakes, MCP SDK with bleeding-edge Elicitation capabilities, and 5 major provider integrations. <strong>Plus:</strong> Our updated <strong><a href="https://http4k.org/commercial-license/">commercial license</a></strong> now supports qualifying small businesses (under $1M ARR) with free Pro access.</p></description></item><item><title>Simplifying MCP: http4k's Updated Authentication Model - Less Code, More Power</title><link>https://http4k.org/news/simplifying-mcp/</link><pubDate>Fri, 09 May 2025 00:00:00 +0000</pubDate><guid>https://http4k.org/news/simplifying-mcp/</guid><description><img class="imageMid my-4" src="./http4k-oauth-mcp.png" alt="http4k MCP logo"/>
<p>We&rsquo;re excited to share a significant update to our <a href="https://mcp.http4k.org">http4k Model Context Protocol (MCP) SDK</a>! 🚀. Based on community feedback and our commitment to making AI integration as frictionless as possible, we&rsquo;ve streamlined the authentication model in our latest release.</p></description></item><item><title>http4k MCP Has Landed: Build Your Own AI Agents with Zero Compromise on Testability!</title><link>https://http4k.org/news/http4k_mcp_has_landed/</link><pubDate>Fri, 28 Mar 2025 00:00:00 +0000</pubDate><guid>https://http4k.org/news/http4k_mcp_has_landed/</guid><description><img class="imageMid my-4" src="./http4k-mcp.png" alt="http4k MCP logo"/>
<p>We&rsquo;re thrilled to announce the launch of the http4k <a href="https://mcp.http4k.org">Model Context Protocol (MCP) SDK</a>! 🚀
This powerful addition to the http4k ecosystem brings seamless AI integration capabilities to your applications through
a clean, functional API that stays true to http4k&rsquo;s core principles.</p></description></item><item><title>http4k v6: Still the most testable web toolkit on the planet!*</title><link>https://http4k.org/news/http4k-v6-still-the-most-testable-web-toolkit-on-the-planet/</link><pubDate>Sat, 01 Feb 2025 00:00:00 +0000</pubDate><guid>https://http4k.org/news/http4k-v6-still-the-most-testable-web-toolkit-on-the-planet/</guid><description><img class="imageMid my-4" src="./takeoff.png" alt="http4k logo"/>
<p>As previewed in our previous post, http4k v6 is finally here 🚀! We’ve been incredibly busy planning this release for
about 6 months and have been exploring the best ways to expand the http4k universe to make things even better.</p></description></item><item><title>CVE-2024-55875: XXE(XML External Entity Injection) vulnerability</title><link>https://http4k.org/security/cve-2024-55875/</link><pubDate>Thu, 12 Dec 2024 00:00:00 +0000</pubDate><guid>https://http4k.org/security/cve-2024-55875/</guid><description><h3 id="description">Description<a class="heading-link" href="#description" aria-label="Link to Description">#</a>
</h3>
<p>There is a XXE(XML External Entity Injection) vulnerability when http4k handling malicious XML contents within requests,
which might allow attackers to read local sensitive information on server, trigger Server-side Request Forgery and even
execute code under some circumstances.</p></description></item><item><title>Preview: http4k v6 and beyond! Introducing Enterprise Edition and Long-Term Support</title><link>https://http4k.org/news/http4k-v6-and-ee/</link><pubDate>Tue, 03 Dec 2024 00:00:00 +0000</pubDate><guid>https://http4k.org/news/http4k-v6-and-ee/</guid><description><h4 id="tldr">TL;DR<a class="heading-link" href="#tldr" aria-label="Link to TL;DR">#</a>
</h4>
<ul>
<li>http4k will release its next major version (6) in January 2025</li>
<li>http4k Community Edition (CE) - will continue to be released under the existing Apache 2 license.</li>
<li>From v6, http4k CE will set its minimum supported target JVM version to 21.</li>
<li>We are introducing the <a href="https://http4k.org/enterprise">http4k Enterprise Edition (EE)</a> subscription under a new commercial license, which will provide LTS support for http4k v5 and older JVMs as well as enterprise support features.</li>
</ul>
<h4 id="a-brief-history-of-time">A brief history of time<a class="heading-link" href="#a-brief-history-of-time" aria-label="Link to A brief history of time">#</a>
</h4>
<p>From its inception over seven years ago, http4k has been increasingly adopted by teams looking to leverage its powerful simplicity, focus on testability and uncompromised stability in their projects. That now translates to over two million monthly downloads. With over 150 modules, http4k has continued to grow steadily and to have some of the most flexible support and integrations available in the Kotlin ecosystem, all backed up by rock-solid test suites and our trademark lightweight approach.</p></description></item><item><title>http4k Platform v5 - New Servers, Loom, TracerBullet, OpenAI plugin SDK and more</title><link>https://http4k.org/news/http4k_v5/</link><pubDate>Thu, 01 Jun 2023 00:00:00 +0000</pubDate><guid>https://http4k.org/news/http4k_v5/</guid><description><img class="imageMid" src="./lego.png" alt="http4k lego"/>
<p>We’re thrilled to announce the next major release of http4k! Since the last major release, the team has been busy enhancing existing features, adding new capabilities with help from our amazing community, things that we&rsquo;ve needed on our own real world projects, and a sprinkling of new magic to keep pushing the boundaries of what&rsquo;s possible with the http4k technology - all 127 modules of it.</p></description></item><item><title>Add typesafe 12-factor configuration to http4k apps with Environments</title><link>https://http4k.org/news/typesafe_configuration/</link><pubDate>Fri, 01 Oct 2021 00:00:00 +0000</pubDate><guid>https://http4k.org/news/typesafe_configuration/</guid><description><h3 id="intro">Intro<a class="heading-link" href="#intro" aria-label="Link to Intro">#</a>
</h3>
<p>This post covers the various concerns around configuring HTTP apps, and introduces the http4k approach for addressing these when deploying applications into cloud-native environments, which leverages the Kotlin type system for maximum safely and code reuse.</p></description></item><item><title>Reassurance to http4k users regarding JCenter shutdown</title><link>https://http4k.org/news/regarding_jcenter/</link><pubDate>Mon, 01 Feb 2021 00:00:00 +0000</pubDate><guid>https://http4k.org/news/regarding_jcenter/</guid><description><p>It was announced this week that the JCenter artifact repository would be <a href="https://jfrog.com/blog/into-the-sunset-bintray-jcenter-gocenter-and-chartcenter/">shutting down in May 2021</a>. As JCenter was a superset of the Maven Central repository, this obviously comes as disappointing and worrying news regarding the future of Open Source software distribution for the JVM. Many builds will undoubtedly break as a result of this move.</p></description></item><item><title>http4k v4 - 17 platforms and counting...</title><link>https://http4k.org/news/http4k_v4/</link><pubDate>Fri, 01 Jan 2021 00:00:00 +0000</pubDate><guid>https://http4k.org/news/http4k_v4/</guid><description><p>Well, at last it&rsquo;s here - after 3 years - http4k v4! Following on from the <a href="https://http4k.org/news/retrospective_v3/">retrospective</a> that we did on version 3, we&rsquo;ve been busy polishing, tidying up the edges, and pushing out a bunch of changes to make the project sparkle. Ready? Then let&rsquo;s dive into the good stuff that&rsquo;s been going on at http4k Towers.</p></description></item><item><title>http4k Toolbox - Guns for show, knives for a pro</title><link>https://http4k.org/news/toolbox/</link><pubDate>Sun, 01 Nov 2020 00:00:00 +0000</pubDate><guid>https://http4k.org/news/toolbox/</guid><description><img class="imageMid" src="./guns.jpg" alt="lock stock: guns for show"/>
<p>Over the years of creating apps with http4k, we&rsquo;ve collated several tools that we use to turbo charge our development activities. While working on v4 of the library, and with a little time on our hands, we decided to bring all of these tools together into a single place so that all of our users could get their benefits.</p></description></item><item><title>Nanoservices - The Power of Composition</title><link>https://http4k.org/news/nanoservices/</link><pubDate>Thu, 01 Oct 2020 00:00:00 +0000</pubDate><guid>https://http4k.org/news/nanoservices/</guid><description><p>http4k is a small library with a zero dependencies (apart from Kotlin StdLib), but what really makes it shine is the power afforded by the combination of the &ldquo;Server as a Function&rdquo; concepts of <code>HttpHandler</code> and <code>Filter</code>.</p></description></item><item><title>A retrospective on http4k v3</title><link>https://http4k.org/news/retrospective_v3/</link><pubDate>Tue, 01 Sep 2020 00:00:00 +0000</pubDate><guid>https://http4k.org/news/retrospective_v3/</guid><description><p>It&rsquo;s been quite a long time since we released version 3 of http4k all the way back in November 2017. Wow - that&rsquo;s over 1000 days in fact! Still, that doesn&rsquo;t mean that we&rsquo;ve been sitting on our hands over in <strong>http4k Towers</strong> - far from it, we&rsquo;ve been busier than ever making sure that we&rsquo;ll remember 2020 for more than just hibernating away in a bunker. In fact, the current interesting situation did give us an idea for a pretty original piece of swag&hellip;</p></description></item><item><title>Documenting http4k APIs with OpenApi3</title><link>https://http4k.org/news/documenting_apis_with_openapi/</link><pubDate>Wed, 01 May 2019 00:00:00 +0000</pubDate><guid>https://http4k.org/news/documenting_apis_with_openapi/</guid><description><p>This post describes <strong>http4k</strong> support for fully describing and securing HTTP endpoints using version 3 of the <strong><a href="https://www.openapis.org/">OpenApi</a></strong> specification, providing typesafe JSON-schema documentation for messages and automatically validating incoming HTTP traffic.</p></description></item><item><title>Websockets. But typesafe. And testable. Without the Server.</title><link>https://http4k.org/news/typesafe_websockets/</link><pubDate>Fri, 01 Dec 2017 00:00:00 +0000</pubDate><guid>https://http4k.org/news/typesafe_websockets/</guid><description><p>Reaction to the last post introducing http4k was pretty good, and one of the most popular questions was: <strong>&ldquo;But what about Websockets&rdquo;</strong>?</p></description></item><item><title>Server as a Function. In Kotlin. Typesafe. Without the Server.</title><link>https://http4k.org/news/meet_http4k/</link><pubDate>Wed, 01 Nov 2017 00:00:00 +0000</pubDate><guid>https://http4k.org/news/meet_http4k/</guid><description><h3 id="meet-http4k">Meet http4k<a class="heading-link" href="#meet-http4k" aria-label="Link to Meet http4k">#</a>
</h3>
<p>http4k is an HTTP toolkit written in Kotlin that enables the serving and consuming
of HTTP services in a functional and consistent way.</p></description></item><item><title/><link>https://http4k.org/ecosystem/connect/reference/slack/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/ecosystem/connect/reference/slack/</guid><description><h2 id="description-feature-overview-of-the-http4k-connect-slack-modules">****&mdash;
category: Reference
type: ecosystem
ecosystem: http4k Connect
title: Slack
description: Feature overview of the http4k Connect Slack modules<a class="heading-link" href="#description-feature-overview-of-the-http4k-connect-slack-modules" aria-label="Link to ****—
category: Reference
type: ecosystem
ecosystem: http4k Connect
title: Slack
description: Feature overview of the http4k Connect Slack modules">#</a>
</h2>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-kotlin" data-lang="kotlin"><span style="display:flex;"><span>dependencies {
</span></span><span style="display:flex;"><span>
implementation(platform("org.http4k:http4k-bom:6.40.1.0"))
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-connect-slack&#34;</span>)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The Slack connector provides the following Actions:</p></description></item><item><title>About the docs</title><link>https://http4k.org/learn/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/learn/</guid><description><p>The http4k technical documentation has been designed following the <strong>Grand Unified Theory of Documentation</strong>. Overall, the http4k developers firmly believe that API design should be natural and friendly to the user, and hence the codebase is not heavily commented. If we have done our jobs correctly, someone with the correct knowledge of a particular domain or platform should be able to implement systems using the http4k APIs by just using an IDE.</p></description></item><item><title>Anthropic</title><link>https://http4k.org/ecosystem/ai/reference/anthropic/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/ecosystem/ai/reference/anthropic/</guid><description><h3 id="installation">Installation<a class="heading-link" href="#installation" aria-label="Link to Installation">#</a>
</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-kotlin" data-lang="kotlin"><span style="display:flex;"><span>dependencies {
</span></span><span style="display:flex;"><span>
implementation(platform("org.http4k:http4k-bom:6.40.1.0"))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// for the Universal LLM adapter
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-ai-llm-anthropic&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// for the low-level AnthropicAI API client
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-connect-ai-anthropic&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// for the FakeAnthropicAI server
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-connect-ai-anthropic-fake&#34;</span>)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The http4k-ai AnthropicAI integrations provide:</p></description></item><item><title>API Clients</title><link>https://http4k.org/ecosystem/connect/concepts/clients/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/ecosystem/connect/concepts/clients/</guid><description><p>Each system API Client is modelled as a single function with arity 1 (that is it takes only a single parameter) returning a <a href="https://github.com/fork-handles/forkhandles/tree/trunk/result4k">Result4k</a> Success/Failure monad type), which is known as an <code>Action</code>. The Client is responsible for managing the overall protocol with the remote system. There are also a set of extension methods generated to provide a more traditional function-based version of the same interface.</p></description></item><item><title>API: CloudEvents</title><link>https://http4k.org/ecosystem/http4k/reference/cloud_events/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/ecosystem/http4k/reference/cloud_events/</guid><description><h3 id="installation-gradle">Installation (Gradle)<a class="heading-link" href="#installation-gradle" aria-label="Link to Installation (Gradle)">#</a>
</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-kotlin" data-lang="kotlin"><span style="display:flex;"><span>dependencies {
</span></span><span style="display:flex;"><span>
implementation(platform("org.http4k:http4k-bom:6.40.1.0"))
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-api-cloudevents&#34;</span>)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The <a href="https://cloudevents.io/">Cloud Events</a> spec defines a common format for Events produced by Cloud services.</p></description></item><item><title>API: GraphQL</title><link>https://http4k.org/ecosystem/http4k/reference/graphql/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/ecosystem/http4k/reference/graphql/</guid><description><h3 id="installation-gradle">Installation (Gradle)<a class="heading-link" href="#installation-gradle" aria-label="Link to Installation (Gradle)">#</a>
</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-kotlin" data-lang="kotlin"><span style="display:flex;"><span>dependencies {
</span></span><span style="display:flex;"><span>
implementation(platform("org.http4k:http4k-bom:6.40.1.0"))
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-api-graphql&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// for the example below you will also need this dependency...
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> implementation(<span style="color:#e6db74">&#34;com.expediagroup:graphql-kotlin-schema-generator&#34;</span>, version = <span style="color:#e6db74">&#34;5.3.2&#34;</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h3 id="about">About<a class="heading-link" href="#about" aria-label="Link to About">#</a>
</h3>
<p>This module provides http4k integration for the excellent <a href="https://www.graphql-java.com/">GraphQL-java</a> library, allowing you to either serve or consume <a href="https://graphql.org">GraphQL</a> services using a simple adapter API.</p></description></item><item><title>API: JSON-RPC</title><link>https://http4k.org/ecosystem/http4k/reference/jsonrpc/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/ecosystem/http4k/reference/jsonrpc/</guid><description><h3 id="installation-gradle">Installation (Gradle)<a class="heading-link" href="#installation-gradle" aria-label="Link to Installation (Gradle)">#</a>
</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-kotlin" data-lang="kotlin"><span style="display:flex;"><span>dependencies {
</span></span><span style="display:flex;"><span>
implementation(platform("org.http4k:http4k-bom:6.40.1.0"))
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-api-jsonrpc&#34;</span>)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h3 id="about">About<a class="heading-link" href="#about" aria-label="Link to About">#</a>
</h3>
<p>Support for JSON-RPC handlers, with support for both manual and automatic marshalling modes.</p></description></item><item><title>API: OpenApi</title><link>https://http4k.org/ecosystem/http4k/reference/contracts/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/ecosystem/http4k/reference/contracts/</guid><description><h3 id="installation-gradle">Installation (Gradle)<a class="heading-link" href="#installation-gradle" aria-label="Link to Installation (Gradle)">#</a>
</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-kotlin" data-lang="kotlin"><span style="display:flex;"><span>dependencies {
</span></span><span style="display:flex;"><span>
implementation(platform("org.http4k:http4k-bom:6.40.1.0"))
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-api-openapi&#34;</span>)
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-format-&lt;insert json lib&gt;&#34;</span>)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h3 id="about">About<a class="heading-link" href="#about" aria-label="Link to About">#</a>
</h3>
<p>The <code>http4k-api-openapi</code> module adds a much more sophisticated routing mechanism to that available in <code>http4k-core</code>. It adds the facility
to declare server-side <code>Routes</code> in a completely typesafe way, leveraging the Lens functionality from the core. These <code>Routes</code> are combined into <code>Contracts</code>, which have the following features:</p></description></item><item><title>Arrange Filters into stacks</title><link>https://http4k.org/howto/arrange_filters_into_stacks/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/howto/arrange_filters_into_stacks/</guid><description><p>http4k Filters are just decorator functions for HttpHandlers and process requests by applying the following process:</p>
<ol>
<li>Receive the Request</li>
<li>Modify it</li>
<li>Pass it to the next HttpHandler in the chain</li>
<li>Receive the Response</li>
<li>Modify it</li>
<li>Return it to the caller</li>
</ol>
<p>We can reason that we can combine filters together to form chains, or &ldquo;Stacks&rdquo; of processing logic - moving from the most generic to the most specific. But the ordering
of the filters is important in order that we have the information at the point in the stack when we need it. For example - if we want to record all HTTP traffic, we much ensure that we
do this after any exception handling has occurred (so that we can record the 5XX properly). Experience has shown that there is a general formula to be used when constructing stacks.</p></description></item><item><title>Authentication for HTTP services</title><link>https://http4k.org/howto/secure_and_auth_http/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/howto/secure_and_auth_http/</guid><description><h3 id="gradle-setup">Gradle setup<a class="heading-link" href="#gradle-setup" aria-label="Link to Gradle setup">#</a>
</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-kotlin" data-lang="kotlin"><span style="display:flex;"><span>dependencies {
</span></span><span style="display:flex;"><span>
implementation(platform("org.http4k:http4k-bom:6.40.1.0"))
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-core&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// for OAuth examples
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-security-oauth&#34;</span>)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>http4k provides a set of Filters for authenticating into other HTTP services. Usage of these filters is shown below to authenticate into a service. Each authentication type is generally available using both dynamic and static credential provision and checking mechanisms.</p></description></item><item><title>AWS</title><link>https://http4k.org/ecosystem/connect/reference/aws/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/ecosystem/connect/reference/aws/</guid><description><p>http4k-connect provides a standardised mechanism to connect to several AWS services. They all use the same mechanisms for authentication, which is what this page is about.</p></description></item><item><title>AWS: AppRunner</title><link>https://http4k.org/ecosystem/connect/reference/amazon/apprunner/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/ecosystem/connect/reference/amazon/apprunner/</guid><description><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-kotlin" data-lang="kotlin"><span style="display:flex;"><span>dependencies {
</span></span><span style="display:flex;"><span>
implementation(platform("org.http4k:http4k-bom:6.40.1.0"))
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-connect-amazon-apprunner&#34;</span>)
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-connect-amazon-apprunner-fake&#34;</span>)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The AppRunner connector provides the following Actions:</p>
<pre><code> * CreateService
* DeleteService
* ListServices
</code></pre>
<h3 id="example-usage">Example usage<a class="heading-link" href="#example-usage" aria-label="Link to Example usage">#</a>
</h3>
<div class="code-example">
<div class="code-example-header">
<span class="code-example-lang">Kotlin</span>
<span class="code-example-file">example.kt</span>
</div>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-kotlin" data-lang="kotlin"><span style="display:flex;"><span><span style="color:#66d9ef">package</span> content.ecosystem.connect.reference.amazon.apprunner
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.aws.AwsCredentials
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.client.JavaHttpClient
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.connect.amazon.apprunner.AppRunner
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.connect.amazon.apprunner.FakeAppRunner
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.connect.amazon.apprunner.Http
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.connect.amazon.apprunner.listServices
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.connect.amazon.core.model.Region
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.connect.amazon.lambda.model.FunctionName
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.core.HttpHandler
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.filter.debug
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#66d9ef">val</span> USE_REAL_CLIENT = <span style="color:#66d9ef">false</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fun</span> <span style="color:#a6e22e">main</span>() {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">val</span> fakeAppRunner = FakeAppRunner()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// we can connect to the real service or the fake (drop in replacement)
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#66d9ef">val</span> http: HttpHandler = <span style="color:#66d9ef">if</span> (USE_REAL_CLIENT) JavaHttpClient() <span style="color:#66d9ef">else</span> fakeAppRunner
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// create a client
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#66d9ef">val</span> client = <span style="color:#a6e22e">AppRunner</span>.Http(<span style="color:#a6e22e">Region</span>.of(<span style="color:#e6db74">&#34;us-east-1&#34;</span>), { AwsCredentials(<span style="color:#e6db74">&#34;accessKeyId&#34;</span>, <span style="color:#e6db74">&#34;secretKey&#34;</span>) }, http.debug())
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// all operations return a Result monad of the API type
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> println(client.listServices())
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div>
</div>
<p>The client APIs utilise the <code>http4k-platform-aws</code> module for request signing, which means no dependencies on the incredibly fat
Amazon-SDK JARs. This means this integration is perfect for running Serverless Lambdas where binary size is a
performance factor.</p></description></item><item><title>AWS: CloudFront</title><link>https://http4k.org/ecosystem/connect/reference/amazon/cloudfront/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/ecosystem/connect/reference/amazon/cloudfront/</guid><description><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-kotlin" data-lang="kotlin"><span style="display:flex;"><span>dependencies {
</span></span><span style="display:flex;"><span>
implementation(platform("org.http4k:http4k-bom:6.40.1.0"))
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-connect-amazon-cloudfront&#34;</span>)
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-connect-amazon-cloudfront-fake&#34;</span>)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The CloudFront connector provides the following Actions:</p>
<pre><code> * CreateInvalidation
</code></pre>
<p>The client APIs utilise the <code>http4k-platform-aws</code> module for request signing, which means no dependencies on the incredibly fat
Amazon-SDK JARs. This means this integration is perfect for running Serverless Lambdas where binary size is a
performance factor.</p></description></item><item><title>AWS: CloudWatch</title><link>https://http4k.org/ecosystem/connect/reference/amazon/cloudwatch/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/ecosystem/connect/reference/amazon/cloudwatch/</guid><description><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-kotlin" data-lang="kotlin"><span style="display:flex;"><span>dependencies {
</span></span><span style="display:flex;"><span>
implementation(platform("org.http4k:http4k-bom:6.40.1.0"))
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-connect-amazon-cloudwatch&#34;</span>)
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-connect-amazon-cloudwatch-fake&#34;</span>)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The CloudWatch connector provides the following Actions:</p>
<ul>
<li>DeleteAlarms</li>
<li>DescribeAlarms</li>
<li>DescribeAlarmsForMetric</li>
<li>DisableAlarmActions</li>
<li>EnableAlarmActions</li>
<li>GetMetricData</li>
<li>GetMetricStatistics</li>
<li>ListMetrics</li>
<li>ListTagsForResource</li>
<li>PutCompositeAlarm</li>
<li>PutMetricAlarm</li>
<li>PutMetricData</li>
<li>SetAlarmState</li>
<li>TagResource</li>
<li>UntagResource</li>
</ul>
<p>The client APIs utilise the <code>http4k-platform-aws</code> module for request signing, which means no dependencies on the incredibly fat
Amazon-SDK JARs. This means this integration is perfect for running Serverless Lambdas where binary size is a
performance factor.</p></description></item><item><title>AWS: Cloudwatch Evidently</title><link>https://http4k.org/ecosystem/connect/reference/amazon/evidently/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/ecosystem/connect/reference/amazon/evidently/</guid><description><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-kotlin" data-lang="kotlin"><span style="display:flex;"><span>dependencies {
</span></span><span style="display:flex;"><span>
implementation(platform("org.http4k:http4k-bom:6.40.1.0"))
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-connect-amazon-evidently&#34;</span>)
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-connect-amazon-evidently-fake&#34;</span>)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The Evidently connector provides the following Actions:</p>
<pre><code> * CreateProject
* CreateFeature
* EvaluateFeature
* BatchEvaluateFeature
* DeleteFeature
* DeleteProject
</code></pre>
<h3 id="example-usage">Example usage<a class="heading-link" href="#example-usage" aria-label="Link to Example usage">#</a>
</h3>
<div class="code-example">
<div class="code-example-header">
<span class="code-example-lang">Kotlin</span>
<span class="code-example-file">example.kt</span>
</div>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-kotlin" data-lang="kotlin"><span style="display:flex;"><span><span style="color:#66d9ef">package</span> content.ecosystem.connect.reference.amazon.evidently
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> dev.forkhandles.result4k.onFailure
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.aws.AwsCredentials
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.client.JavaHttpClient
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.connect.amazon.core.model.Region
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.connect.amazon.evidently.Evidently
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.connect.amazon.evidently.FakeEvidently
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.connect.amazon.evidently.Http
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.connect.amazon.evidently.createFeature
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.connect.amazon.evidently.createProject
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.connect.amazon.evidently.evaluateFeature
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.connect.amazon.evidently.model.EntityId
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.connect.amazon.evidently.model.FeatureName
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.connect.amazon.evidently.model.ProjectName
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.connect.amazon.evidently.model.VariableValue
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.connect.amazon.evidently.model.VariationName
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.core.HttpHandler
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.filter.debug
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#66d9ef">val</span> USE_REAL_CLIENT = <span style="color:#66d9ef">false</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fun</span> <span style="color:#a6e22e">main</span>() {
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// we can connect to the real service or the fake (drop in replacement)
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#66d9ef">val</span> http: HttpHandler = <span style="color:#66d9ef">if</span> (USE_REAL_CLIENT) JavaHttpClient() <span style="color:#66d9ef">else</span> FakeEvidently()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// create a client
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#66d9ef">val</span> client = <span style="color:#a6e22e">Evidently</span>.Http(<span style="color:#a6e22e">Region</span>.of(<span style="color:#e6db74">&#34;us-east-1&#34;</span>), { AwsCredentials(<span style="color:#e6db74">&#34;accessKeyId&#34;</span>, <span style="color:#e6db74">&#34;secretKey&#34;</span>) }, http.debug())
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">val</span> projectName = <span style="color:#a6e22e">ProjectName</span>.of(<span style="color:#e6db74">&#34;acme-service&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">val</span> featureName = <span style="color:#a6e22e">FeatureName</span>.of(<span style="color:#e6db74">&#34;take-over-the-world&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// create project
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> client.createProject(projectName)
</span></span><span style="display:flex;"><span> .onFailure { <span style="color:#66d9ef">it</span>.reason.throwIt() }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// create feature
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> client.createFeature(
</span></span><span style="display:flex;"><span> project = projectName,
</span></span><span style="display:flex;"><span> name = featureName,
</span></span><span style="display:flex;"><span> defaultVariation = <span style="color:#a6e22e">VariationName</span>.of(<span style="color:#e6db74">&#34;bide-our-time&#34;</span>),
</span></span><span style="display:flex;"><span> variations = mapOf(
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">VariationName</span>.of(<span style="color:#e6db74">&#34;bide-our-time&#34;</span>) to VariableValue(<span style="color:#66d9ef">false</span>),
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">VariationName</span>.of(<span style="color:#e6db74">&#34;it-is-time&#34;</span>) to VariableValue(<span style="color:#66d9ef">true</span>)
</span></span><span style="display:flex;"><span> ),
</span></span><span style="display:flex;"><span> entityOverrides = mapOf(
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">EntityId</span>.of(<span style="color:#e6db74">&#34;test-subject-1&#34;</span>) to <span style="color:#a6e22e">VariationName</span>.of(<span style="color:#e6db74">&#34;it-is-time&#34;</span>)
</span></span><span style="display:flex;"><span> )
</span></span><span style="display:flex;"><span> ).onFailure { <span style="color:#66d9ef">it</span>.reason.throwIt() }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// evaluate feature
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#66d9ef">val</span> result = client.evaluateFeature(projectName, featureName, <span style="color:#a6e22e">EntityId</span>.of(<span style="color:#e6db74">&#34;test-subject-2&#34;</span>))
</span></span><span style="display:flex;"><span> .onFailure { <span style="color:#66d9ef">it</span>.reason.throwIt() }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> println(result)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div>
</div>
<p>The client APIs utilise the <code>http4k-platform-aws</code> module for request signing, which means no dependencies on the incredibly fat
Amazon-SDK JARs. This means this integration is perfect for running Serverless Lambdas where binary size is a
performance factor.</p></description></item><item><title>AWS: CloudWatchLogs</title><link>https://http4k.org/ecosystem/connect/reference/amazon/cloudwatchlogs/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/ecosystem/connect/reference/amazon/cloudwatchlogs/</guid><description><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-kotlin" data-lang="kotlin"><span style="display:flex;"><span>dependencies {
</span></span><span style="display:flex;"><span>
implementation(platform("org.http4k:http4k-bom:6.40.1.0"))
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-connect-amazon-cloudwatchlogs&#34;</span>)
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-connect-amazon-cloudwatchlogs-fake&#34;</span>)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The CloudWatchLogs connector provides the following Actions:</p>
<ul>
<li>CreateLogGroup</li>
<li>CreateLogStream</li>
<li>DeleteLogGroup</li>
<li>DeleteLogStream</li>
<li>FilterLogEvents</li>
<li>PutLogEvents</li>
</ul>
<p>The client APIs utilise the <code>http4k-platform-aws</code> module for request signing, which means no dependencies on the incredibly fat
Amazon-SDK JARs. This means this integration is perfect for running Serverless Lambdas where binary size is a
performance factor.</p></description></item><item><title>AWS: Cognito</title><link>https://http4k.org/ecosystem/connect/reference/amazon/cognito/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/ecosystem/connect/reference/amazon/cognito/</guid><description><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-kotlin" data-lang="kotlin"><span style="display:flex;"><span>dependencies {
</span></span><span style="display:flex;"><span>
implementation(platform("org.http4k:http4k-bom:6.40.1.0"))
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-connect-amazon-cognito&#34;</span>)
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-connect-amazon-cognito-fake&#34;</span>)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The Cognito connector provides the following Actions:</p>
<ul>
<li>AdminCreateUser</li>
<li>AdminDeleteUser</li>
<li>AdminDisableUser</li>
<li>AdminEnableUser</li>
<li>AdminGetUser</li>
<li>AdminResetUserPassword</li>
<li>AdminSetUserPassword</li>
<li>AssociateSoftwareToken</li>
<li>ConfirmForgotPassword</li>
<li>CreateResourceServer</li>
<li>CreateUserPool</li>
<li>CreateUserPoolClient</li>
<li>CreateUserPoolDomain</li>
<li>DeleteUserPool</li>
<li>DeleteUserPoolClient</li>
<li>DeleteUserPoolDomain</li>
<li>ForgotPassword</li>
<li>GetJwks</li>
<li>ListUserPools</li>
<li>InitiateAuth</li>
<li>RespondToAuthChallenge</li>
<li>VerifySoftwareToken</li>
</ul>
<h2 id="-fake"># Fake<a class="heading-link" href="#-fake" aria-label="Link to # Fake">#</a>
</h2>
<p>The Cognito Fake has very limited functionality for creating User Pools and User Pool Clients only.
It can act as an OAuthServer for created User Pool Clients. It supports the ClientCredentials and
Authorization Code grants and returns JWTs which have been signed with a private key. The matching public key can be
retrieved from the following endpoint:</p></description></item><item><title>AWS: Container Credentials</title><link>https://http4k.org/ecosystem/connect/reference/amazon/containercredentials/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/ecosystem/connect/reference/amazon/containercredentials/</guid><description><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-kotlin" data-lang="kotlin"><span style="display:flex;"><span>dependencies {
</span></span><span style="display:flex;"><span>
implementation(platform("org.http4k:http4k-bom:6.40.1.0"))
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-connect-amazon-containercredentials&#34;</span>)
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-connect-amazon-containercredentials-fake&#34;</span>)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The Container Credentials connector provides the following Actions:</p>
<pre><code> * GetCredentials
</code></pre>
<p>The client APIs utilise the <code>http4k-platform-aws</code> module for request signing, which means no dependencies on the incredibly fat
Amazon-SDK JARs. This means this integration is perfect for running Serverless Lambdas where binary size is a
performance factor.</p></description></item><item><title>AWS: DynamoDb</title><link>https://http4k.org/ecosystem/connect/reference/amazon/dynamodb/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/ecosystem/connect/reference/amazon/dynamodb/</guid><description><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-kotlin" data-lang="kotlin"><span style="display:flex;"><span>dependencies {
</span></span><span style="display:flex;"><span>
implementation(platform("org.http4k:http4k-bom:6.40.1.0"))
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-connect-amazon-dynamodb&#34;</span>)
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-connect-amazon-dynamodb-fake&#34;</span>)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The DynamoDb connector provides the following Actions:</p>
<pre><code>* CreateTable
* DeleteTable
* DescribeTable
* ListTables
* UpdateTable
* DeleteItem
* GetItem
* PutItem
* Query
* Scan
* UpdateItem
* TransactGetItems
* TransactWriteItems
* BatchGetItem
* BatchWriteItem
* ExecuteTransaction
* ExecuteStatement
* BatchExecuteStatement
</code></pre>
<p>Note that the FakeDynamo supports the majority of the Dynamo operations with the following exceptions. You can use <a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html">DynamoDB</a> local instead to provide these functions:</p></description></item><item><title>AWS: EventBridge</title><link>https://http4k.org/ecosystem/connect/reference/amazon/eventbridge/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/ecosystem/connect/reference/amazon/eventbridge/</guid><description><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-kotlin" data-lang="kotlin"><span style="display:flex;"><span>dependencies {
</span></span><span style="display:flex;"><span>
implementation(platform("org.http4k:http4k-bom:6.40.1.0"))
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-connect-amazon-eventbridge&#34;</span>)
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-connect-amazon-eventbridge-fake&#34;</span>)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The EventBridge connector provides the following Actions:
* CreateEventBus
* DeleteEventBus
* DescribeEventBus
* PutEvents</p></description></item><item><title>AWS: Firehose</title><link>https://http4k.org/ecosystem/connect/reference/amazon/firehose/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/ecosystem/connect/reference/amazon/firehose/</guid><description><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-kotlin" data-lang="kotlin"><span style="display:flex;"><span>dependencies {
</span></span><span style="display:flex;"><span>
implementation(platform("org.http4k:http4k-bom:6.40.1.0"))
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-connect-amazon-firehose&#34;</span>)
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-connect-amazon-firehose-fake&#34;</span>)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The Firehose connector provides the following Actions:
* CreateDeliveryStream
* DeleteDeliveryStream
* ListDeliveryStreams
* PutRecord
* PutRecordBatch</p></description></item><item><title>AWS: IAM Identity Center</title><link>https://http4k.org/ecosystem/connect/reference/amazon/iamidentitycenter/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/ecosystem/connect/reference/amazon/iamidentitycenter/</guid><description><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-kotlin" data-lang="kotlin"><span style="display:flex;"><span>dependencies {
</span></span><span style="display:flex;"><span>
implementation(platform("org.http4k:http4k-bom:6.40.1.0"))
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-connect-amazon-iamidentitycenter&#34;</span>)
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-connect-amazon-iamidentitycenter-fake&#34;</span>)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The IAMIdentityCenter connector provides the following Fakes:</p>
<h2 id="oidc">OIDC<a class="heading-link" href="#oidc" aria-label="Link to OIDC">#</a>
</h2>
<p>Actions:</p></description></item><item><title>AWS: Instance Metadata Service</title><link>https://http4k.org/ecosystem/connect/reference/amazon/instancemetadata/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://http4k.org/ecosystem/connect/reference/amazon/instancemetadata/</guid><description><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-kotlin" data-lang="kotlin"><span style="display:flex;"><span>dependencies {
</span></span><span style="display:flex;"><span>
implementation(platform("org.http4k:http4k-bom:6.40.1.0"))
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-connect-amazon-instancemetadata&#34;</span>)
</span></span><span style="display:flex;"><span> implementation(<span style="color:#e6db74">&#34;org.http4k:http4k-connect-amazon-instancemetadata-fake&#34;</span>)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The <a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html">Instance Metadata Service</a> V1 connector provides the following Actions:</p>
<pre><code> * GetAmiId
* GetHostName
* GetInstanceIdentityDocument
* GetInstanceType
* GetLocalHostName
* GetLocalIpv4
* GetPublicHostName
* GetPublicIpv4
* GetSecurityCredentials
* ListSecurityCredentials
</code></pre>
<h3 id="example-usage">Example usage<a class="heading-link" href="#example-usage" aria-label="Link to Example usage">#</a>
</h3>
<div class="code-example">
<div class="code-example-header">
<span class="code-example-lang">Kotlin</span>
<span class="code-example-file">example.kt</span>
</div>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-kotlin" data-lang="kotlin"><span style="display:flex;"><span><span style="color:#66d9ef">package</span> content.ecosystem.connect.reference.amazon.instancemetadata
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.client.JavaHttpClient
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.connect.amazon.instancemetadata.FakeInstanceMetadataService
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.connect.amazon.instancemetadata.Http
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.connect.amazon.instancemetadata.InstanceMetadataService
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.connect.amazon.instancemetadata.getInstanceIdentityDocument
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.connect.amazon.instancemetadata.getLocalIpv4
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.core.HttpHandler
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> org.http4k.filter.debug
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#66d9ef">val</span> USE_REAL_CLIENT = <span style="color:#66d9ef">false</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fun</span> <span style="color:#a6e22e">main</span>() {
</span></span><span style="display:flex;"><span> <span style="color:#75715e">// we can connect to the real service or the fake (drop in replacement)
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#66d9ef">val</span> http: HttpHandler = <span style="color:#66d9ef">if</span> (USE_REAL_CLIENT) JavaHttpClient() <span style="color:#66d9ef">else</span> FakeInstanceMetadataService()
</span></span><span style="display:flex;"><span>