-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
1496 lines (1249 loc) · 78 KB
/
index.html
File metadata and controls
1496 lines (1249 loc) · 78 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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<!-- BEGIN Info -->
<meta
name="description"
content="Nexus is an open-source GraphQL framework that generates an instant GraphQL server from a user's existing data sources and automates deployment to AWS."
/>
<meta name="title" property="og:title" content="Nexus" />
<meta property="og:type" content="Website" />
<meta name="image" property="og:image" content="assets/nexus-logo.png" />
<meta
name="description"
property="og:description"
content="Nexus - Nexus is an open-source GraphQL framework that generates an instant GraphQL server from a user's existing data sources and automates deployment to AWS."
/>
<meta name="author" content="Nexus" />
<!-- END Info -->
<!-- BEGIN favicon -->
<link
rel="apple-touch-icon"
sizes="180x180"
href="assets/favicon/apple-touch-icon.png"
/>
<link
rel="mask-icon"
href="assets/favicon/safari-pinned-tab.svg"
color="#5bbad5"
/>
<link rel="shortcut icon" href="assets/favicon/favicon.ico" />
<meta name="msapplication-TileColor" content="#ffffff" />
<meta
name="msapplication-config"
content="images/favicon/browserconfig.xml"
/>
<meta name="theme-color" content="#ffffff" />
<!-- END favicon -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Nexus</title>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/@tailwindcss/typography@0.2.x/dist/typography.min.css"
/>
<link rel="stylesheet" href="stylesheets/reset.css" />
<link rel="stylesheet" href="stylesheets/style.css" />
<link rel="stylesheet" href="stylesheets/responsive.css" />
</head>
<body>
<header class="mobile-menu-closed">
<div id="header">
<a href="./index.html">
<img src="assets/logo/main-logo.png" />
</a>
<nav>
<a href="#start-here" class="selected">Overview</a>
<a href="#case-study">Case Study</a>
<a href="#presentation">Presentation</a>
<a href="#our-team">The Team</a>
<a
href="https://github.com/nexus-graphql/nexus-cli"
target="_blank"
class="icon"
><i class="fab fa-github"></i
></a>
</nav>
<div id="menu">
<button type="button">
<svg
id="mobile-open"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M4 6h16M4 12h16M4 18h16"
/>
</svg>
<svg
id="mobile-close"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
</div>
</div>
<div id="header-buffer"></div>
<div id="mobile-menu">
<a href="#start-here" class="selected">Overview</a>
<a href="#case-study">Case Study</a>
<a href="#presentation">Presentation</a>
<a href="#our-team">Our Team</a>
<a href="https://github.com/nexus-graphql" target="_blank"
><i class="fab fa-github"></i></a>
</div>
</header>
<div id="start-here" class="main-section">
<div class="h-full">
<div class="static-logo-color"></div>
<div class="">
<img
class="nexus sm-screen"
src="assets/logo/nexus-logo.png"
/>
<img class="nexus lg-screen" src="assets/logo/nexus-name.png" />
<p class="light-text">
An open-source framework that<br />generates an instant
<span class="text-pink">GraphQL server</span><br /> from
<span class="text-blue">multiple data sources</span><br />
</p>
</div>
</div>
<div class="h-full">
<div class="bg-dark-blue static-logo-blue">
<h2>Instant GraphQL Server</h2>
</div>
<div class="bg-dark-blue">
<h2 class="sm-header">Instant GraphQL Server from Nexus</h2>
<p>A GraphQL server will be automatically generated from a user's existing Postgres database</p>
<img class="nexus lg-screen" src="assets/media/images/server.png" />
</div>
</div>
<div class="h-full">
<div class="bg-pink static-logo-white">
<h2>Test The Server Locally</h2>
</div>
<div class="bg-pink">
<h2 class="sm-header">Test The Server Locally</h2>
<p>
Test the generated GraphQL server locally with an integrated graphical interface
</p>
<img src="assets/media/images/graphical.png"/>
</div>
</div>
<div class="h-full">
<div class="bg-dark-blue static-logo-blue">
<h2>Easy to Deploy</h2>
</div>
<div class="bg-dark-blue">
<h2 class="sm-header">Easy to Deploy</h2>
<p>
Use Nexus's CLI to deploy all the necessary infrastructure
to Amazon Web Services (AWS) with a single command</p>
<img src="assets/media/images/architecture.png"/>
</div>
</div>
</div>
<aside id="toc">
<!-- Case Study <br /><br /> -->
<ul>
<!-- Section 1 -->
<li data-section="section-1" class="selected">
<a href="#section-1">
<div>
<div class="bullet"><div></div></div>
<p>1. What is Nexus?</p>
</div>
</a>
</li>
<!-- Section 2 -->
<li data-section="section-2">
<a href="#section-2">
<div>
<div class="bullet"><div></div></div>
<p>2. APIs</p>
</div>
</a>
</li>
<li data-section="section-2" class="subitem">
<a href="#section-2-1">
<div>
<div class="bullet"><div></div></div>
<p>2.1 REST</p>
</div>
</a>
</li>
<li data-section="section-2" class="subitem">
<a href="#section-2-2">
<div>
<div class="bullet"><div></div></div>
<p>2.2 Under-fetching and Over-fetching Data</p>
</div>
</a>
</li>
<li data-section="section-2" class="subitem">
<a href="#section-2-3">
<div>
<div class="bullet"><div></div></div>
<p>2.3 Adapting an API</p>
</div>
</a>
</li>
<!-- Section 3 -->
<li data-section="section-3">
<a href="#section-3">
<div>
<div class="bullet"><div></div></div>
<p>3. GraphQL</p>
</div>
</a>
</li>
<li data-section="section-3" class="subitem">
<a href="#section-3-1">
<div>
<div class="bullet"><div></div></div>
<p>3.1 GraphQL Implementation Challenges</p>
</div>
</a>
</li>
<li data-section="section-3" class="subitem">
<a href="#section-3-2">
<div>
<div class="bullet"><div></div></div>
<p>3.2 Server Components</p>
</div>
</a>
</li>
<li data-section="section-3" class="subitem">
<a href="#section-3-3">
<div>
<div class="bullet"><div></div></div>
<p>3.3 Schema Writing Approaches</p>
</div>
</a>
</li>
<li data-section="section-3" class="subitem">
<a href="#section-3-4">
<div>
<div class="bullet"><div></div></div>
<p>3.4 Deployment</p>
</div>
</a>
</li>
<!-- Section 4 -->
<li data-section="section-4">
<a href="#section-4">
<div>
<div class="bullet"><div></div></div>
<p>4. Existing Solutions</p>
</div>
</a>
</li>
<li data-section="section-4" class="subitem">
<a href="#section-4-1">
<div>
<div class="bullet"><div></div></div>
<p>4.1 Managed Cloud Services</p>
</div>
</a>
</li>
<li data-section="section-4" class="subitem">
<a href="#section-4-2">
<div>
<div class="bullet"><div></div></div>
<p>4.2 Open Source Libraries</p>
</div>
</a>
</li>
<li data-section="section-4" class="subitem">
<a href="#section-4-3">
<div>
<div class="bullet"><div></div></div>
<p>4.3 Nexus</p>
</div>
</a>
</li>
<!-- Section 5 -->
<li data-section="section-5">
<a href="#section-5">
<div>
<div class="bullet"><div></div></div>
<p>5. Nexus Walkthrough</p>
</div>
</a>
</li>
<li data-section="section-5" class="subitem">
<a href="#section-5-1">
<div>
<div class="bullet"><div></div></div>
<p>5.1 Download and Setup</p>
</div>
</a>
</li>
<li data-section="section-5" class="subitem">
<a href="#section-5-2">
<div>
<div class="bullet"><div></div></div>
<p>5.2 Initializing GraphQL API Server</p>
</div>
</a>
</li>
<li data-section="section-5" class="subitem">
<a href="#section-5-3">
<div>
<div class="bullet"><div></div></div>
<p>5.3 Adding Other Data Sources</p>
</div>
</a>
</li>
<li data-section="section-5" class="subitem">
<a href="#section-5-4">
<div>
<div class="bullet"><div></div></div>
<p>5.4 Testing the Server</p>
</div>
</a>
</li>
<li data-section="section-5" class="subitem">
<a href="#section-5-5">
<div>
<div class="bullet"><div></div></div>
<p>5.5 Deployment</p>
</div>
</a>
</li>
<li data-section="section-5" class="subitem">
<a href="#section-5-6">
<div>
<div class="bullet"><div></div></div>
<p>5.6 Dashboard</p>
</div>
</a>
</li>
<li data-section="section-5" class="subitem">
<a href="#section-5-7">
<div>
<div class="bullet"><div></div></div>
<p>5.7 Destroy</p>
</div>
</a>
</li>
<!-- Section 6 -->
<li data-section="section-6">
<a href="#section-6">
<div>
<div class="bullet"><div></div></div>
<p>6. Nexus Architecture</p>
</div>
</a>
</li>
<li data-section="section-6" class="subitem">
<a href="#section-6-1">
<div>
<div class="bullet"><div></div></div>
<p>6.1 Generating the Server</p>
</div>
</a>
</li>
<li data-section="section-6" class="subitem">
<a href="#section-6-1-1">
<div>
<div class="bullet"><div></div></div>
<p>6.1.1 Initializing the Server and Integrating Data Sources</p>
</div>
</a>
</li>
<li data-section="section-6" class="subitem">
<a href="#section-6-2">
<div>
<div class="bullet"><div></div></div>
<p>6.2 Deploying the Server</p>
</div>
</a>
</li>
<li data-section="section-7">
<a href="#section-7">
<div>
<div class="bullet"><div></div></div>
<p>7. Nexus Implementation Challenges</p>
</div>
</a>
</li>
<li data-section="section-7" class="subitem">
<a href="#section-7-1">
<div>
<div class="bullet"><div></div></div>
<p>7.1 Connecting Multiple Data Sources</p>
</div>
</a>
</li>
<li data-section="section-7" class="subitem">
<a href="#section-7-2">
<div>
<div class="bullet"><div></div></div>
<p>7.2 Hot Reloading</p>
</div>
</a>
</li>
<li data-section="section-7" class="subitem">
<a href="#section-7-3">
<div>
<div class="bullet"><div></div></div>
<p>7.3 Time to Redeploy</p>
</div>
</a>
</li>
<!-- Section 8 -->
<li data-section="section-8">
<a href="#section-8">
<div>
<div class="bullet"><div></div></div>
<p>8. Future Work</p>
</div>
</a>
</li>
<li data-section="section-8" class="subitem">
<a href="#section-8-1">
<div>
<div class="bullet"><div></div></div>
<p>8.1 Customization of the GraphQL Schema</p>
</div>
</a>
</li>
<li data-section="section-8" class="subitem">
<a href="#section-8-2">
<div>
<div class="bullet"><div></div></div>
<p>8.2 Multi-Cloud Deployment</p>
</div>
</a>
</li>
<li data-section="section-8" class="subitem">
<a href="#section-8-3">
<div>
<div class="bullet"><div></div></div>
<p>8.3 Allowing Additional Data Sources</p>
</div>
</a>
</li>
</ul>
</aside>
<div id="case-study" class="main-section">
<div id="case-study-content">
<div class="prose">
<h1>Case Study</h1>
<!-- Section 1 -->
<h2 id="section-1">1. What is Nexus?</h2>
<figure>
<img src="assets/media/diagrams/1.png" class="case-study-image" />
<figcaption>Fig.1 - Nexus is an instant GraphQL API framework</figcaption>
</figure>
<p>
Nexus is an open-source framework that generates and deploys a GraphQL API from a user’s existing data sources. We simplify the user's setup by providing a CLI tool and admin dashboard. Data sources can be added, removed, and changed without writing any new code or schemas. Additionally, users can test the generated GraphQL API locally with an integrated graphical interface. This interface exposes the API’s documentation and serves as a playground for making test queries and viewing responses. Finally, when the API is ready to deploy, Nexus automates deployment to AWS.
</p>
<p>
In this case study, we will introduce APIs, GraphQL, and the challenges developers face when implementing GraphQL APIs. Furthermore, we discuss how and why Nexus was built and the features we hope to develop in the future. The main goal of Nexus was to efficiently deploy an auto-generated GraphQL server that connects to multiple data sources. Before diving deeper into Nexus, let’s discuss what an API is and how it can be used.
</p>
<!-- Section 2 -->
<h2 id="section-2" class="h2">2. APIs</h2>
<p>
An API, or Application Programming Interface, is a way to share data across different systems. This is similar to how a mouse, keyboard, or screen is used as an interface to transfer data between humans and computers. An API is a layer that standardizes and abstracts the inner workings of two separate systems, allowing them to communicate fluidly.
</p>
<figure>
<img src="assets/media/diagrams/2.png" class="case-study-image" />
<figcaption>Fig.2 - APIs are a way to share data across systems</figcaption>
</figure>
<p>
Web applications are commonly split into two major parts: the “frontend” and the “backend." These parts are decoupled to separate concerns. The frontend handles how a web page looks and user interaction with the page. In contrast, the backend accesses databases and handles business logic. The development workflow is optimized by decoupling, allowing separate languages, libraries, and frameworks to be used.
</p>
<p>
Once separated, the two parts need a common language to communicate with each other. An API serves as the link, allowing communication in a standardized format. Many API patterns and conventions specify how to build and design APIs for different needs. Many of them are endpoint-based, and the most common is REST.
</p>
<h3 id="section-2-1">2.1 REST</h3>
<p>
A RESTful API provides endpoints corresponding to the application's significant resources. REST utilizes the HTTP protocol to define actions that can be taken on those resources via HTTP methods. Following REST conventions, the API is standardized, typically allowing the user to infer an endpoint's intention. For example, sending a GET request to a <span class="code-snippet">/books</span> endpoint would send back information on all books, whereas a GET request to <span class="code-snippet">/books/:id</span> would send back information about a specific book.
</p>
<figure>
<img src="assets/media/diagrams/3.png" class="case-study-image" />
<figcaption>Fig.3 - Example of REST API endpoints</figcaption>
</figure>
<p>
REST has become the dominant pattern for building web application APIs. By some estimates, over 89% of APIs today follow REST conventions. One reason for its popularity is that REST is simple for developers to understand and build. It interacts well with other building blocks of web architecture, like the HTTP protocol. REST particularly shines in applications where client pages correspond directly with REST endpoints.
</p>
<figure>
<img src="assets/media/diagrams/4.png" class="case-study-image" />
</figure>
<p>
Although REST has many benefits, issues can arise when a new frontend use case is integrated with an existing REST API. Consider a hypothetical bookstore, a web application supported by a REST API. When a new mobile application is introduced, a few problems become more prevalent.
</p>
<h3 id="section-2-2">2.2 Under-fetching and Over-fetching Data</h3>
<p>
Due to a mobile device's limited screen size, fewer book details can be displayed on the catalog screen, and therefore less data is needed from the API to load this page. Figure 4 illustrates this difference in design between the desktop and mobile applications. Details such as publisher, publish date, and format are not part of the mobile application’s catalog page.
</p>
<figure>
<img src="assets/media/diagrams/5.png" class="case-study-image" />
<figcaption>Fig.4 - Each client type has different data needs.</figcaption>
</figure>
<p>
When the frontend developer fetches the data to display this page, they make a request to the pre-existing <span class="code-snippet">/books</span> endpoint designed for the desktop application. Since the REST API has not yet been adapted for this new use case, the current endpoint returns information that doesn’t fit the mobile application's data needs. This is known as over-fetching. Figure 5 shows the <span class="code-snippet">/books</span> endpoint’s response which has all the book information, but the mobile application doesn’t need all of that data.
</p>
<figure>
<img src="assets/media/diagrams/6.png" class="case-study-image" />
<figcaption>Fig.5 - Over-fetching data can lead to system performance issues.</figcaption>
</figure>
<p>
More data transferred in each request means longer wait times for the frontend to receive and process the data. Over-fetching can lead to a user experiencing higher response times, resulting in a slower page load. Sending too much data is especially problematic on mobile devices. Mobile networks have less bandwidth, which means slower data transfer. A typical page takes ~88% longer to load on mobile devices than on a desktop. This bookstore example is simplified; as applications scale, the user experience on a mobile device can degrade to the point where users may leave before the page loads.
</p>
<p>
Another part of the mobile application needs to load a cart page that lists which books a user has in their cart. Books and carts are represented by separate endpoints in the API, so the frontend developers must make multiple requests to fetch all the necessary information to load the cart. Since one endpoint doesn’t contain all the required data, they are “under-fetching.” Under-fetching can cause a “waterfall” effect of requests cascading to many more related requests, resulting in multiple round trips between the client and server.
</p>
<figure>
<img src="assets/media/diagrams/7.png" class="case-study-image" />
<figcaption>Fig.6 - Under-fetching data can lead to additional requests to complete a page.</figcaption>
</figure>
<p>
The time it takes for a request to be sent over the network from client to server and back is known as round-trip latency. While round-trip latency varies, it can take roughly 207ms on average. When under-fetching leads to additional unnecessary round-trips, the latency from the other requests can significantly increase page load time. Every five additional requests might lead to 1000ms of load time. Since many users will leave a page that is still loading after 10,000ms, even a handful of unnecessary requests can contribute to lost users.
</p>
<figure>
<img src="assets/media/diagrams/8.png" class="case-study-image" />
<figcaption>Fig.7 - Round-trip latency leads to longer page load times, especially for mobile clients</figcaption>
</figure>
<p>
Beyond application performance, over-fetching and under-fetching affect frontend developer productivity. When an API does not match their frontend client’s data needs well, developers must spend additional time orchestrating many requests and filtering unnecessary data. In some cases, dealing with data can take the majority of frontend development time, leaving little time to spend on building critical UI.
</p>
<figure>
<img src="assets/media/diagrams/9.png" class="case-study-image" />
</figure>
<h3 id="section-2-3">2.3 Adapting an API</h3>
<p>
Development teams faced with supporting multiple clients are not limited to using fixed endpoints that cause under-fetching and over-fetching. They can adapt their REST APIs to make them better fit each of their frontend use cases. Adding new endpoints, providing query parameters for customized requests, or versioning their API for each use case are a few options.
</p>
<figure>
<img src="assets/media/diagrams/10.png" class="case-study-image" />
<figcaption>Fig.8 - Adjusting & creating endpoints to accommodate new client use cases</figcaption>
</figure>
<p>
Introducing customization makes a REST API more flexible. However, these adaptations make it more complex and challenging to work with for API providers. In a recent survey by Postman, 51% of respondents reported over half of their organization’s development effort is dedicated to APIs. As the complexity grows, adapting the API can become a critical bottleneck, slowing the addition of future client use cases.
</p>
<figure>
<img src="assets/media/diagrams/11.png" class="case-study-image" />
</figure>
<p>
Creating and managing documentation can also take time away from the backend developer’s primary responsibilities. As the API changes and adaptations are made, the documentation becomes more challenging to maintain, requiring more time to keep up-to-date. This may not always be possible, which is why API documentation is often considered a “nice-to-have” on the priority list for providers. However, documentation is critical for API consumers, and poor or missing information about endpoints compounds the challenges faced by the frontend team.
</p>
<p>
While our hypothetical bookstore example is simplified for demonstration, in reality, the developers often need to interact with many APIs to fetch all the data they need. This means they deal with data access issues across multiple APIs and data sources, increasing the complexity and the time necessary to deal with it.
</p>
<p>
REST is widespread because it works well for applications where the API can be optimized for a use case, and data access patterns match the provided endpoints. While endpoints can be adapted in various ways to facilitate request customization, this comes at the cost of complexity and developer time. However, several vital factors may influence a team to re-consider how they structure an API:
</p>
<ul>
<li>Support is needed for frontend applications that have different bandwidth needs</li>
<li>Data access is nested, interrelated, recursive, or varies frequently</li>
<li>Data is distributed across multiple sources</li>
</ul>
<p>
A new API paradigm, GraphQL, emerged in 2015 as an option to create APIs that are highly customizable and flexible for such use cases.
</p>
<!-- Section 3 -->
<h2 id="section-3" class="h2">3. GraphQL</h2>
<p>
Unlike multi-endpoint APIs like REST, a GraphQL API exposes a single endpoint. This difference contributes to many of the benefits GraphQL can offer.
</p>
<figure>
<img src="assets/media/diagrams/12.png" class="case-study-image" />
<figcaption>Fig.9 - All client types query the same single endpoint</figcaption>
</figure>
<p>
With GraphQL, each frontend client uses a single endpoint to request the required data. To support fetching multiple resources for differing client types using the same endpoint, GraphQL introduces a query language that clients use to request the data. Client-side developers no longer need to keep track of many different endpoints and their different standards. Furthermore, API developers no longer need to add new endpoints, adapt their endpoints, or version them for different client types. By moving to one endpoint, both providers and clients can save time.
</p>
<figure>
<img src="assets/media/diagrams/13.png" class="case-study-image" />
<figcaption>Fig.10 - A query specifies the data, and the response matches the query structure</figcaption>
</figure>
<p>
Let’s return to the hypothetical bookstore example from above. Data was over-fetched because the information needed for the desktop application differed from the mobile application. How can GraphQL fix this? A GraphQL query specifies the data a client needs, and the response structure matches that query. Queries are customizable, and the same query can fetch multiple resources simultaneously. The response will contain precisely the information requested, no more, no less. This change helps the developers save time and reduces the amount of data sent over the wire.
</p>
<figure>
<img src="assets/media/diagrams/14.png" class="case-study-image" />
<figcaption>Fig.11 - Each client can specify the required data with custom queries</figcaption>
</figure>
<p>
We also saw how under-fetching could lead to round-trip latency. How can GraphQL help with this? A single query can fetch all the necessary data for the client, preventing cascading waterfall requests. Developers no longer have to wait for multiple requests to make round trips to the API server. It’s important to note there may still be multiple round trips needed to fetch data from various data sources. However, these can happen from API server to data source rather than from client to server.
</p>
<figure>
<img src="assets/media/diagrams/15.png" class="case-study-image" />
<figcaption>Fig.12 - Latency is reduced for clients and pushed to the GraphQL layer</figcaption>
</figure>
<p>
GraphQL APIs are self-documenting and can be quickly introspected to view available query options. As a result, API providers no longer have to create and maintain documentation, which can drastically help the provider save time and improve productivity.
</p>
<h3 id="section-3-1">3.1 GraphQL Implementation Challenges</h3>
<p>
While the frontend developers enjoy the benefits of a single endpoint, the responsibility for supporting a GraphQL API falls to the backend team.
</p>
<p>
Building a GraphQL API introduces new challenges and pitfalls for API developers. First, developers must get up to speed on the GraphQL specification and learn about the unique components that make up a GraphQL server. The learning curve can be steep because GraphQL differs significantly from REST. They’ll also need to decide on an approach to writing their schema and combining them. Each approach has its tradeoffs, which can complicate the decision and slow the setup process.
</p>
<p>
Secondly, the developer must deploy their new server so that frontend clients can query the API. They will need to decide which cloud services to utilize among the many options, provision and connect their chosen services, and deploy and manage that infrastructure.
</p>
<figure>
<img src="assets/media/diagrams/16.png" class="case-study-image" />
</figure>
<p>
Many steps go into building and deploying an initial GraphQL server, and this process can be time-consuming, tedious, and error-prone. The process of migrating from REST or adding a GraphQL layer to an existing application can take weeks or longer.
</p>
<p>
To understand the challenge that development teams face, let’s take a closer look at what it takes to build a GraphQL API connected to multiple data sources.
</p>
<h3 id="section-3-2">3.2 Server Components</h3>
<p>
The main components of a GraphQL server are the schema and resolvers. A GraphQL schema defines the data types that can be requested and the relationships between types. Resolvers are functions that retrieve the requested data specified in the schema.
</p>
<figure>
<img src="assets/media/diagrams/17.png" class="case-study-image" />
<figcaption>Fig.13 - Server responsibilities to support a single endpoint</figcaption>
</figure>
<p>
A GraphQL schema comprises type definitions, which describe a queryable type within the GraphQL API. Each type includes fields that define the properties of that type, and each field can be a base type, like String or Integer. To support the graph data structure of GraphQL, fields are also used to represent associations between types. For example, a type of “Book” may have a field “author” which corresponds to an “Author” type, thus associating those two types.
</p>
<figure>
<img src="assets/media/diagrams/18.png" class="case-study-image" />
</figure>
<p>
The default type <span class="code-snippet">Query</span> represents one entry point into the schema and actions that retrieve data. The <span class="code-snippet">Query</span> type contains fields that the GraphQL schema creator defines. The GraphQL specification also includes default types of <span class="code-snippet">Mutation</span> for adding or modifying data and <span class="code-snippet">Subscription</span> to support streaming data with GraphQL.
</p>
<figure>
<img src="assets/media/diagrams/19.png" class="case-study-image" />
</figure>
<p>
Resolvers are functions that can take a GraphQL query and respond with the appropriate data for each field in the query. They are defined by the developer and specify how the data for fields in the type definitions are retrieved.
</p>
<h3 id="section-3-3">3.3 Schema Writing Approaches</h3>
<p>
Before developers can create a schema, they may choose between two approaches for schema writing: schema-first or code-first. The schema-first approach utilizes the GraphQL Schema Definition Language or SDL for short. Using SDL allows the developer to define their schema in a programming language-agnostic way.
</p>
<p>
The SDL includes syntax for defining the types that form the GraphQL data model. A schema written using the SDL provides a holistic picture of the data and associations within an application.
</p>
<figure>
<img src="assets/media/diagrams/20.png" class="case-study-image" />
</figure>
<p>
Since the SDL is not tied to a specific programming language, the resulting schema outlines the data model without implementation details. In a schema-first approach, the schema and resolvers are written separately. Since resolvers define how data is retrieved, they must be written in the developer’s chosen programming language.
</p>
<p>
For a code-first approach, the process begins with writing types with resolvers directly in the desired programming language. For example, using the “graphql” library in Node.js, the developer can use imported JavaScript objects to create their type definitions with fields and corresponding resolvers. In this approach, the code serves as the schema, and an SDL version can be generated from the code using scripts.
</p>
<figure>
<img src="assets/media/diagrams/21.png" class="case-study-image" />
</figure>
<p>
Each approach has tradeoffs. The schema-first approach divides the type definitions and resolvers, separating concerns. The singular focus makes it easier to understand and quickly share the data model. However, it involves a new language, and the SDL-defined schema is not complete on its own. Additionally, the separation of resolvers can lead to duplication requiring more maintenance over time.
</p>
<p>
Unlike the schema-first approach, the code-first approach is self-contained, which means the entire schema is defined in one place. Consequently, the overall structure of the data model can be more challenging to understand in code form.
</p>
<p>
As multiple data sources are added, the complexity of a schema grows. Many teams will opt to modularize their schema, separating each data source into its own schema. They will then need a strategy to combine them into a unified schema if they want to maintain the benefits of a single endpoint. There are several ways for the developer to implement this, but each has its own tradeoffs to consider.
</p>
<figure>
<img src="assets/media/diagrams/22.png" class="case-study-image" />
</figure>
<p>
GraphQL’s Schema Definition Language, type definitions, resolvers, and schema writing approaches are fundamental to building a GraphQL API from scratch. While there are libraries to ease the process, it can still take weeks for developers brand new to GraphQL.
</p>
<h3 id="section-3-4">3.4 Deployment</h3>
<figure>
<img src="assets/media/diagrams/23.png" class="case-study-image" />
</figure>
<p>
We’ve discussed a few challenges developers face as they learn how to build a server in this new paradigm, but building the server is only half the battle. The developer still needs to deploy the server for the frontend team to make queries. This process can be complicated and involves many steps.
</p>
<p>
When deploying their server to the cloud, there are a variety of platforms a developer might choose. We focus on the most popular Amazon Web Services, also known as AWS.
</p>
<ul>
<li>IAM User Roles</li>
<li>VPC</li>
<li>Public Subnet in VPC</li>
<li>Security Group for Public Subnet</li>
<li>EC2 Instance in Public Subnet</li>
<li>Routing Table</li>
<li>Router</li>
<li>Internet Gateway
</li>
</ul>
<p>
Although this is a rudimentary infrastructure, it still has several resources to be provisioned. A developer must understand these resources and their related services when deploying an API from scratch.
</p>
<figure>
<img src="assets/media/diagrams/24.png" class="case-study-image" />
<figcaption>Fig.14 - AWS Services</figcaption>
</figure>
<p>
Currently, AWS offers 200+ services, with more added all the time. You can see an example of these services in figure 14. The sheer volume of services, plus their confusing names and acronyms, has inspired several “AWS in plain English” articles to be written that strive to explain what each service is used for and what it should have been called instead.
</p>
<p>
Once the developer learns what resources are needed, they must also make them work together. However, coordinating communication between resources can introduce bugs that take more work to troubleshoot, can be tedious for the developer, and increase the time spent getting a server running for clients to query.
</p>
<p>
Finding the right resources is only one hurdle the developer needs to overcome; they must also choose the right ones to support their architecture. This step can be complex and, if done improperly, can affect the performance of their application.
</p>
<p>
AWS provides a few different tools to assist the developer in provisioning resources. First is a graphical interface used to provision resources by hand. Next is a command line interface that can be used to provision resources by interacting with the API.
</p>
<figure>
<img src="assets/media/diagrams/25.png" class="case-study-image" />
<figcaption>Fig.15 - AWS CLI commands to provision a single EC2 instance</figcaption>
</figure>
<p>
Both of these tools strive to make provisioning convenient for the developer. However, they both involve dozens of sequential steps to provision and connect the different resources required. In figure 15, you can see an example of some commands that need to be run in the AWS CLI to provision a single EC2 instance. Although this is a simplified example, the documentation for EC2 alone offers 575 commands. This volume is what developers struggle with. Although having many options can be good, navigating them can also be challenging, especially for someone new to infrastructure.
</p>
<figure>
<img src="assets/media/diagrams/26.png" class="case-study-image" />
</figure>
<p>
In a small business or non-profit, the responsibility for managing the whole stack falls to a few developers or sometimes a single developer. The rise of mobile apps and the increasing prevalence of “smart” devices require building applications for various client types. The small team will be responsible for adding new frontend clients as needed and building the APIs to support those clients. In addition, as services are outsourced or otherwise distributed, they must deal with more internal and external data sources.
</p>
<p>
Large organizations can often afford to dedicate teams of developers to learn the GraphQL specification and implement their API in-house. Smaller organizations may decide early in their initial research that the complexity that GraphQL brings outweighs the benefits. Besides the performance benefits, the secondary goal of switching to GraphQL is to save developer time. If the time spent getting the API running is more than the time saved on the frontend, switching to GraphQL will not appear to be worth it.
</p>
<p>
Small teams can benefit from an alternative to building their own GraphQL API. As they explore the GraphQL ecosystem, they will find several existing solutions that can help make the process faster and easier.
</p>
<!-- Section 4 -->
<h2 id="section-4" class="h2">4. Existing Solutions</h2>
<p>
Given the considerable amount of time it takes to learn and implement a GraphQL API, an alternative approach that some teams may consider is using a tool that generates their API. We looked at several options that led us to develop Nexus as an alternative to the existing solutions.
</p>
<h3 id="section-4-1">4.1 Managed Cloud Services</h3>
<p>
At the highest level of abstraction are managed cloud services like Hasura and StepZen. These are GraphQL API generators that automatically create, manage, and deploy the server for the user.
</p>
<p>
With a managed service, setup can be done in just a few minutes, and previous knowledge of GraphQL isn’t required to get an API running. Most managed services support a wide variety of data sources and offer the ability to combine data sources into a unified GraphQL layer.
</p>
<p>
However, a managed service may only support some data sources, so developers must ensure the sources they currently use are supported. If they don’t, they will either have to switch to a service that supports their required data source or start over and build their server from scratch.
</p>
<figure>
<img src="assets/media/diagrams/27.png" class="case-study-image" />
</figure>
<p>
Deployment is also handled entirely by the service. Automated deployment is one of the primary benefits of using a managed service, but it has some tradeoffs. Outsourcing deployment results in a lack of control over the infrastructure that supports the API. There is also no opportunity to optimize the cost of that infrastructure.
</p>
<p>
As an added benefit, managed services typically offer a robust set of additional API optimization features, like caching, monitoring, and observability. If the developer needs these other features, they can incorporate them in a few clicks, making them reasonably simple to implement.
</p>
<p>
Managed services abstract much of the complexity away from the user, leading to speed and ease of setup. However, they trade off extendability and control.
</p>
<h3 id="section-4-2">4.2 Open Source Libraries</h3>
<p>
Developers who want additional control and extendability can use several open-source GraphQL API generator libraries, like WunderGraph or GraphQL Mesh.
</p>
<p>
Generator libraries help get developers started more quickly than writing GraphQL code from scratch. However, they still require manual setup and configuration, which often involves some basic GraphQL knowledge and library-specific syntax.
</p>
<figure>
<img src="assets/media/diagrams/28.png" class="case-study-image" />
</figure>
<p>
Generator libraries support a wide variety of data sources. Unlike managed services, they are also highly extendable because the developer can access the generated code. For data sources that aren’t supported, the developer can extend the schema manually or with plugins.
</p>
<p>
The ability to add data sources is only one of many ways the developer can extend their server. They can also utilize plugins to add more advanced features. If there isn’t a plugin for their needs, they can manually extend their code to fit their use case. Extensibility is one of the main benefits of using open-source libraries and why a developer may choose to use them.
</p>
<p>
Although generator libraries help create the server, they do not deploy the server for the developer once it is generated. Some libraries have documentation that may include basic deployment guides for different cloud providers and architectures, but they do not typically provide direct assistance with deployment. Without deployment assistance, developers fully control their infrastructure decisions and cost. Ultimately, this comes at the expense of the developer’s time and the deployment complexity we described previously.
</p>
<h3 id="section-4-3">4.3 Nexus</h3>
<p>
Nexus is a framework for quickly generating a GraphQL API from multiple data sources and deploying the API to a user’s AWS account. We wrap several open-source tools for API generation and deployment, speeding up the configuration and use of those tools. We built Nexus for teams who would like to build and deploy a simple GraphQL API in just a few minutes, with the option to extend it over time.
</p>
<p>
Nexus uses GraphQL Mesh, a powerful GraphQL API generator, to build the user’s server. We reduced the configuration of this open-source library to a few simple commands, so no experience with GraphQL or the Mesh library is needed to get started.
</p>
<figure>
<img src="assets/media/diagrams/29.png" class="case-study-image" />
</figure>
<p>
Nexus currently supports three data sources: Postgres, REST APIs, and GraphQL APIs. If a data source is not supported, the user can extend their API using Mesh’s collection of additional sources or manually extend the schema.
</p>
<p>
After the server is generated, Nexus deploys the GraphQL server with a single command. We simplify deployment by abstracting away infrastructure setup and making a few decisions for the user. The deployed infrastructure is then provisioned entirely in their AWS account and is fully modifiable by the user.
</p>
<p>
Although Nexus offers many beneficial features, we don’t provide advanced options for fine-tuning the API like managed services. As a result, users have some of the benefits of extendability and ownership that come with an open-source library, along with some of the deployment abstractions of a managed service, at the cost of advanced API features. However, users can add features as needed because the generated code lives on their local machine.
</p>
<!-- Section 5 -->
<h2 id="section-5" class="h2">5. Nexus Walkthrough</h2>
<h3 id="section-5-1">5.1 Download and Setup</h3>
<figure>
<img src="assets/media/diagrams/30.png" class="case-study-image" />
</figure>
<p>
Nexus is available as an NPM package. Global installation gives users access to all the commands and a local admin dashboard. Prerequisites and installation instructions are listed in the <a href="https://github.com/nexus-graphql/nexus-cli"> readme section of our GitHub repository</a>.
</p>
<figure>
<img src="assets/media/diagrams/31.gif" class="case-study-image" />
</figure>
<h3 id="section-5-2">5.2 Initializing GraphQL API Server</h3>
<p>
After installation, the user can initialize a new project with the <span class="code-snippet">init</span> command. They’ll run this in an empty project folder where we’ll generate their server files. We collect a Postgres database as the primary data source. To avoid confusing bugs when the server is generated, the Postgres connection string is validated for the user when they input it.
</p>
<figure>
<img src="assets/media/diagrams/32.png" class="case-study-image" />
</figure>
<p>
Behind the scenes, we install the necessary packages and create the configuration files to generate and run the GraphQL server in the user’s current working directory. They now have a basic GraphQL server built from their Postgres database with a single command.
</p>
<h3 id="section-5-3">5.3 Adding Other Data Sources</h3>
<p>
Adding a second data source is similar to adding the initial Postgres database. The <span class="code-snippet">nexus add</span> command will prompt the user for the data source type and then tailor subsequent prompts based on that source type. This command can add REST endpoints, a remote GraphQL API, or another Postgres database.
</p>
<figure>
<img src="assets/media/diagrams/33.png" class="case-study-image" />
</figure>
<p>
REST endpoints are included using a local path or remote URL to a JSON file that defines the user’s endpoints following the OpenAPI specification. Adding a GraphQL data source can be done by providing the URL of the API.
</p>
<h3 id="section-5-4">5.4 Testing the Server Locally</h3>
<p>
After the user initializes their server and adds one or more data sources, they can test their API locally by running the <span class="code-snippet">nexus dev</span> command. This opens a graphical interface for exploring the unified schema and making test queries. The test server supporting this interface is identical to the server that will be deployed, so it can be used to accurately pre-plan client queries.
</p>
<figure>
<img src="assets/media/diagrams/34.png" class="case-study-image" />
</figure>
<h3 id="section-5-5">5.5 Deployment</h3>
<p>
Nexus simplifies the deployment process down to a single command: <span class="code-snippet">nexus deploy</span>. This command handles all the complexity of packaging the server code and provisioning the infrastructure.
</p>
<figure>
<img src="assets/media/diagrams/35.gif" class="case-study-image" />