-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.html
1748 lines (1382 loc) · 81.3 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
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-US" prefix="og: http://opg.me/ns#">
<head>
<meta charset="UTF-8" />
<meta name="title" property="og:title" content="Satellite" />
<meta
name="description"
property="og:description"
content="Satellite is an open-source GraphQL Backend-as-a-Service that makes it easy to get a GraphQL API up and running to power the frontend of your dynamic web application."
/>
<meta name="type" property="og:type" content="website" />
<meta
name="url"
property="og:url"
content="https://satellite-baas.github.io/"
/>
<meta
name="image"
property="og:image"
content="images/logos/satellite-full.png"
/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta
name="author"
content="Will Baker, Ilyas Kussainov, Jordan Moore, Lewis Reynolds"
/>
<title>Satellite</title>
<link
rel="apple-touch-icon"
sizes="180x180"
href="/images/icons/favicons/apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="/images/icons/favicons/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="/images/icons/favicons/favicon-16x16.png"
/>
<link rel="manifest" href="/images/icons/favicons/site.webmanifest" />
<link
rel="mask-icon"
href="/images/icons/favicons/safari-pinned-tab.svg"
color="#5366f5"
/>
<link rel="shortcut icon" href="/images/icons/favicons/favicon.ico" />
<meta name="msapplication-TileColor" content="#da532c" />
<meta
name="msapplication-config"
content="/images/icons/favicons/browserconfig.xml"
/>
<meta name="theme-color" content="#ffffff" />
<!-- <style>reset</style> -->
<link rel="stylesheet" href="stylesheets/reset.css" />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/styles/gruvbox-dark.min.css"
charset="utf-8"
/>
<!-- <style></style> -->
<link rel="stylesheet" href="stylesheets/main.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/highlight.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- <script></script> -->
<script src="javascripts/application.js"></script>
<style></style>
</head>
<body>
<div class="logo-links">
<p id="satellite-logo">MENU</p>
<a href="https://github.com/satellite-baas" target="_blank">
<img
src="images/logos/github-black.png"
alt="github logo"
id="github-logo"
/>
</a>
</div>
<a id="toTop-link" href="#" target="_blank">
<img
src="images/logos/back-to-top.png"
alt="Back to top"
id="toTop-logo"
/>
</a>
<nav id="site-navigation">
<ul>
<li>
<a href="#home" id="home-link">HOME</a>
</li>
<li>
<a href="#case-study" id="case-study-link">CASE STUDY</a>
<nav id="case-study-mobile">
<ul></ul>
</nav>
</li>
<li>
<a href="#our-team" id="our-team-link">OUR TEAM</a>
</li>
</ul>
</nav>
<header id="home">
<h1>
<img
id="hero-logo"
src="images/logos/satellite-hero.png"
alt="Satellite logo"
/>
<p>A GraphQL Backend-as-a-Service for dynamic web applications</p>
</h1>
</header>
<section class="integration">
<div class="box">
<img
id="banner-deploy"
src="images/gifs/spin-up-satellite.gif"
alt="Satellite UI"
/>
</div>
<article class="box">
<div class="text-box">
<h3>Simple to use</h3>
<p>Create, manage and delete backends with the click of a button.</p>
</div>
</article>
</section>
<section class="integration">
<article class="box">
<div class="text-box">
<h3>Easy to configure</h3>
<p>Upload GraphQL schema and send GraphQL queries to your backend.</p>
</div>
</article>
<div class="box">
<img
id="banner-deploy"
src="images/gifs/add-data.gif"
alt="Satellite UI"
/>
</div>
</section>
<section class="integration">
<div class="box">
<img
id="banner-deploy"
src="images/gifs/setup.gif"
alt="Satellite setup process"
/>
</div>
<article class="box">
<div class="text-box">
<h3>Cloud native</h3>
<p>Deploy to any cloud provider using Kubernetes with just a few commands.</p>
<!-- <div id="cloud-logos">
<span>
<img src="images/logos/aws.png"/>
</span>
<span>
<img src="images/logos/gcp.png"/>
</span>
<span>
<img src="images/logos/azure.png"/>
</span>
</div>
</div> -->
</article>
</section>
<main>
<section id="case-study">
<h1>Case Study</h1>
<div id="side-nav">
<img src="images/logos/satellite-mark.png" alt="Satellite logo" />
</div>
<nav>
<ul></ul>
</nav>
<h2 id="what-is-satellite">1) What is Satellite?</h2>
<p>
Satellite is an open-source GraphQL backend-as-a-service (BaaS). It lets teams easily deploy and manage GraphQL backends for web applications.
</p>
<p>
Satellite abstracts away the complexity of building a GraphQL backend. It lets the application developer define their entire backend using only a single input - a GraphQL schema. Satellite's multi-instance architecture, based on Kubernetes, lets developers create and use as many backends as they need. Satellite is a great fit for new applications where ease of use and quick deployment are priorities.
</p>
<p>
In this case study, we'll describe both <em>why</em> and <em>how</em> we designed and built Satellite. Satellite was born from our desire to make setting up a GraphQL backend easier. We overcame many technical challenges to achieve this.
</p>
<p>
To explain Satellite's design, we'll first discuss the general architecture of a modern web application.
</p>
<h2 id="web-app-architecture">2) Web App Architecture</h2>
<h3 id="frontend-vs-backend">2.1) Frontend vs Backend</h3>
<p>
Web applications can be thought of as having two parts - the frontend and the backend. The frontend is what the user sees when using the application. It is responsible for an application's appearance and for handling user interactions. On the other side of an application is the backend. It handles the business logic and data persistence operations needed to power the frontend.
</p>
<div class="img-wrapper">
<img
src="images/diagrams/2_1-front-back.svg"
alt="The two parts of a web application."
/>
</div>
<p>
Modern applications often separate the backend from the frontend. This split architecture allows frontend and backend teams to work independently. It also allows development of different frontend client applications which use the same backend [<a href="#footnote-1">1</a>]. Given the advantages of this decoupled architecture, we need to think about how the frontend and backend communicate.
</p>
<h3 id="api-s-in-web-applications">
2.2) How do the Frontend and Backend Communicate?
</h3>
<p>
An API, or Application Programming Interface, provides a well-defined way for computer systems to interact with each other. There are many different types of APIs. They all provide some way for one system to access the functionality of another system. It makes sense, then, for the frontend of a web application to communicate with the backend using an API [<a href="#footnote-2">2</a>]. An API that lets a frontend and backend communicate using HTTP is called a web API. In a web API, the backend server produces the API and the frontend client consumes it.
</p>
<div class="img-wrapper">
<img
src="images/diagrams/2_2-api-ex.svg"
alt="Frontend to backend communication with an API."
/>
</div>
<p>
There are many different ways to build a web API. The state-of-the-art for web APIs has evolved over the years, and API designers are always finding better solutions to the challenges they are facing.
</p>
<h3 id="facebook-s-news-feed-api">
2.3) Designing a Better API: Facebook's News Feed
</h3>
<p>
This story starts in 2011, when Facebook decided to completely re-write their iOS app. Previously, their mobile app had been a wrapper around the Facebook webpage. They determined they needed to create a new, native app to provide the kind of experience they wanted for their mobile users. Their design required the frontend to be separated from the backend, and for the two sides to communicate with an API. This was the first time Facebook had tried to develop an app like this. They soon had issues when trying to reuse the existing API for the News Feed feature [<a
href="#footnote-3"
>3</a
>].
</p>
<h4>2.3.1) Why the Existing API Didn't Work</h4>
<p>
For Facebook’s News Feed, it wasn’t as simple as retrieving a story and all the information for that story. Each story is interconnected, nested, and recursive. The existing APIs weren’t designed to allow developers to deliver a news feed-like experience on mobile. They didn’t have a hierarchical nature or let developers select the exact data they needed. They were, in fact, designed to return HTML back to a web browser.
</p>
<div class="img-wrapper">
<img
src="images/diagrams/2_3_1-facebook-api-1.svg"
alt="An inefficient API interaction."
/>
</div>
<p>
This meant that the client application would need to make several round-trips to the API to get the information it wanted. For example, it might have to first get one story, and from it determine what other stories it needed to request to complete the feed. Then it might keep repeating that process over and over until it got all the information it needed. Additionally, each response would contain a lot of data that wasn’t needed. These factors combined resulted in slow network performance for the new app.
</p>
<h4>2.3.2) Why Facebook Created GraphQL</h4>
<p>
At this point, it was clear to Facebook that they needed to design a better API for their News Feed to improve the mobile experience. A quote from Nick Schrock, one of the co-creators of this new API which is now called GraphQL, highlights their focus on frontend development:
</p>
<blockquote>
<i
>"We tried to design what we thought was the ideal API for frontend
developers, and then work backwards to the technology."</i
>
<br /><br />
- Nick Schrock, GraphQL co-creator
</blockquote>
<p>
A key feature of GraphQL let it power the mobile apps Facebook had envisioned: letting the frontend client request exactly the data it needs. This eliminates the issue of over-fetching and the need for multiple round trips. This is critical for mobile applications which have limited bandwidth and need fast response times.
</p>
<div class="img-wrapper">
<img
src="images/diagrams/2_3_2-facebook-api-2.svg"
alt="An API interaction with GraphQL."
/>
</div>
<p>
One other important aspect of a GraphQL API is that it uses a strongly typed system to describe its capabilities. This allows clients to use a process called introspection to see exactly what they are able to do with the API, making GraphQL effectively self-documenting [<a href="#footnote-4">4</a>]. This has also lead to the development of many client-side tools.
</p>
<h4>2.3.3) Widespread Adoption of GraphQL</h4>
<p>
Because of its unique features, GraphQL caught on quickly at Facebook, and ended up being used heavily in their mobile application. It was an internal tool from 2012 until 2015; that year, they released an open-source version. Soon after GraphQL was open-sourced, many other companies began using it, including AirBnB, Twitter, Netflix, and Github. It has continued to grow in adoption ever since [<a href="#footnote-5">5</a>].
</p>
<p>
Now that we understand the types of problems that GraphQL was created to solve, we can take a closer look at what GraphQL is and how it works.
</p>
<h2 id="what-is-graphql">3) What is GraphQL?</h2>
<p>
GraphQL is a query language for APIs. In this section, we'll explain in more depth how it works and what is involved in building a GraphQL application.
</p>
<h3 id="the-graphql-specification">3.1) The GraphQL Specification</h3>
<p>
GraphQL is actually a specification that describes its type system and query language [<a href="#footnote-6">6</a>]. Both of these will be covered in more detail later. For now, keep in mind that this specification can be implemented in any programming language. It's not specific to one application or architecture. There are server-side implementations of the GraphQL specification in many programming languages. These server-side implementations are called GraphQL servers.
</p>
<h3 id="graphql-servers">3.2) GraphQL Servers</h3>
<p>
GraphQL servers communicate with clients using HTTP. The GraphQL server parses the request into an abstract syntax tree (AST) then walks the tree and determines how to respond to the request. Once the GraphQL server has assembled the request, the request is returned to the client as a JSON object over HTTP.
</p>
<h3 id="interacting-with-a-graphql-api">
3.3) Interacting with a GraphQL API
</h3>
<p>
With the GraphQL specification implemented on the server, the frontend can query it. Since the data is defined according to GraphQL's type system, the frontend structures its queries according to those types. The frontend can then specify exactly the data it wants in a query to the GraphQL server. The server will return that data in a JSON object.
</p>
<div class="img-wrapper">
<img
src="images/diagrams/3_3-graphql-overview.svg"
alt="GraphQL - Describe your data, ask for what you want, and get predictable results."
/>
</div>
<p>
Enabling this kind of interaction for frontend clients worked great for Facebook's News Feed API.
</p>
<h2 id="graphql-backends">4) GraphQL Backends</h2>
<p>
You should now have an idea of what kind of problems GraphQL was created to solve and a general understanding of how it works. You might even be interested in creating your next application using a GraphQL API. There are several factors to consider if you do, though.
</p>
<p>
First, we'll cover the overall architecture required for a web application backend.
</p>
<h3 id="backend-architecture">4.1) Backend Architecture</h3>
<p>
As a first step in understanding what it takes to build a GraphQL backend, let's take a look at the general setup for a backend:
</p>
<div class="img-wrapper">
<img
src="images/diagrams/4_1-normal-server.svg"
alt="The 3-tier architecture of a backend."
/>
</div>
<p>
A backend is usually built with a 3-tier architecture [<a href="#footnote-7">7</a>]. The different "tiers" in this architecture serve the following purposes:
</p>
<ul>
<li>
<b>Web Server:</b>: The web server acts as the internet-facing entry point to the backend. Web servers are optimized to handle requests involving <em>static</em> data, like static file serving and caching. They can typically handle large volumes of requests for this kind of data. If the web server cannot fulfill requests directly, it forwards requests to the backend.
</li>
<li>
<b>Application Server:</b>: The application server is where requests for <em>dynamic</em> data end up. It handles processing and fulfilling those requests. The application server is where the business logic that powers the application resides. The application server doesn't persist data itself, though. If a request needs access to persistent data, the application server will need to access a data store.
</li>
<li>
<b>Database:</b>: The database provides long-term data persistence to the application server. Interaction with the database must go through the application server.
</li>
</ul>
<p>
This kind of architecture is the foundation for building any feature our application might need.
</p>
<h3 id="backend-features">4.2) Backend Features</h3>
<p>
Given the basic architecture of a backend, we can start to imagine all the different things that a backend might need to do. These might include enabling SSL connections, managing realtime connections, providing hosting for frontend assets, and more. These all need to be set up and configured.
</p>
<div class="img-wrapper">
<img
src="images/diagrams/4_2-backend-features.svg"
alt="A few of the many different features that a backend is responsible for."
/>
</div>
<p>
Any one of these tasks is a topic unto itself. For the backend of a GraphQL application, though, producing the GraphQL API is a subject we'll need to explore further.
</p>
<h3 id="what-are-the-challenges-of-a-graphql-api">
4.3) What are the Challenges of a GraphQL API?
</h3>
<p>
Individual developers and companies have mentioned the challenges
associated with implementing GraphQL in production applications.
</p>
<p>
Arnaud Lauret, author of the book "The Design of Web APIs", mentions
the new challenges that a GraphQL API brings [<a href="#footnote-8"
>8</a
>]:
</p>
<blockquote>
<i
>“GraphQL does not ease an API provider’s job and brings new
challenges.”</i
>
<br /><br />
- Arnaud Lauret, author of The Design of Web APIs
</blockquote>
<p>
In an article from PayPal's engineering blog, a similar challenge is
mentioned - GraphQL is different than what developers may be used to
[<a href="#footnote-9">9</a>]:
</p>
<blockquote>
<i
>“Ensure that architects and API designers are on board with GraphQL
... More than likely, they have designed REST APIs for years.
GraphQL is different.”</i
>
<br /><br />
- Scaling GraphQL at Paypal - Paypal Engineering Blog
</blockquote>
<p>
With this in mind, we are ready to proceed with discussing how one
produces a GraphQL API.
</p>
<h3 id="how-is-a-graphql-api-produced">
4.4) How is a GraphQL API Produced?
</h3>
<p>
To produce a GraphQL API, we need to run a GraphQL server. As mentioned earlier, a GraphQL server is software that receives and responds to GraphQL requests. The behavior of a GraphQL server is defined using two inputs: a GraphQL schema and resolver functions. A GraphQL schema defines “what” the GraphQL server can do using the GraphQL type system, and resolver functions tell it “how” to do it [<a href="#footnote-10">10</a>].
</p>
<p>
A diagram of a GraphQL server is shown here. A GraphQL schema defines the GraphQL API. Then the API invokes the necessary resolver functions. Finally, the resolvers carry out the actions needed to produce a response, like querying a database:
</p>
<div class="img-wrapper">
<img
src="images/diagrams/4_4-graphql-server.svg"
alt="A GraphQL server."
/>
</div>
<h4>4.4.1) GraphQL Schema</h4>
<p>
GraphQL schema declaratively defines the functionality of a GraphQL API [<a href="#footnote-11">11</a>]. Schema is made up of types, and types have one or more fields.
</p>
<p>
A basic GraphQL schema is shown here. It has several types - the “Person” type is an object type. Object types make up the “things” of your API. Each type will also have fields. For the Person here, there is a name and phone field, which are a string and integer. You can think of fields like the properties of your objects.
</p>
<div class="img-wrapper">
<img
src="images/diagrams/4_4_1-graphql-schema.png"
alt="A GraphQL schema."
/>
</div>
<p>
There are many more types than just objects. Two important ones are query and mutation types. These describe what actions you can do with your object types. Queries define how to retrieve data and mutations define how to create or change data. Here we have a query to find a person by name, and a mutation to create a new person.
</p>
<p>
Keep in mind that these definitions of queries and mutations don’t say anything about <em>how</em> the API gets the job done. They only describe what the API can do!
</p>
<h4>4.4.2) GraphQL Resolvers</h4>
<p>
Resolvers are functions that tell the GraphQL server how to respond to
requests.
</p>
<p>
Unlike the schema, which has to follow the requirements of the GraphQL specification, resolvers are flexible. They are just functions, and you can do anything with them that you would do with any other function. The only requirement is that the function needs to return a value(s) which correspond to the field(s) specified by the schema [<a href="#footnote-12">12</a>].
</p>
<p>
In this example, the resolvers correspond to the respective query and mutation types that were defined in the GraphQL schema.
</p>
<div class="img-wrapper">
<img
src="images/diagrams/4_4_2-graphql-resolver.png"
alt="Some GraphQL resolvers."
/>
</div>
<p>
With the GraphQL schema and resolver functions defined, we have everything we need to initialize the GraphQL server and produce a GraphQL API.
</p>
<h3 id="how-can-we-reduce-the-complexity-of-a-graphql-backend">
4.5) How Can We Reduce the Complexity of a GraphQL Backend?
</h3>
<p>
We now see the big picture of what goes into creating a GraphQL backend. Besides the architecture and configuration needed for a typical backend, there are also the inputs needed to define the GraphQL API: schema and resolver functions.
</p>
<div class="img-wrapper">
<img
src="images/diagrams/4_5_1-full-backend.svg"
alt="All of the architecture and inputs required to make a GraphQL backend."
/>
</div>
<p>
For a frontend developer wanting to get a GraphQL application up and running quickly, that’s a lot to think about. Because of this, we wanted to find a quick and easy way to setup a simple GraphQL backend.
</p>
<p>
Ideally, the developer wouldn’t have to think about the backend design at all. The standard backend components and configuration should be set up automatically, as should the lower-level GraphQL configuration, like resolver functions.
</p>
<p>
In order to solve the aforementioned problems, we decided to build a backend-as-a-service (BaaS). A BaaS provides an abstraction over all the functionality and complexity of the backend.
</p>
<h2 id="backend-as-a-service">5) Backend-as-a-Service</h2>
<h3 id="what-is-a-backend-as-a-service-baas">
5.1) What is a Backend-as-a-Service (BaaS)?
</h3>
<p>
A BaaS encapsulates the underlying architecture that a backend needs - the web server, app server, and database. It also provides pre-configured features like SSL certificates and static frontend hosting. The functionality of the backend is made available to frontend applications through an API [<a href="#footnote-13">13</a>].
</p>
<div class="img-wrapper">
<img
src="images/diagrams/5_1-backend-as-a-service.svg"
alt="A backend as a service."
/>
</div>
<p>
With a BaaS, you simply ask for a backend to be created. Then it gives you an endpoint to access that backend's functionality.
</p>
<h3 id="why-use-a-baas">
5.2) What are the tradeoffs of using a BaaS?
</h3>
<p>
As we've seen, a BaaS facilitates frontend development. It abstracts away the complexity of the backend, allowing for faster application development.
</p>
<p>
This abstraction does come with costs, though. For example, the BaaS itself still requires setup and maintenance. Also, with these kinds of services, you gain abstraction and sacrifice control. The table below shows how a BaaS compares to two other services which provide abstraction over backend concerns: infrastructure-as-a-service (IaaS) and platform-as-a-service (PaaS).
</p>
<div class="img-wrapper">
<img
src="images/diagrams/5_2-abstraction-vs-control1.png"
alt="BaaS tradeoffs - abstraction vs. control."
/>
</div>
<p>
An IaaS provides the lowest level of abstraction. The developer configures everything from the operating system on up. That makes it low in abstraction but high in control.
</p>
<p>
A PaaS provides more abstraction than an IaaS, but less than a BaaS. The developer provides all the application code for the backend. The platform handles the operating system configuration and deployment.
</p>
<p>
At the highest level of abstraction is a BaaS. The developer no longer needs to provide any backend code or handle any backend configuration, but they can't control how the service works internally.
</p>
<p>
Giving up control over the internals of the backend seemed like a reasonable trade-off for an application that requires rapid development.
</p>
<h3 id="existing-graphql-baas">5.3) Existing GraphQL BaaS</h3>
<p>
There are several existing GraphQL BaaS options to choose from. These can be grouped into two categories: managed services and open-source solutions.
</p>
<h4>5.3.1) Managed Services</h4>
<p>
Managed services are paid, proprietary services and are fully supported by a provider. Using a paid service takes care of all the details of setting up and managing backends. In general, they are easy to use - with some caveats. <a href="https://aws.amazon.com/amplify/">AWS Amplify</a>, for example, has a close integration with other AWS services. That makes it a great option if you are committed to using AWS services for your entire application. It's possible, but more difficult, to use it with non-AWS services. Since there is no need to deploy anything to use these managed services, they're very simple to use.
</p>
<p>
These managed services also tend to have many features. Services like <a href="https://www.8base.com/">8Base</a> and <a href="https://nhost.io/">Nhost</a> provide just about any feature you could want from a backend even beyond the GraphQL API. <a href="https://dgraph.io/slash-graphql">Slash GraphQL</a> has comparatively fewer features. It does, though, have some advanced options like the ability to run custom logic via serverless lambda functions.
</p>
<h4>5.3.2) Open-Source Solutions</h4>
<p>
For open-source options, the most popular is probably <a href="https://parseplatform.org/">Parse Platform</a>. Parse is a self-hosted platform that provides a backend with all the features you could need for your application, including a GraphQL API. Unlike the managed services, you can host Parse anywhere you want. It gives you full control over your data and infrastructure.
</p>
<p>
Another, less well-known GraphQL BaaS is <a href="https://spaceuptech.com/">Spacecloud</a>. It offers a similar wide range of features as Parse and also lets you self-host it wherever you want.
</p>
<h3 id="why-not-use-an-existing-graphql-baas">
5.4) Why Not Use an Existing GraphQL BaaS?
</h3>
<p>
While the existing GraphQL BaaS options have many useful features,
they have their tradeoffs as well.
</p>
<p>
Although managed services need minimal effort to deploy and are generally easy to use, they are not open-source. With these services, you don’t have any control over how your application and its data are hosted. You also run the risk of vendor lock-in if your application outgrows the BaaS.
</p>
<p>
With the existing open source options, you maintain control of your data but have more complicated deployment and usage. You will need to worry about things like selecting and configuring a database with both Parse and Spacecloud, for example. With their wide range of features and options, it can take some time to learn how to use them once they are deployed.
</p>
<h3 id="where-does-satellite-fit">5.4) Where Does Satellite Fit?</h3>
<p>
After reviewing the existing BaaS options, we saw that there was an opportunity for a self-hosted GraphQL BaaS that is easy to deploy and use. Two main things influenced our idea. One is the simplicity of managed services. The other is the ability to self-host an open-source solution and maintain full control of an application and its data.
</p>
<p>
The table below shows where Satellite fits compared to some existing
options:
</p>
<div class="img-wrapper">
<img
src="images/diagrams/5_4_option-comparison-table.png"
alt="How Satellite compares to existing BaaS options."
/>
</div>
<p>
Compared to the other GraphQL BaaS options, Satellite has fewer features. We kept it that way to simplify deployment and ensure that it was intuitive to use. Like other existing open-source options, you can host Satellite anywhere you’d like.
</p>
<p>
Since Satellite doesn’t have a huge number of features, it won't be a good fit for every application. But if you want an open-source solution to quickly get a GraphQL backend running with minimal features, Satellite might be a good option.
</p>
<h2 id="the-core-application">6) The Core Application</h2>
<p>
The Satellite core application represents a single backend instance. It provides a GraphQL API for client applications to access, a persistent data store, and static file serving for frontend hosting.
</p>
<div class="img-wrapper">
<img
src="images/diagrams/6_1-core-architecture-simple.svg"
alt="Satellite's core application architecture - high level."
/>
</div>
<p>
These features are made possible using several components under the hood. First is an Nginx web server, used for serving static files and routing incoming requests. Next is a NodeJS Express application server, which allows administrative actions to be made on the Satellite instance. Finally, a Dgraph graph database is used to store persistent data.
</p>
<p>
Our priority while designing Satellite was to keep it easy to use. In this rest of this section, we'll explain the main problems we solved in achieving that goal and how we arrived at our current architecture.
</p>
<h3 id="how-is-an-application-s-data-defined">
6.1) How is an Application's Data Defined?
</h3>
<p>
When we started building Satellite, we faced a question: how do we build a GraphQL backend that works for any application without knowing what kind of data that application will need ahead of time? We needed to build a “generic” GraphQL backend that would work for any application.
</p>
<p>
To answer that question, we had to determine the best way to allow a developer to define the structure of their application's data.
</p>
<h4>6.1.1) GraphQL Schema vs. Database Schema</h4>
<p>
The backend for a GraphQL application will normally need to deal with interconnected, related data. One way to handle this is to use a relational database with a GraphQL layer over it. The GraphQL queries from the client would get translated to SQL queries by resolver functions. This solution has the drawback of needing two sets of schema - one for the relational database and one for the GraphQL API.
</p>
<p>
Requiring a database schema in addition to the GraphQL schema would add another piece of configuration that must be provided to the backend. That was something we wanted to avoid to keep Satellite simple.
</p>
<h4>6.1.2) A Hypothetical Database Schema Generator</h4>
<p>
At first, we thought we could come up with a way to generate a relational database schema from a GraphQL schema. This would eliminate the need for two schemas and make it possible to define the structure of the backend's data using only a GraphQL schema.
</p>
<p>But what would this look like? Would it even be possible?</p>
<p>
For a simple GraphQL schema, consisting of only a single object type like the one shown below, this idea could work. We could generate a database schema defining a table with columns corresponding to the object.
</p>
<div class="img-wrapper">
<img
src="images/diagrams/6_1_2-schema-to-schema.png"
alt="Generating a database schema from a simple GraphQL schema."
/>
</div>
<p>
The logic for this hypothetical conversion process should've been a simple matter of converting strings. For now, we were ready to proceed to the next step.
</p>
<h3 id="how-is-an-application-s-data-accessed">
6.2) How is an Application's Data Accessed?
</h3>
<p>
Now that we had a way to define the data of an application, we needed
a way to access the data.
</p>
<h4>6.2.1) Resolver Functions in a GraphQL BaaS</h4>
<p>
As we’ve mentioned, making the data available for a GraphQL backend requires a GraphQL server to serve the API. The GraphQL server also needs to contain resolver functions for responding to requests. The challenge is that writing these resolver functions requires the developer to go "under the hood" and edit the backend’s code. To keep Satellite easy to use and preserve the encapsulation of the BaaS, this was a problem we wanted to avoid.
</p>
<h4>6.2.2) A Hypothetical Resolver Function Generator</h4>
<p>
As a possible solution, we thought we could take a similar approach as we had for converting the GraphQL schema to a database schema, and apply it to automatically generating resolver functions. These would be functions for common actions on an application’s data - creating, reading, updating, and deleting [<a href="#footnote-14">14</a>]. The GraphQL server would then be initialized with those functions.
</p>
<p>
Would it be possible to do this? We again considered our very simple GraphQL schema to consider what this resolver function generator might look like:
</p>
<div class="img-wrapper">
<img
src="images/diagrams/6_2_2-schema-to-resolvers.png"
alt="Generating resolver functions from a simple GraphQL schema."
/>
</div>
<p>
We would need four resolvers for each object type in the schema: a Query type for reading the data and three Mutation types for creating, updating, and deleting. This was getting complicated but still seemed doable. Since all the resolvers followed a similar pattern, we should've been able to generate the correct function signatures and required database actions to make it work... at least for a simple schema like this.
</p>
<p>
Our imagined schema converter would no longer only be a matter of converting strings. Now it would need to generate functions, too. But, we still felt confident enough to proceed down this path.
</p>
<h4>6.2.3) The Hypothetical Architecture</h4>
<p>
We could now envision a hypothetical architecture for our GraphQL backend. It would need only a GraphQL schema as an input.
</p>
<div class="img-wrapper">
<img
src="images/diagrams/6_2_3-hypothetical-architecture.svg"
alt="A hypothetical architecture for Satellite."
/>
</div>
<p>
The schema converter would get the GraphQL schema. Then it would generate a database schema and create the database. Next, it would generate the resolvers functions. Finally, the GraphQL server would produce a GraphQL API. It could then receive and respond to GraphQL requests from frontend applications.
</p>
<p>
But like so many things in software engineering, it turned out to be more complicated than we had assumed.
</p>
<h3 id="what-about-more-complicated-data">
6.3) What About More Complicated Data?
</h3>
<p>
So far, we've only looked at a very simple schema - probably too simple to make an interesting application.
</p>
<p>
Difficulties arose with more complicated schema. Creating the database schema and resolver functions became much harder. The schema in the next figure shows some more complex behaviors that can be defined using the GraphQL type system:
</p>
<ul>
<li>
The type <code>Person</code> has the fields <code>name</code>,
<code>address</code>, and <code>friends</code>:
<ul>
<li>
<code>name</code> has the <em>scalar</em> type of
<code>String</code>. Scalar types are what we have been looking
at so far. These types repesent a peice of concrete data.
</li>
<li>
<code>address</code> has the type of <code>Address</code>. The
type <code>Address</code> is also defined in the schema. This is
a <em>user defined</em> type.
</li>
<li>
<code>friends</code> refers to a <em>list</em> of user defined
types - a list of <code>Person</code> types.
</li>
</ul>
</li>
<li>
The type <code>Address</code> is similar to what we've seen so far,
with all of its fields being scalar types.
</li>
</ul>
<p>
A schema like this allows the GraphQL API to handle relationships. That's a key feature of GraphQL, so it wasn't something we could ignore. But what would our imagined schema converter look like now?
</p>
<div class="img-wrapper">
<img
src="images/diagrams/6_3-complicated-schema.png"
alt="More complicated conversion - the results are uncertain."
/>
</div>
<p>
The schema converter would need to define multiple tables, foreign keys, and constraints. Besides this, we'd also have to think much harder about resolver generation.
</p>
<p>
So far, we'd been taking advantage of something called the default resolver. According to the GraphQL specification, every field in a GraphQL schema needs a resolver. If no resolver function is defined for a field, most GraphQL implementations will fall back to the default resolver [<a href="#footnote-15">15</a>]. The default resolver simply returns a property from the returned object with the relevant field name. For example, if we defined resolvers for every field of the simple schema we considered earlier, the resulting functions would look like this:
</p>
<div class="img-wrapper">
<img
src="images/diagrams/6_3-full-resolvers.png"
alt="A full set of resolvers, without the implicit default resolvers."
/>
</div>
<p>
See the extra resolvers defined for Person? These are usually handled
behind the scenes by the default resolver.
</p>
<p>
Clearly, with schema having fields that aren't simple scalar types, we could no longer rely on the default resolver. Our schema converter would need to be smart enough to traverse each type recursively, identify non-scalar fields and generate resolver functions for those fields. An algorithm like this would actually be similar in concept to how a GraphQL server converts an incoming request into an AST.
</p>
<p>
Although we were still confident we could pull this off, going this route looked like it would mean reinventing the wheel. We thought it would be a good time to take a step back and consider alternatives.
</p>
<h3 id="graph-databases">6.4) Graph Databases</h3>
<p>
Our search for a simpler way to generate resolver functions from a GraphQL schema led us to consider other kinds of databases. Graph databases showed promise.
</p>
<h4>6.4.1) What are Graph Databases?</h4>
<p>
Graph databases are specialized to handle highly interconnected data [<a href="#footnote-16">16</a>]. They do this by treating their data as a graph - which is similar to how GraphQL treats its data. In fact, some Graph databases even have integrations with GraphQL to generate resolvers, which was exactly what we were looking for.
</p>
<h4>6.4.2) Graph Databases and GraphQL</h4>
<p>
Two graph databases with GraphQL integrations are <a href="https://neo4j.com/labs/grandstack-graphql/">neo4j</a> and <a href="https://dgraph.io/">Dgraph</a>. Neo4j is the most widely used graph database [<a href="#footnote-17">17</a>]. Its GraphQL integration involves using an add-on to the database, which was a more complicated setup than we were hoping for.
</p>
<p>
Dgraph is less well-known that neo4j, but it has native GraphQL integration. You don’t have to install any other addons - you get the GraphQL API directly from the database.
</p>
<div class="img-wrapper">
<img
src="images/diagrams/6_4_2-graph-databases.png"
alt="Two graph databases - Neo4j and Dgraph."
/>
</div>
<p>
Because of its native GraphQL support, we chose Dgraph for Satellite's database. This greatly simplified our architecture.
</p>
<h4>6.4.3) Simplified Architecture</h4>
<p>
Letting Dgraph handle resolver generation and serve the GraphQL API let us simplify our hypothetical architecture:
</p>
<div class="img-wrapper">
<img
src="images/diagrams/6_4_2-simplified-architecture.svg"
alt="Simplified (hypothethical) architecture."
/>
</div>
<p>
With Dgraph accepting a GraphQL schema as an input, we were able to remove two major components from our architecture. We no longer needed a schema converter for generating database schema and resolvers. We also didn't need a separate application server to serve the API.
</p>
<p>
At this point, the majority of the heavy lifting was done. We still had a few more problems to solve before we could get to the final Satellite backend architecture, though.
</p>
<h3 id="other-challenges">6.5) Other Challenges</h3>
<h4>6.5.1) How Does Satellite Backend Administration Work?</h4>
<p>
Besides a GraphQL endpoint, Dgraph exposes administrative endpoints for interacting with its GraphQL schema. They can be used for updating the schema and viewing the currently loaded schema. The frontend Satellite user would need to access these admin endpoints but they shouldn’t be accessible from the public internet. As it was, we had no way of making only the GraphQL endpoint public to the internet, while keeping the admin endpoint private.
</p>
<div class="img-wrapper">
<img
src="images/diagrams/6_5_1-dgraph-admin-endpoints.svg"
alt="Dgraph's administrative endpoints."
/>
</div>
<p>
Also, we had no way to upload or serve static files for web applications. We needed a way to resolve both of these issues before we could declare victory.
</p>
<h4>6.5.2) Protecting the Administrative Endpoints</h4>
<p>
To protect Dgraph's administrative endpoints and deal with static files, we needed a couple more components.
</p>
<p>
The first component we needed was a web server to serve static files and act as a reverse proxy to the GraphQL API endpoint that Dgraph provides. We chose Nginx for this since it's an efficient and battle-tested product [<a href="#footnote-18">18</a>].
</p>
<div class="img-wrapper">
<img
src="images/diagrams/6_5_2-protecting-endpoints.png"