-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
API-Fastapi.html
1088 lines (1004 loc) · 69.2 KB
/
API-Fastapi.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">
<head>
<meta charset="utf-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>API & FastApi</title>
<meta content="" name="description">
<meta content="" name="keywords">
<!-- Favicons -->
<link href="assets/img/Favicon-1.png" rel="icon">
<link href="assets/img/Favicon-1.png" rel="apple-touch-icon">
<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i|Raleway:300,300i,400,400i,500,500i,600,600i,700,700i|Poppins:300,300i,400,400i,500,500i,600,600i,700,700i" rel="stylesheet">
<!-- Vendor CSS Files -->
<link href="assets/vendor/aos/aos.css" rel="stylesheet">
<link href="assets/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="assets/vendor/bootstrap-icons/bootstrap-icons.css" rel="stylesheet">
<link href="assets/vendor/boxicons/css/boxicons.min.css" rel="stylesheet">
<link href="assets/vendor/glightbox/css/glightbox.min.css" rel="stylesheet">
<link href="assets/vendor/swiper/swiper-bundle.min.css" rel="stylesheet">
<!-- Creating a python code section-->
<link rel="stylesheet" href="assets/css/prism.css">
<script src="assets/js/prism.js"></script>
<!-- Template Main CSS File -->
<link href="assets/css/style.css" rel="stylesheet">
<!-- To set the icon, visit https://fontawesome.com/account-->
<script src="https://kit.fontawesome.com/5d25c1efd3.js" crossorigin="anonymous"></script>
<!-- end of icon-->
<!-- =======================================================
* Template Name: iPortfolio
* Updated: Sep 18 2023 with Bootstrap v5.3.2
* Template URL: https://bootstrapmade.com/iportfolio-bootstrap-portfolio-websites-template/
* Author: BootstrapMade.com
* License: https://bootstrapmade.com/license/
======================================================== -->
</head>
<body>
<!-- ======= Mobile nav toggle button ======= -->
<i class="bi bi-list mobile-nav-toggle d-xl-none"></i>
<!-- ======= Header ======= -->
<header id="header">
<div class="d-flex flex-column">
<div class="profile">
<img src="assets/img/myphoto.jpeg" alt="" class="img-fluid rounded-circle">
<h1 class="text-light"><a href="index.html">Arun</a></h1>
<div class="social-links mt-3 text-center">
<a href="https://www.linkedin.com/in/arunp77/" target="_blank" class="linkedin"><i class="bx bxl-linkedin"></i></a>
<a href="https://github.com/arunp77" target="_blank" class="github"><i class="bx bxl-github"></i></a>
<a href="https://twitter.com/arunp77_" target="_blank" class="twitter"><i class="bx bxl-twitter"></i></a>
<a href="https://www.instagram.com/arunp77/" target="_blank" class="instagram"><i class="bx bxl-instagram"></i></a>
<a href="https://arunp77.medium.com/" target="_blank" class="medium"><i class="bx bxl-medium"></i></a>
</div>
</div>
<nav id="navbar" class="nav-menu navbar">
<ul>
<li><a href="index.html#hero" class="nav-link scrollto active"><i class="bx bx-home"></i> <span>Home</span></a></li>
<li><a href="index.html#about" class="nav-link scrollto"><i class="bx bx-user"></i> <span>About</span></a></li>
<li><a href="index.html#resume" class="nav-link scrollto"><i class="bx bx-file-blank"></i> <span>Resume</span></a></li>
<li><a href="index.html#portfolio" class="nav-link scrollto"><i class="bx bx-book-content"></i> <span>Portfolio</span></a></li>
<li><a href="index.html#skills-and-tools" class="nav-link scrollto"><i class="bx bx-wrench"></i> <span>Skills and Tools</span></a></li>
<li><a href="index.html#language" class="nav-link scrollto"><i class="bi bi-menu-up"></i> <span>Languages</span></a></li>
<li><a href="index.html#awards" class="nav-link scrollto"><i class="bi bi-award-fill"></i> <span>Awards</span></a></li>
<li><a href="index.html#professionalcourses" class="nav-link scrollto"><i class="bx bx-book-alt"></i> <span>Professional Certification</span></a></li>
<li><a href="index.html#publications" class="nav-link scrollto"><i class="bx bx-news"></i> <span>Publications</span></a></li>
<!-- <li><a href="index.html#extra-curricular" class="nav-link scrollto"><i class="bx bx-rocket"></i> <span>Extra-Curricular Activities</span></a></li> -->
<!-- <li><a href="#contact" class="nav-link scrollto"><i class="bx bx-envelope"></i> <span>Contact</span></a></li> -->
</ul>
</nav><!-- .nav-menu -->
</div>
</header><!-- End Header -->
<main id="main">
<!-- ======= Breadcrumbs ======= -->
<section id="breadcrumbs" class="breadcrumbs">
<div class="container">
<div class="d-flex justify-content-between align-items-center">
<h2>Data-Engineering</h2>
<ol>
<li><a href="Data-engineering.html" class="clickable-box">Content section</a></li>
<li><a href="index.html#portfolio" class="clickable-box">Portfolio section</a></li>
</ol>
</div>
</div>
</section><!-- End Breadcrumbs -->
<!------ right dropdown menue ------->
<div class="right-side-list">
<div class="dropdown">
<button class="dropbtn"><strong>Shortcuts:</strong></button>
<div class="dropdown-content">
<ul>
<li><a href="cloud-compute.html"><i class="fas fa-cloud"></i> Cloud</a></li>
<li><a href="AWS-GCP.html"><i class="fas fa-cloud"></i> AWS-GCP</a></li>
<li><a href="amazon-s3.html"><i class="fas fa-cloud"></i> AWS S3</a></li>
<li><a href="ec2-confi.html"><i class="fas fa-server"></i> EC2</a></li>
<li><a href="Docker-Container.html"><i class="fab fa-docker" style="color: rgb(29, 27, 27);"></i> Docker</a></li>
<li><a href="Jupyter-nifi.html"><i class="fab fa-python" style="color: rgb(34, 32, 32);"></i> Jupyter-nifi</a></li>
<li><a href="snowflake-task-stream.html"><i class="fas fa-snowflake"></i> Snowflake</a></li>
<li><a href="data-model.html"><i class="fas fa-database"></i> Data modeling</a></li>
<li><a href="sql-basics.html"><i class="fas fa-table"></i> QL</a></li>
<li><a href="sql-basic-details.html"><i class="fas fa-database"></i> SQL</a></li>
<li><a href="Bigquerry-sql.html"><i class="fas fa-database"></i> Bigquerry</a></li>
<li><a href="scd.html"><i class="fas fa-archive"></i> SCD</a></li>
<li><a href="sql-project.html"><i class="fas fa-database"></i> SQL project</a></li>
<!-- Add more subsections as needed -->
</ul>
</div>
</div>
</div>
<!-- ======= Portfolio Details Section ======= -->
<section id="portfolio-details" class="portfolio-details">
<div class="container">
<div class="row gy-4">
<h1>API and FastApi</h1>
<div class="col-lg-8">
<div class="portfolio-details-slider swiper">
<div class="swiper-wrapper align-items-center">
<figure>
<img src="assets/img/data-engineering/APIs.png" alt="" style="max-width: 50%; max-height: 50%;">
<figcaption></figcaption>
</figure>
</div>
<div class="swiper-pagination"></div>
</div>
</div>
<div class="col-lg-4 grey-box">
<h3>Content</h3>
<ol>
<li><a href="#introduction">Introduction</a></li>
<li><a href="#concept">API concept</a></li>
<li><a href="#fastapi">FastApi</a></li>
<li><a href="#json">JSON: JavaScript Object Notation</a></li>
<li><a href="#reference">Reference</a></li>
</ol>
</div>
</div>
<!---------sections start here ------------>
<section id="introduction">
<h3>Introduction</h3>
API stands for <strong>Application Programming Interface</strong>. An API is a set of subroutine definitions, communication protocols and tools that allows different software applications to communicate with each other.
It defines the methods and data formats that applications can use to request and exchange information.
<div class="alert alert-info"> <i class="bi bi-pen-fill"></i> We can think of a API as a power outlet. A socket defines a protocol for its use: the device you want to connect must have two pins, spaced a certain distance apart. If this distance is respected, then the socket will deliver a 220V current at a frequency of 50Hz. From the customer's point of view, i.e. the electrical appliance, it doesn't matter how the electricity is generated. It can be any kind of power plant. From the other side, i.e. from the point of view of the plug, there is no need to adapt to the electrical device: if the protocol is respected, the necessary energy is supplied.
</div>
<figure>
<img src="assets/img/data-engineering/api-1.png" alt="" style="max-width: 90%; max-height: auto;">
<figcaption style="text-align: center;"><strong>Image credit: </strong>@ Arun Kumar Pandey</figcaption>
</figure>
APIs play a crucial role in modern software development by enabling the integration of different services, systems, or applications. They allow developers to access the functionality of a service or application without needing to understand its internal workings. APIs are used for various purposes, including accessing web services, databases, operating system services, or hardware components.
<p><strong>Some examples:</strong> There are many types of APIs possible. Some of them are:</p>
<ul>
<li>the <a href="https://pandas.pydata.org/docs/reference/index.html#api" target="_blank">pandas</a> library can actually be seen as an API. There is a set of rules that allow to use complex functions from a simplified documentation.</li>
<li>the <a href="https://openweathermap.org/current" target="_blank">OpenWeatherMap API</a> is a data API. From an HTTP request, we receive weather data in the requested location, at the requested date.</li>
<li>the API <a href="https://cloud.google.com/translate?hl=en" target="_blank">Google Cloud Translate</a> allows to use the translation function of Google to easily translate the texts we use.</li>
</ul>
<h4 id="types-api">Types of APIs:</h4>
<ul>
<li><strong>Web APIs (HTTP/RESTful APIs): </strong>APIs that use the HTTP protocol and follow REST (Representational State Transfer) principles for communication. </li>
<li><strong>Library APIs: </strong>APIs provided by programming libraries to enable developers to use pre-built functions and classes.</li>
<li><strong>Operating System APIs: </strong>APIs provided by operating systems to allow applications to interact with the underlying system resources.</li>
<li><strong>Database APIs: </strong>APIs that provide access to databases, allowing applications to retrieve or manipulate data.</li>
</ul>
<!------ API concept ------------->
<h4 id="concept">Concepts</h4>
Securing an API is crucial to protect sensitive data, maintain the integrity of your system, and prevent unauthorized access.
Securing an API rely on three important levels:
<ol type="i">
<li><strong>Authentication: </strong>Authentication is a step that consists in verifying the identity of the client querying the API. By providing some credentials or a key to the API, the server will know that the client is who he claims to be.</li>
<li><strong>Authorization: </strong>At the authorization level, the API will check that, based on the identity acknowledged at the previous step, the client is indeed allowed to perform the query.</li>
<li><strong>Traceability: </strong>To better the security of your API, you also need to track the queries. We usually store information about <code>What</code>, <code>Who</code> and <code>When</code> the queries were made in a simple log file or, in some cases, in a database.
<ul>
<li><strong>What: </strong>
<ul>
<li>which endpoint was called.</li>
<li>which method was used.</li>
</ul>
</li>
<li><strong>Who: </strong>
<ul>
<li>the user that made the call</li>
<li>the device used to make that call (mobile phone, web browser, programming language, ...)</li>
<li>the IP used by the user</li>
</ul>
</li>
<li><strong>When: </strong>the time of the request (date and hour)</li>
</ul>
</li>
</ol>
<figure>
<img src="assets/img/data-engineering/who-when-what.png" alt="" style="max-width: 90%; max-height: auto;">
<figcaption style="text-align: center;"><strong>Image credit: </strong><a href="https://datascientest.com/" target="_blank">Datascientist.com</a></figcaption>
</figure>
Getting information on the source of the request can help add security to your API. For example, you could restrict IP addresses to given countries: if you are a U.S. company with servers, employees and clients in the U.S., a query from somewhere else could be suspicious.
Another approach is to validate a few IP addresses that corresponds to the machines using your service and reject any other IP.
<h4 id="components">Key components</h4>
Key components icnclude:
<ul>
<li><strong>Endpoints: </strong>URLs or URIs that define where the API can be accessed.</li>
<li><strong>Methods: </strong>Specify the actions that can be performed, such as GET (retrieve data), POST (submit data), PUT (update data), DELETE (remove data), etc.</li>
<li><strong>Request and Response Formats: </strong>Define how data is structured when making requests to the API and how it is formatted in the response.
Data formats define the structure of the data exchanged between the API and the application. </li>
<li><strong>Authentication: </strong>Authentication methods ensure that only authorized users can access the API's functionality.</li>
</ul>
<p><strong>For example:</strong> the following URI <span style="color: blue;">http://example.org/resource</span> can be read as follows:</p>
<ul>
<li><span style="color: blue;">http://</span> is the protocol used</li>
<li><span style="color: blue;">example.org</span> is the domain name of the server, which is a simplification of the server's IP address.</li>
<li><span style="color: blue;">/resource</span> is the endpoint you wish to request</li>
</ul>
<figure>
<img src="assets/img/data-engineering/endpoint-https.png" alt="" style="max-width: 90%; max-height: auto;">
<figcaption style="text-align: center;"><strong>Image credit: </strong><a href="index.html" target="_blank">Arun Kumar Pandey</a></figcaption>
</figure>
<p>Note that a URI can also have parameters. For example, the URI <span style="color: blue;">http://example.org/resource?key1=value1&key2=value2</span> allows to pass the keys <code>key1</code> and <code>key2</code> which have respectively the values <code>value1</code> and <code>value2</code> to the server. This is called a query string or query parameters.</p>
<!---------------------->
<h4 id="https">HTTP responses</h4>
When an HTTP request is sent, the server sends a response to the client. This response is also composed of different elements:
<ul>
<li>Headers with the response metadata</li>
<li>A body with the content of the response</li>
<li>A status code</li>
</ul>
The content of an HTTP response is very often HTML for websites but it is more likely to be JSON or XML for APIs. The status code makes it easy to understand if the request was successful. By convention, the error codes should correspond to the following states:
<ul>
<li><code>10X</code>: Information</li>
<li><code>20X</code>: Means that the request was successful</li>
<li><code>30X</code>: Redirection</li>
<li><code>40X</code>: Means a client-side error / Client error</li>
<li><code>50X</code>: Means server side error / Server error</li>
</ul>
Thus, a 404 code is an error from the client that did not enter the right address to access the resource while a 503 error will be an error from the server that cannot run the requested service.
<h5 id="links-web">Links with the web</h5>
Websites work on the same principle of server-client architecture that we request via HTTP using a Web browser. Thus, by clicking on a link, the browser sends a request of type <code>GET</code> to the server of the website. If the address is correct, the server returns a response containing an HTML file that will be interpreted by the browser. Similalry, when a form is filled in on a website, it is generally a request of type POST. The request then contains the data filled in the form.
<h5 id="protocol">HTTPS protocol</h5>
The HTTPS protocol is a more secure version of the HTTP protocol. It is in fact the HTTP protocol to which an SSL (Secure Socket Layer) encryption layer is added. It protects the authentication of a server, the confidentiality and integrity of the data exchanged, and sometimes the authentication of the client: a public key is given to the client so that the data sent back to the server is encrypted; this data is then decoded thanks to a private key available on the server. It tends to become the standard, pushed by search engines that better reference sites using an HTTPS protocol.
<h5 id="clients">HTTP clients</h5>
As we have seen in the previous examples, the browser is a client that allows to make HTTP requests to servers that are able to return data according to the request. However, there are other simpler tools to use when you want to interact with an API.
<h5 id="curl">CURL</h5>
We will query an API from the terminal using the command line interface cURL (client URL Request Library). To make an HTTP request from the terminal with cURL, the syntax for making a request is as follows :
<pre><code class="language-python">curl -X GET http://example.com </code></pre>
The -X argument introduces the method, in this case, GET. Then we can write the URI.
<ul>
<li>For example:
<pre><code class="language-python">curl -X GET https://jsonplaceholder.typicode.com/posts/1</code></pre>
<p>With this request, we receive a "stringified" JSON object containing information about a post.</p>
<figure>
<img src="assets/img/data-engineering/curl-get1.png" alt="" style="max-width: 90%; max-height: auto;">
<figcaption style="text-align: center;"><strong>Image credit: </strong><a href="index.html" target="_blank">Arun Kumar Pandey</a></figcaption>
</figure>
<p>Here, we have requested the post with ID 1. We can get all posts with a GET request to the <code>/posts</code> endpoint. This is a case we commonly encounter: the endpoint with an ID returns an individual observation while without any ID it returns all observations.</p>
<p>The HTTP response to this request contains only the body. To see the headers, we can add the <code>-i</code> argument to the :</p>
<pre class="language-python"><code>curl -X GET -i https://jsonplaceholder.typicode.com/posts/1</code></pre>
In the header, you can see information about the content of the response, such as the status code, which in this case is 200.
</li>
<li>We have seen how to make a request with the GET method. Now, if you want to use the PUT method to add data to the API, you will probably want to specify a body and headers. To do this, you need to precede your headers with the -H argument and the body with the -d argument.
<pre class="language-python"><code>
curl -X PUT -i\
-H "Content-Type: application/json"\
-d '{"id": 1, "content": "hello world"}'\
https://jsonplaceholder.typicode.com/posts/1
</code></pre>
Here, we indicate in the header the type of data sent (JSON), and in the body the data in question. cURL is undoubtedly the simplest tool to use.
</li>
</ul>
<h5 id="postman"><a href="https://www.postman.com/" target="_blank">Postman</a></h5>
Postman is a collaborative platform for API development. It allows to build and execute HTTP requests, to store them in a history so that they can be replayed, and to organize them in collections. Among other things, Postman allows us to:
<ul>
<li>Quickly and easily send REST, SOAP and GraphQL requests</li>
<li>Automate manual tests and integrate them into a CI/CD pipeline to ensure that no code changes interrupt the API in production.</li>
<li>Communicate the expected behavior of an API by simulating endpoints and their responses without having to configure a backend server</li>
<li>Generate and publish nice machine-readable documentation to make the API easier to use.</li>
<li>Stay up-to-date on the health of your API by checking performance and response times at scheduled intervals.</li>
<li>Collaborate in real time with built-in version control.</li>
</ul>
Postman offers a very simple interface to make complex HTTP requests. It is a very useful tool for testing/exploring an API. Moreover, Postman's features allow us to easily export a request made with Postman in the language of our choice.
<h4 id="python-libraries">Python HTTP libraries</h4>
The simplest library to make requests with Python is probably the <a href="https://docs.python-requests.org/en/latest/" target="_blank">Requests</a> library and it can be installed using:
<pre class="language-python"><code>
pip3 install requests
# or conda install requests
</code></pre>
and then we can access the content as:
<pre class="language-python"><code>
import requests
# creating a GET request
r = requests.get('https://jsonplaceholder.typicode.com/posts/1')
# getting the response elements
response_dict = r.json
response_header = r.headers
status_code = r.status_code
</code></pre>
We can of course pass a body, headers with this library.
<pre class="language-python"><code>
r = requests.put(
url='https://jsonplaceholder.typicode.com/posts/1',
data={"id": 1, "content": "hello world"},
headers={"Content-Type": "application/json"}
)
</code></pre>
Another popular library is the <a href="https://docs.python.org/3/library/urllib.html" target="_blank">Urllib library</a> installed natively with Python but more difficult to use.
</section>
<!------ FastApi ------------->
<section>
<h3 id="rest-api">The REST standard</h3>
Each API has a specific architecture, as well as rules to respect that determine the data formats and commands accepted to communicate with. In order to promote accessibility and standardization of APIs for developers, there are now classic API architectures that are very often used. For example, <strong>REST (Representational State Transfer)</strong> is an architecture that is very often used in the creation of WEB services. It allows applications to communicate with each other regardless of the operating system via the HTTP protocol. A REST API uses HTTP requests to communicate and must respect the following principles:
<ul>
<li><strong>Client-server architecture :</strong> the client must make HTTP requests to request resources. There is independence between the client side and the server application so that changes to one endpoint do not affect the others.</li>
<li><strong>Uniform interface :</strong> simplified architecture that allows each part to evolve independently. To speak of a uniform interface, 4 constraints must be respected</li>
<li><strong>Resource identification in requests :</strong> resources are identified in requests and are separated from the representations returned to the client.</li>
<li><strong>Resource manipulation by representations :</strong> clients receive files that represent resources. These representations must contain enough information to be modified or deleted.</li>
<li><strong>Self-describing messages :</strong> all messages returned to the client contain enough information to describe how the client should handle the information.
<li><strong>Hypermedia as an engine for application state change (HATEOAS) :</strong> after accessing a resource, the REST client must be able to discover all other available actions through hyperlinks.</li>
<li><strong>Cached :</strong> the client must be able to cache the data that the API provides in response, you can check this link for further informations.</li>
<li><strong>Layered system :</strong> communication can take place through intermediate servers (proxy servers or load balancing devices).</li>
<li><strong>Stateless :</strong> no information is stored between two requests and the API treats each request as a first request.</li>
</ul>
Note that in the REST standard, the endpoint must designate an object that we wish to manipulate and the methods must correspond to the following effects
<ul>
<li><code>GET</code> to retrieve information</li>
<li><code>POST</code> to add new data to the server</li>
<li><code>PUT</code> to modify data already on the server</li>
<li><code>DELETE</code> to delete data</li>
</ul>
This standard is not the only one and is not mandatory to implement to get an efficient API but it is probably the most known.
<h3 id="fastapi">FastAPI</h3>
<a href="https://fastapi.tiangolo.com/" target="_blank">FastApi</a> is a modern, fast (high-performance), web framework for building APIs with Python 3.7+ based on standard Python type hints. It is designed to be easy to use, fast to develop with, and provide high performance, making it an excellent choice for building RESTful APIs. Here's a brief overview and key features of FastAPI:
<ol>
<li><strong>Fast: </strong>As the name suggests, FastAPI is designed to be high-performance. It is built on top of <a href="https://www.starlette.io/" target="_blank">Starlette</a> and <a href="https://docs.pydantic.dev/latest/" target="_blank">Pydantic</a>, which contribute to its speed.</li>
<li><strong>Type Annotations: </strong>One of the standout features is the use of Python type hints to define the types of request and response data. This not only serves as documentation but also enables automatic data validation and serialization.</li>
<li><strong>Automatic Documentation: </strong>FastAPI generates <a href="https://www.openapis.org/" target="_blank">OpenAPI</a> and <a href="https://json-schema.org/learn/getting-started-step-by-step" target="_blank">JSON Schema documentation</a> automatically based on your Python type hints.
You can explore and interact with your API using <a href="https://swagger.io/tools/swagger-ui/" target="_blank">Swagger UI</a> or ReDoc.</li>
<li><strong>Asynchronous Support: </strong>FastAPI fully supports asynchronous programming using Python's async and await keywords. This allows for efficient handling of I/O-bound operations.</li>
<li><strong>Dependency Injection System: </strong>FastAPI has a built-in dependency injection system that makes it easy to manage dependencies and share common resources across different parts of your application.</li>
<li><strong>OAuth2 and JWT Authentication: </strong>It provides built-in support for <a href="https://oauth.net/2/" target="_blank">OAuth2</a> and <a href="https://jwt.io/introduction" target="_blank">JWT</a> authentication, making it easier to secure your APIs.</li>
<li><strong>Data Validation and Serialization: </strong>FastAPI uses Pydantic models for data validation and serialization. This allows you to define data models with type hints, and FastAPI will automatically handle validation and serialization/deserialization.</li>
<li><strong>WebSocket Support: </strong> In addition to traditional HTTP APIs, FastAPI supports WebSocket communication, allowing for real-time bidirectional communication.</li>
<li><strong>Cors (Cross-Origin Resource Sharing) Middleware: </strong>FastAPI includes middleware for handling Cross-Origin Resource Sharing, making it easy to control which domains can access your API.</li>
<li><strong>Dependency Injection System: </strong>FastAPI has a sophisticated dependency injection system that simplifies handling dependencies in your API, making your code clean and modular.</li>
</ol>
<h5>Gettign started:</h5>
In this section we will look at the basics of FastAPI. The first step is to install the fastapi and uvicorn libraries. uvicorn is a library that allows you to launch the server created by FastAPI.
<div class="grey-box">
The Python libraries for creating APIs generally use another server to launch the API. For example, you can launch a Flask API without uvicorn but it is generally not recommended (see the launch message).
</div>
<pre class="language-python"><code>pip install fastapi uvicorn</code></pre>
Here's a simple example of a FastAPI application (create <code>main.py</code> file):
<pre class="language-python"><code>
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int, query_param: str = None):
return {"item_id": item_id, "query_param": query_param}
</code></pre>
We can run the app with Uvicorn:
<pre class="language-bash"><code>uvicorn main:app --reload</code></pre>
Visit <a href="https://127.0.0.1:8000" target="_blank">https://127.0.0.1:8000</a> in your browser, and you should see the automatically generated Swagger documentation. In the conolse, the folloing line should be observed:
<pre>INFO: Uvicorn running on http://127.0.0.1:8000(Press CTRL+C to quit)</pre>
This line gives us the address at which the API works.
<p>In another console, issue the following command to query the endpoint <code>/</code>:</p>
<pre class="language-bash"><code>curl -X GET http://127.0.0.1:8000/ </code></pre>
<p>In this section we will see how to use dynamic routing and then how to pass arguments directly into a request. Finally, we will see how FastAPI generates documentation for arguments.</p>
<ol>
<li><strong>Dynamic Routing: </strong>Dynamic routing allows you to generate endpoints automatically. Modify the main.py file by pasting the following lines :
<pre class="language-bash"><code>
from fastapi import FastAPI
users_db = [
{
'user_id': 1,
'name': 'Alice',
'subscription': 'free tier'
},
{
'user_id': 2,
'name': 'Bob',
'subscription': 'premium tier'
},
{
'user_id': 3,
'name': 'Clementine',
'subscription': 'free tier'
}
]
app = FastAPI()
@app.get('/')
def get_index():
return {
'greetings': 'welcome'
}
@app.get('/users')
def get_users():
return users_db
@app.get('/users/{userid:int}')
def get_user(userid):
try:
user = list(filter(lambda x: x.get('user_id') == userid, users_db))[0]
return user
except IndexError:
return {}
@app.get('/users/{userid:int}/name')
def get_user_name(userid):
try:
user = list(filter(lambda x: x.get('user_id') == userid, users_db))[0]
return {'name': user['name']}
except IndexError:
return {}
@app.get('/users/{userid:int}/subscription')
def get_user_suscription(userid):
try:
user = list(filter(lambda x: x.get('user_id') == userid, users_db))[0]
return {'subscription': user['subscription']}
except IndexError:
return {}
</code></pre>
<p>Here <code>users_db</code> is the database and with this code, we want to:</p>
<ul>
<li><code>GET /</code> returns a welcome message</li>
<li><code>GET /users</code> returns the entire database</li>
<li><code>GET /users/userid</code> returns all the data for a user based on its id. userid should be an integer. If the userid provided does not match an existing user, an empty dictionary will be returned.</li>
<li><code>GET /users/userid/name</code> returns the name of a user based on its id. userid should be an integer. If the userid provided does not match an existing user, an empty dictionary will be returned.</li>
<li><code>GET /users/userid/subscription</code> returns the subscription type of a user based on their id. userid should be an integer</li>
</ul>
<p>We notice that the interface to use these requests allows to pass arguments for dynamic routing :</p>
<figure>
<img src="assets/img/data-engineering/fastapi-doc.png" alt="" style="max-width: 90%; max-height: auto;">
<figcaption style="text-align: center;"><strong></strong><a href="" target="_blank"></a></figcaption>
</figure>
<p>We can see below, how dynamic routing works here:</p>
<figure>
<img src="assets/img/data-engineering/fastapi-doc1.png" alt="" style="max-width: 90%; max-height: auto;">
<figcaption style="text-align: center;"><strong></strong><a href="" target="_blank"></a> We need to provide the entries to get the output.</figcaption>
</figure>
</li>
<li><strong>Request string:</strong> We have seen how to pass data to the API using dynamic routing. In this part, we will see how to do it using the query string. FastAPI makes it easy to specify which arguments can be passed via the query string. In the following example, we will define a function that can take an argument <code>argument1</code>. This argument must be passed in the query string.
<pre class="language-bash"><code>
from fastapi import FastAPI
api = FastAPI()
@api.get('/')
def get_index(argument1):
return {
'data': argument1
}
</code></pre>
<p>When using the curl command in the command prompt, we can interact with web servers by sending HTTP requests. Let's break down two scenarios:</p>
<figure>
<img src="assets/img/data-engineering/fastapi-doc2.png" alt="" style="max-width: 90%; max-height: auto;">
<figcaption style="text-align: center;"><strong></strong><a href="" target="_blank"></a> We need to provide the entries to get the output.</figcaption>
</figure>
<p>In the first case, with the command, we're sending a GET request (<code>-X GET</code>) to <span style="color: blue;">http://127.0.0.1:8000/</span> with an additional query parameter <code>argument1</code> set to <code>hello world</code>. The server processes this request and returns the value of the <code>argument1</code> parameter, which in this case is "hello world" (in first case). Whereas in second case, we're sending a GET request to the same server but without any query parameters. However, the server expects the <code>argument1</code> parameter to be present. Since it's missing, the server responds with a <code>422 Unprocessable Entity</code> error. This error indicates that the request couldn't be processed because the required field (<code>argument1</code>) is missing.</p>
<p>We can see this beahviour through the <code>docs/</code> documentation. We need to provide the argument otherwise, when executed it will produce an error. We see in the interface that the <code>argument1</code> field is required. Going down the interface, we can also see the codes that this route can return: 200 if the request succeeds and 422 if the request does not have the required field.</p>
<ul>
<li><strong>Another example:</strong>
<pre class="language-bash"><code>
@app.get('/typed')
def get_typed(argument1: int):
return {
'data': argument1 + 1
}
</code></pre>
This basically gives error, if provide not an integer as argument. However, when provided a strong, it gives our output as <code>{"data" : 123}</code> when <code>argument1 = 123</code>
<figure>
<img src="assets/img/data-engineering/fastapi-doc3.png" alt="" style="max-width: 90%; max-height: auto;">
<figcaption style="text-align: center;"><strong></strong><a href="" target="_blank"></a> We need to provide an integer entry to get the output.</figcaption>
</figure>
</li>
<li><strong>Example on Optional class:</strong> Finally, we can choose to have an optional argument. For this we can use the Optional class of the typing library. However, a default value must be provided.
<pre class="language-bash"><code>
from typing import Optional
@api.get('/addition')
def get_addition(a: int, b: Optional[int]=None):
if b:
result = a + b
else:
result = a + 1
return {
'addition_result': result
}
</code></pre>
where the function takes two parameters: 'a' (an integer) and 'b' (an optional integer), with a default value of 'None'. If 'b' has a value (i.e., it's not 'None'), 'a' and 'b' are added together, and the result is assigned to the variable result. If 'b' is None, 'a' is incremented by '1', and the result is assigned to result.
</li>
</ul>
</li>
<li><strong>Request body: </strong>To pass data to the API, the FastAPI library relies on the use of the <code>BaseModel</code> class from <code>pydantic</code> to specify the form of the query body. We will first create an Item class inherited from the BaseModel class.
<pre class="language-bash"><code>
from fastapi import FastAPI
from typing import Optional
from pydantic import BaseModel
class Item(BaseModel):
itemid: int
description: str
owner: Optional[str] = None
app = FastAPI()
@app.post('/item')
def post_item(item: Item):
return {
'itemid': item.itemid
}
</code></pre>
<p>Here the Item class has the attributes itemid which must be an integer, description which must be a string and owner which is an optional string. We are going to create a route for which we will have to associate a query body containing these attributes. We can open the OpenAPI and inspect the route description <code>POST /item</code>:</p>
<figure>
<img src="assets/img/data-engineering/fastapi-doc4.png" alt="" style="max-width: 90%; max-height: auto;">
<figcaption style="text-align: center;"><strong></strong><a href="" target="_blank"></a> We need to provide an 'Request body' to get the output.</figcaption>
</figure>
We can see that the annotations given here are no longer counted as parameters (arguments to be specified in the query string). On the other hand, we must now specify the request body ("Request body required"). Thanks to the inheritance of the BaseModel class, we could change the interpretation of the annotation by FastAPI. The use of this BaseModel class as a parent class thus allows a route to accept a body. We force the body of the request to respect a certain schema with certain values that can be optional. Moreover, the use of this class allows to ignore fields which are not predefined. Finally, the BaseModel class allows to easily return all the attributes of the body of a query that have been created in JSON format without having to specify this definition. Note that we can use the <code>typing</code> and <code>pydantic</code> libraries to give more complex types to our data. The following example shows a use of these libraries:
<pre class="language-bash"><code>
from pydantic import BaseModel
from typing import Optional, List
class Owner(BaseModel):
name: str
address: str
class Item(BaseModel):
itemid: int
description: str
owner: Optional[Owner] = None
ratings: List[float]
available: bool
</code></pre>
Pydantic also allows to use "exotic" types like http URLs, IP addresses, ... If you want to explore these data types, you can go to this <a href="https://docs.pydantic.dev/latest/concepts/types/" target="_blank">https://docs.pydantic.dev/latest/concepts/types/</a>.
</li>
<li><strong>Headers: </strong>In this part, we will see how to pass data to the server via the request headers. This command can be very useful to pass authentication tokens or to check the content type, the origin of the request, ... For this, we can use the <code>Header</code> class of <code>fastapi</code>. For example, the following function checks the value of <code>User-Agent</code>. This header is used to determine the source of a request :
<pre class="language-bash"><code>
from fastapi import Header
@api.get('/headers')
def get_headers(user_agent=Header(None)):
return {
'User-Agent': user_agent
}
</code></pre>
<figure>
<img src="assets/img/data-engineering/fastapi-doc5.png" alt="" style="max-width: 90%; max-height: auto;">
<figcaption style="text-align: center;"><strong></strong><a href="" target="_blank"></a> We see in this case that the returned user-agent is the browser user-agent.</figcaption>
</figure>
</li>
</ol>
<!----------------------------->
<h4 id="example">Example Fastapi</h4>
In the above case-1 (Dynamic Routing), we have seen the <code>users_db</code>. Now we want to add folloing routes:
<ul>
<code>PUT /users</code> creates a new user in the database and returns the data for the created user. The data about the new user must be provided in the body of the query.
<code>POST /users/userid</code> modifies the data for the user identified by userid and returns the data for the modified user. The data about the user to be modified must be supplied in the body of the request
<code>DELETE /users/userid</code> deletes the user identified by userid and returns a confirmation of the deletion.
</ul>
We will choose to return an empty dictionary in the case of an internal error and we will use a User class inherited from BaseModel.
<figure>
<img src="assets/img/data-engineering/fastapi-doc6.png" alt="" style="max-width: 90%; max-height: auto;">
<figcaption style="text-align: center;"><strong></strong><a href="" target="_blank"></a> We need to provide an integer entry to get the output.</figcaption>
</figure>
The correspodning main.py file is:
<pre><code class="language-bash">
from fastapi import FastAPI
from typing import Optional
from pydantic import BaseModel
users_db = [
{
'user_id': 1,
'name': 'Alice',
'subscription': 'free tier'
},
{
'user_id': 2,
'name': 'Bob',
'subscription': 'premium tier'
},
{
'user_id': 3,
'name': 'Clementine',
'subscription': 'free tier'
}
]
app = FastAPI()
class User(BaseModel):
userid: Optional[int]
name: str
subscription: str
@app.put('/users')
def put_users(user: User):
new_id = max(users_db, key=lambda u: u.get('user_id'))['user_id']
new_user = {
'user_id': new_id + 1,
'name': user.name,
'subscription': user.subscription
}
users_db.append(new_user)
return new_user
@app.post('/users/{userid:int}')
def post_users(user: User, userid):
try:
old_user = list(
filter(lambda x: x.get('user_id') == userid, users_db)
)[0]
users_db.remove(old_user)
old_user['name'] = user.name
old_user['subscription'] = user.subscription
users_db.append(old_user)
return old_user
except IndexError:
return {}
@app.delete('/users/{userid:int}')
def delete_users(userid):
try:
old_user = list(
filter(lambda x: x.get('user_id') == userid, users_db)
)[0]
users_db.remove(old_user)
return {
'userid': userid,
'deleted': True
}
except IndexError:
return {}
</code></pre>
<h5>Conclusion</h5>
<p>FastAPI is a powerful and easy-to-use framework for building APIs with Python. Its combination of type hinting, automatic documentation, and high performance makes it a strong choice for a wide range of API development projects. Whether you're building a small RESTful API or a complex real-time application, FastAPI provides the tools and features to make development efficient and enjoyable.</p>
<!----------------------------------------->
<h4 id="documentaion">FastApi documentation</h4>
<ul>
<li><strong>Customize the documentation of functions: </strong>To add comments to the use of an endpoint, we can use the docstring of the function. We can also give a name to our API via the FastAPI class.
<pre><code class="language-python">
from fastapi import FastAPI
app = FastAPI(
title="My API",
description="My own API powered by FastAPI. Created by <strong>Arun Kumar Pandey.</strong>",
version="1.0.1")
@app.get("/")
def read_root():
"""Returns greetings
"""
return {"Hello": "World"}
</code></pre>
<figure>
<img src="assets/img/data-engineering/fastapi-doc0.png" alt="" style="max-width: 90%; max-height: auto;">
<figcaption style="text-align: center;"><strong></strong><a href="" target="_blank"></a></figcaption>
</figure>
</li>
<ul>
<li>If we provide description of the function as a docstring, the interface automatically shows the description straight from the docstring of the function. We can also add the name argument to the decorator to name the route in OpenAPI: by default, route names are created from the titles of the functions used: <code>Get Index</code> for <code>read_root</code>. For example, we can set decorator name
<pre><code class="language-python">
@api.get('/', name="Hello World")
def get_index():
"""Returns greetings
"""
return {'greetings': 'welcome'}
</code></pre>
<figure>
<img src="assets/img/data-engineering/fastapi-doc-docstring.png" alt="" style="max-width: 90%; max-height: auto;">
<figcaption style="text-align: center;"><strong></strong><a href="" target="_blank"></a></figcaption>
</figure>
</li>
</ul>
<li><strong>Documentation of the function body: </strong> We will now see how FastAPI handles the definition of models from the BaseModel class:
<pre><code class="language-python">
from pydantic import BaseModel
from typing import Optional
class Computer(BaseModel):
computerid: int
cpu: Optional[str]
gpu: Optional[str]
price: float
@app.put('/computer', name='Create a new computer')
def get_computer(computer: Computer):
"""Creates a new computer within the database
"""
return computer
</code></pre>
<figure>
<img src="assets/img/data-engineering/fastapi-doc7.png" alt="" style="max-width: 90%; max-height: auto;">
<figcaption style="text-align: center;"><strong></strong><a href="" target="_blank"></a></figcaption>
</figure>
In the Schemas tab, the description of the Computer class is now available. Here we have also added description on the headers. You can see in the function description that the header is documented.
</li>
<li><strong>Organizing the documentation: </strong>By default, all functions are documented in a default tab. However, you can choose to organize these functions in different parts. To do this, one must specify the tags argument in the decorator.
<pre><code class="language-python">
app = FastAPI(
title="My FastApi",
description="My own API powered by FastAPI. Created by <strong>Arun Kumar Pandey</strong>.",
version="1.0.1",
openapi_tags=[
{
'name': 'home',
'description': 'default functions'
},
{
'name': 'items',
'description': 'functions that are used to deal with items'
}
]
)
@app.get('/', tags=['home'])
def get_index():
"""returns greetings
"""
return {
'greetings': 'hello world'
}
@app.get('/items', tags=['home', 'items'])
def get_items():
"""returns an item
"""
return {
'item': "some item"
}
</code></pre>
Now note down the various parts added here.
<figure>
<img src="assets/img/data-engineering/fastapi-doc8.png" alt="" style="max-width: 90%; max-height: auto;">
<figcaption style="text-align: center;"><strong></strong><a href="" target="_blank"></a></figcaption>
</figure>
The functions are now divided into different parts. The same function can be put in several parts. We could add a description for the different parts using the openapi_tags argument of the FastAPI class constructor. We can also change the address of the OpenAPI and Redoc documentations using the <code>docs_url</code> or <code>redoc_url</code> arguments. If these arguments are set to None, these endpoints are disabled. Finally, one can choose to change the address of the OpenAPI manifest with the <code>openapi_url</code> argument.
<pre><code class="language-python">
app = FastAPI(
# Change the address of the OpenAPI documentation
docs_url="/custom-docs", # Set to the desired URL path, e.g., "/custom-docs"
# Change the address of the ReDoc documentation
redoc_url=None, # Set to None to disable the ReDoc endpoint or specify a custom URL
# Change the address of the OpenAPI manifest
openapi_url="/custom-openapi" # Set to the desired URL path, e.g., "/custom-openapi"
)
</code></pre>
</li>
<li><strong>Using errors: </strong>Errors are an important tool when developing applications: they allow to easily give indications about a bad handling of the application. In particular, we can give information by using the status code of the response but also by giving information in the body of the response. Up to now, we have been able to obtain errors of types 500, 404 and 422. In this part we will see how to create more custom errors. </li>
<pre><code class="language-python">
app = FastAPI()
data = [1, 2, 3, 4, 5]
@app.get('/data')
def get_data(index):
return {
'data': data[int(index)]
}
</code></pre>
<p>If we open the OpenAPI documentation, we can see that two errors are proposed. In this case, we can see that if the value of index is greater than 4 or less than 0, we may get an IndexError. Also, if index is not an integer, we should get a ValueError.</p>
<p>We have also seen that FastAPI generates its own errors for routes not found (404: you can make a GET /nowhere request to see for yourself) or for data formats that do not correspond to the defined expectations (422: in particular via the use of annotations or classes inherited from BaseModel). We will use try-except blocks to catch Python errors and return HTTPException with the associated HTTP codes.</p>
<pre><code class="language-python">
from fastapi import HTTPException
app =FastAPI()
@app.get('/data')
def get_data(index):
try:
return {
'data': data[int(index)]
}
except IndexError:
raise HTTPException(
status_code=404,
detail='Unknown Index')
except ValueError:
raise HTTPException(
status_code=400,
detail='Bad Type'
)
</code></pre>
<p>So we can easily change the error codes and the data returned on error. For the detail argument, we can give a dictionary or any other structure that can be interpreted as a JSON.</p>
<p>Finally, if we want to change the form of the data returned on error, we can create our own exceptions and pass them to the <code>@api.exception_handler</code> decorator.</p>
<pre><code class="language-python">
from fastapi import FastAPI
from fastapi import Request
from fastapi.responses import JSONResponse
import datetime
app = FastAPI()
class MyException(Exception):
def __init__(self,
name : str,
date: str):
self.name = name
self.date = date
@app.exception_handler(MyException)
def MyExceptionHandler(
request: Request,
exception: MyException
):
return JSONResponse(
status_code=418,
content={
'url': str(request.url),
'name': exception.name,
'message': 'This error is my own',
'date': exception.date
}
)
@app.get('/my_custom_exception')
def get_my_custom_exception():
raise MyException(
name='my error',
date=str(datetime.datetime.now())
)
</code></pre>
<p>Let's take some time to describe this code. In the first block, we define a new Exception. We give it the attributes <code>name</code> and <code>date</code>. In the second block, we tell FastAPI how to react when the exception is raised. We give a response of type JSON to return, giving it a <code>status_code</code> and a status. We can then access the attributes of the request or the exception to return them in a JSON. Finally the last block allows us to define a route that generates this error.</p>
</ul>
</section>
<hr>
<!------------------->
<div class="grey-box">
<h3 id="json">JSON: JavaScript Object Notation</h3>
JSON, or JavaScript Object Notation, is a lightweight data-interchange format. It is easy for humans to read and write and easy for machines to parse and generate.
It is widely used for data exchange between a server and a web application (i.e. is used extensively in web applications and APIs), as well as for configuration files and data storage.
<p></p>
<h5>Basics of JSON</h5>
<ol>
<li><strong>Data Structure: </strong>
<ul>
<li>JSON represents data as key-value pairs, similar to a dictionary in Python or an object in JavaScript.</li>
<li>Data is organized in name/value pairs, where the name (a string) is followed by a colon, and the value can be a string, number, boolean, array, or another JSON object.</li>
<pre class="language-json"><code>
{
"name": "John Doe",
"age": 30,
"isStudent": false,
"courses": ["Math", "History", "Science"],
"address": {
"street": "123 Main St",
"city": "Anytown",
"zip": "12345"
}
}
</code></pre>
</ul>
</li>
<li><strong> Data Types: </strong>
JSON data is organized into key-value pairs. Each key-value pair is enclosed in curly braces <code>{}</code>.
The key is a string of characters and the value can be any of the following types:
<ul>
<li><strong>Strings</strong>: Enclosed in double quotes.</li>
<li><strong>Numbers</strong>: Integer or floating-point.</li>
<li><strong>Booleans</strong>: <code>true</code> or <code>false</code>.</li>
<li><strong>Arrays</strong>: Ordered list of values.</li>
<li><strong>null: </strong>A special value that indicates the absence of a value.</li>
<li><strong>Objects</strong>: Unordered collection of key/value pairs.</li>
</ul>
</li>
<li><strong>JSON vs. JavaScript Object: </strong>While JSON syntax resembles JavaScript object syntax, they are not exactly the same. In JSON, keys must be strings,
and strings must be enclosed in double quotes.</li>
</ol>
<h5>Use cases:</h5>
<ol>
<li><strong>Data Exchange: </strong>Commonly used for sending and receiving data between a server and a web application. APIs often return data in JSON format.</li>
<li><strong>Configuration Files: </strong>Used for configuration settings in various applications. Easy to read and write manually.</li>
<li><strong>Storage: </strong>NoSQL databases often use JSON-like formats to store data.</li>
<li><strong>Serialization: </strong>Objects in programming languages can be serialized into JSON for data interchange.</li>
</ol>
<h5>JSON Schema:</h5>
JSON Schema is a vocabulary that allows you to annotate and validate JSON documents. It provides a way to describe the structure of JSON data for documentation, validation, and interaction.
<p>For creating JSON schema from scratch, see the <a href="https://json-schema.org/learn/getting-started-step-by-step" target="_blank">Create a nested data structure</a>.</p>
<strong>Example:</strong> the expected structure and constraints for a JSON object representing information about an individual, particularly someone's personal details, such as a student. Let's break down the schema:
<ol>
<li><strong>Person Details:</strong>
<ul>
<li>The root object represents details about an individual, likely a person.</li>
</ul>
</li>
<li><strong>Name:</strong>
<ul>
<li>The "name" property is expected to be a string, representing the person's name.</li>
</ul>
</li>
<li><strong>Age:</strong>
<ul>
<li>The "age" property is expected to be an integer, representing the person's age.</li>
</ul>
</li>
<li><strong>Student Indicator:</strong>
<ul>
<li>The "isStudent" property is a boolean indicating whether the person is a student or not.</li>
</ul>
</li>
<li><strong>Courses:</strong>
<ul>
<li>The "courses" property is an array of strings, presumably representing the courses the student is enrolled in.</li>
</ul>
</li>
<li><strong>Address:</strong>
<ul>
<li>The "address" property is an object with details about the person's address.</li>
</ul>
</li>
<li><strong>Address Details:</strong>
<ul>
<li>It includes "street," "city," and "zip" properties, all of which are expected to be strings.</li>
<li>These address details are marked as required.</li>
</ul>
</li>
<li><strong>Overall Requirements:</strong>
<ul>
<li>The entire object must have the "name," "age," and "isStudent" properties.</li>
<li>The "address" property is optional, but if present, it must include the required details ("street," "city," and "zip").</li>
</ul>
</li>
</ol>
<pre class="language-json"><code>
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"isStudent": {
"type": "boolean"
},
"courses": {
"type": "array",
"items": {
"type": "string"
}
},
"address": {
"type": "object",
"properties": {
"street": {
"type": "string"
},
"city": {
"type": "string"
},
"zip": {
"type": "string"
}
},
"required": ["street", "city", "zip"]
}
},
"required": ["name", "age", "isStudent"]
}
</code></pre>
This schema defines the expected structure and types of the JSON object. This can be understood as:
<pre class="language-php"><code>
object
├─ name: string
├─ age: integer
├─ isStudent: boolean
├─ courses: array