-
Notifications
You must be signed in to change notification settings - Fork 0
/
comparison.html
310 lines (298 loc) · 18.3 KB
/
comparison.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="description" content="manual">
<meta name="generator" content="Paradox, paradox-material-theme=0.6.0, mkdocs-material=3.0.3">
<meta name="lang:clipboard.copy" content="Copy to clipboard">
<meta name="lang:clipboard.copied" content="Copied to clipboard">
<meta name="lang:search.language" content="">
<meta name="lang:search.pipeline.stopwords" content="true">
<meta name="lang:search.pipeline.trimmer" content="true">
<meta name="lang:search.result.none" content="No matching documents">
<meta name="lang:search.result.one" content="1 matching document">
<meta name="lang:search.result.other" content="# matching documents">
<meta name="lang:search.tokenizer" content="[\s\-]+">
<meta name="description" content="manual">
<link rel="shortcut icon" href="assets/images/favicon.png">
<title>Comparison with similar tools · endpoints4s</title>
<link rel="stylesheet" href="assets/stylesheets/application.451f80e5.css">
<link rel="stylesheet" href="lib/material__tabs/dist/mdc.tabs.min.css">
<link rel="stylesheet" href="lib/prettify/prettify.css">
<script src="assets/javascripts/modernizr.1aa3b519.js"></script>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,400i,700|Roboto+Mono">
<style>
body,input{font-family:"Roboto","Helvetica Neue",Helvetica,Arial,sans-serif}
code,kbd,pre{font-family:"Roboto Mono","Courier New",Courier,monospace}
</style>
<link rel="stylesheet" href="assets/fonts/font-awesome.css">
<link rel="stylesheet" href="assets/fonts/material-icons.css">
<link rel="stylesheet" href="assets/stylesheets/paradox-material-theme.css">
<link rel="stylesheet" href="snippets.css">
</head>
<body
>
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" data-md-component="overlay" for="__drawer"></label>
<header class="md-header" data-md-component="header">
<nav class="md-header-nav md-grid">
<div class="md-flex">
<div class="md-flex__cell md-flex__cell--shrink">
<a href="index.html" title="endpoints4s" class="md-header-nav__button md-logo">
<i class="md-icon">local_library</i>
</a>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--menu md-header-nav__button" for="__drawer"></label>
</div>
<div class="md-flex__cell md-flex__cell--stretch">
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
<span class="md-header-nav__topic">
endpoints4s
</span>
<span class="md-header-nav__topic">
Comparison with similar tools
</span>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="query" data-md-state="active">
<label class="md-icon md-search__icon" for="__search"></label>
<button type="reset" class="md-icon md-search__icon" data-md-component="reset" tabindex="-1"></button>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="result">
<div class="md-search-result__meta">
Type to start searching
</div>
<ol class="md-search-result__list"></ol>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<div class="md-header-nav__source">
<a href="https://github.com/endpoints4s/endpoints4s"
title="Go to repository"
class="md-source"
data-md-source="github">
<div class="md-source__icon">
<i class="fa fa-github"></i>
</div>
<div class="md-source__repository">
endpoints4s/endpoints4s
</div>
</a>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container">
<main class="md-main">
<div class="md-main__inner md-grid" data-md-component="container">
<div class="md-sidebar md-sidebar--primary" data-md-component="navigation">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" data-md-level="0" style="visibility: hidden">
<label class="md-nav__title md-nav__title--site" for="drawer">
<a href="index.html" title="endpoints4s" class="md-nav__button md-logo">
<span class="md-nav__button md-logo">
<i class="md-icon">local_library</i>
</a>
<a href="index.html" title="endpoints4s">
endpoints4s
</a>
</label>
<div class="md-nav__source">
<a href="https://github.com/endpoints4s/endpoints4s"
title="Go to repository"
class="md-source"
data-md-source="github">
<div class="md-source__icon">
<i class="fa fa-github"></i>
</div>
<div class="md-source__repository">
endpoints4s/endpoints4s
</div>
</a>
</div>
<ul>
<li><a href="use-cases.html" class="page">Use Cases</a></li>
<li><a href="quick-start.html" class="page">Quick start</a></li>
<li><a href="design.html" class="page">Design in a nutshell</a></li>
<li><a href="algebras-and-interpreters.html" class="page">Algebras and interpreters</a>
<ul>
<li><a href="algebras/endpoints.html" class="page"><code>Endpoints</code></a></li>
<li><a href="algebras/json-entities.html" class="page">JSON Entities</a></li>
<li><a href="algebras/json-schemas.html" class="page">JSON Schemas</a></li>
<li><a href="algebras/chunked-entities.html" class="page">Chunked Entities</a></li>
<li><a href="algebras/middlewares.html" class="page">Middlewares</a></li>
<li><a href="algebras/assets.html" class="page">Assets</a></li>
<li><a href="algebras/mux-endpoints.html" class="page">Multiplexed Endpoints</a></li>
<li><a href="interpreters/pekko-http.html" class="page">Pekko HTTP</a></li>
<li><a href="interpreters/http4s.html" class="page">http4s</a></li>
<li><a href="interpreters/scalajs-web-fetch.html" class="page">Scala.js web client (Fetch)</a></li>
<li><a href="interpreters/sttp.html" class="page">sttp</a></li>
<li><a href="interpreters/openapi.html" class="page">OpenAPI</a></li>
<li><a href="interpreters/circe.html" class="page">Circe</a></li>
<li><a href="interpreters/play-json.html" class="page">Play JSON</a></li>
</ul></li>
<li><a href="guides.html" class="page">Guides</a>
<ul>
<li><a href="guides/tupler.html" class="page"><code>Tupler</code></a></li>
<li><a href="guides/custom-authentication.html" class="page">Application-specific authentication</a></li>
</ul></li>
<li><a href="community.html" class="page">Community</a></li>
<li><a href="comparison.html" class="active page">Comparison with similar tools</a></li>
<li><a href="talks.html" class="page">Talks and Articles</a></li>
<li><a href="release-and-compatibility-notes.html" class="page">Release and Compatibility Notes</a></li>
</ul>
<nav class="md-nav md-nav--secondary">
<label class="md-nav__title" for="__toc">Table of contents</label>
<ul>
<li><a href="comparison.html#comparison-with-similar-tools" class="header">Comparison with similar tools</a>
<ul>
<li><a href="comparison.html#autowire-remotely-lagom-mu" class="header">Autowire / Remotely / Lagom / Mu</a></li>
<li><a href="comparison.html#swagger-thrift-grpc" class="header">Swagger / Thrift / gRPC</a></li>
<li><a href="comparison.html#rho-fintrospect-tapir" class="header">Rho / Fintrospect / tapir</a></li>
<li><a href="comparison.html#servant-typedapi-typed-schema" class="header">Servant / typedapi / typed-schema</a></li>
</ul></li>
</ul>
</nav>
</nav>
<ul style="display: none">
<li class="md-nav__item md-version" id="project.version">
<label class="md-nav__link" for="__version">
<i class="md-icon" title="Version">label_outline</i> 1.12.1
</label>
</li>
</ul>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="toc">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary">
<label class="md-nav__title" for="__toc">Table of contents</label>
<ul>
<li><a href="comparison.html#comparison-with-similar-tools" class="header">Comparison with similar tools</a>
<ul>
<li><a href="comparison.html#autowire-remotely-lagom-mu" class="header">Autowire / Remotely / Lagom / Mu</a></li>
<li><a href="comparison.html#swagger-thrift-grpc" class="header">Swagger / Thrift / gRPC</a></li>
<li><a href="comparison.html#rho-fintrospect-tapir" class="header">Rho / Fintrospect / tapir</a></li>
<li><a href="comparison.html#servant-typedapi-typed-schema" class="header">Servant / typedapi / typed-schema</a></li>
</ul></li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content">
<article class="md-content__inner md-typeset">
<div class="md-content__searchable">
<h1><a href="#comparison-with-similar-tools" name="comparison-with-similar-tools" class="anchor"><span class="anchor-link"></span></a>Comparison with similar tools</h1>
<p>In this page, we compare endpoints4s with alternative tools that solve the same problem. We highlights their differences and explain the motivation behind our design decisions.</p>
<h2><a href="#autowire-remotely-lagom-mu" name="autowire-remotely-lagom-mu" class="anchor"><span class="anchor-link"></span></a>Autowire / Remotely / Lagom / Mu</h2>
<p><a href="https://github.com/lihaoyi/autowire">Autowire</a>, and <a href="http://verizon.github.io/remotely">Remotely</a>, and <a href="https://github.com/higherkindness/mu">Mu</a> are Scala libraries automating remote procedure calls between a server and a client. <a href="https://www.lagomframework.com/">Lagom</a> is a framework for implementing microservices.</p>
<p>The main difference with endpoints4s is that these tools are based on macros synthesizing the client according to the interface (defined as a Scala trait) of the server. By contrast, endpoints4s uses no macros.</p>
<p>We chose not to rely on macros because we find that they make it harder to reason about the code (since they synthesize code that is not seen by the developer), they may not be well supported by IDEs, and they seem to require a significant effort to support all edge cases (several issues have been reported about macro expansion: <a href="https://goo.gl/Spco7u">https://goo.gl/Spco7u</a>, <a href="https://goo.gl/F2E5Ev">https://goo.gl/F2E5Ev</a> and <a href="https://goo.gl/LCmVr8">https://goo.gl/LCmVr8</a>).</p>
<p>A more fundamental difference is that in Autowire and Remotely, the underlying HTTP communication is viewed as an implementation detail, and all remote calls are multiplexed through a single HTTP endpoint. In contrast, the goal of endpoints4s is to embrace the features of the HTTP protocol (content negotiation, authorization, semantic verbs and status codes, etc.), so, in general, one HTTP endpoint is used for one remote call (though the library also supports multiplexing in case users don’t care about the underlying HTTP protocol).</p>
<p>Last but not least, Autowire, Remotely, Mu, and Lagom can not generate documentation of the communication protocol.</p>
<h2><a href="#swagger-thrift-grpc" name="swagger-thrift-grpc" class="anchor"><span class="anchor-link"></span></a>Swagger / Thrift / gRPC</h2>
<p>Solutions such as Swagger, Thrift, and gRPC generate the client and server code based on a protocol description written in a custom language, whereas in endpoints4s descriptions are written in plain Scala and producing a client or a server doesn’t require generating code.</p>
<p>These custom languages have the benefit of being very clear about their domain, but they generally lack of means of abstraction (no way to factor out similar parts of endpoint descriptions) or means of computing (no expression evaluation, no control structures, etc.). With endpoints4s, developers can easily write a function returning an endpoint description according to some specific logic and given some parameters.</p>
<p>Tools based on code generators have the benefit that they can be integrated with virtually any stack (Scala, Rust, etc.). However, we find that they also have some drawbacks. First, they require users to set up an additional step in their build, ensuring that the code is generated before compiling the modules that use it, and that each time the source files are modified the code is re-generated. Our experience with code generators also showed that sometimes the generated code does not compile. In such a case, it may be difficult to identify the origin of the problem because the error is reported on the generated code, not on the code written by the developer. Furthermore, sometimes the generated code is not convenient to use as it stands, and developers maintain another layer of abstraction on top of it. By not relying on code generation, endpoints4s eliminates these potential problems.</p>
<p>You can find a more elaborated article about the limitations of approaches based on code generation in <a href="http://julien.richard-foy.fr/blog/2016/01/24/my-problem-with-code-generation/">this blog post</a>.</p>
<h2><a href="#rho-fintrospect-tapir" name="rho-fintrospect-tapir" class="anchor"><span class="anchor-link"></span></a>Rho / Fintrospect / tapir</h2>
<p><a href="http://fintrospect.io/">Fintrospect</a>, <a href="https://github.com/http4s/rho">Rho</a>, and <a href="https://github.com/softwaremill/tapir">tapir</a> projects are comparable alternatives to endpoints4s. Their features and usage are similar: users describe their communication protocol in plain Scala and the library produces clients (Fintrospect and tapir only), servers and documentation.</p>
<p>A key difference is that in these projects the endpoints description language is defined as a sealed AST: users can not extend descriptions with application-specific concerns and interpreters can not be partial. We can illustrate that point with Web Sockets, a feature that is not be supported by all clients and servers. For instance, Play-WS does not support Web Sockets. This means that a Web Socket endpoint description can not be interpreted by a Play-WS based client. There are two ways to inform the user about such an incompatibility: either by showing a compilation error, or by throwing a runtime exception. In endpoints4s, interpreters can partially support the description language, resulting in a compilation error if one tries to apply an interpreter that is not powerful enough to interpret a given endpoint description. By contrast, if the description language is a sealed AST then all interpreters have to be total, otherwise a <code>MatchError</code> will be thrown at runtime.</p>
<p>That being said, a drawback of having an extensible description language is that users have to “build” their language by combining different modules together (eg, <code>Endpoints with JsonEntitiesFromSchemas</code>), and then build matching interpreters. These steps are not needed with projects where the description language is based on a sealed AST.</p>
<h2><a href="#servant-typedapi-typed-schema" name="servant-typedapi-typed-schema" class="anchor"><span class="anchor-link"></span></a>Servant / typedapi / typed-schema</h2>
<p><a href="https://haskell-servant.github.io/">Servant</a> is a Haskell library that uses generic programming to derive client, server and documentation from endpoint descriptions. <a href="https://github.com/pheymann/typedapi">typedapi</a> and <a href="https://github.com/TinkoffCreditSystems/typed-schema">typed-schema</a> are similar projects written in Scala. In these projects, both descriptions and interpreters are extensible. The difference with endpoints4s is that descriptions are <strong>types</strong>, whereas in endpoints4s they are <strong>values</strong>.</p>
<p>Using types as descriptions has some benefits: they can directly be used to type instances of data (in contrast, in endpoints4s descriptions of data types have to mirror a corresponding type definition). On the other hand, we believe that abstracting and combining types using type-level computations is, in general, less convenient for users.</p>
</div>
<div>
<a href="https://github.com/endpoints4s/endpoints4s/tree/master/documentation/manual/src/main/paradox/comparison.md" title="Edit this page" class="md-source-file md-edit">
Edit this page
</a>
</div>
<div class="print-only">
<span class="md-source-file md-version">
1.12.1
</span>
</div>
</article>
</div>
</div>
</main>
<footer class="md-footer">
<div class="md-footer-nav">
<nav class="md-footer-nav__inner md-grid">
<a href="community.html" title="Community" class="md-flex md-footer-nav__link md-footer-nav__link--prev" rel="prev">
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-back md-footer-nav__button"></i>
</div>
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Previous
</span>
Community
</span>
</div>
</a>
<a href="talks.html" title="Talks and Articles" class="md-flex md-footer-nav__link md-footer-nav__link--next" rel="next">
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Next
</span>
Talks and Articles
</span>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-forward md-footer-nav__button"></i>
</div>
</a>
</nav>
</div>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-footer-copyright">
Powered by
<a href="https://github.com/lightbend/paradox">Paradox</a>
and
<a href="https://jonas.github.io/paradox-material-theme/">Paradox Material Theme</a>
</div>
<div class="md-footer-social">
<a href="https://github.com/endpoints4s/endpoints4s" class="md-footer-social__link fa fa-github"></a>
</div>
</div>
</div>
</footer>
</div>
<script src="assets/javascripts/application.583bbe55.js"></script>
<script src="assets/javascripts/paradox-material-theme.js"></script>
<script>app.initialize({version:"0.17",url:{base:"."}})</script>
<script type="text/javascript" src="lib/prettify/prettify.js"></script>
<script type="text/javascript" src="lib/prettify/lang-scala.js"></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
window.prettyPrint && prettyPrint();
});
</script>
</body>
</html>