-
Notifications
You must be signed in to change notification settings - Fork 0
/
mongoDb.html
338 lines (308 loc) · 118 KB
/
mongoDb.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
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta http-equiv="x-ua-compatible" content="ie=edge"/><meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/><meta name="generator" content="Gatsby 5.0.1"/><meta data-react-helmet="true" name="description" content="This tutorial will guide you to build a RESTful API with Node.js, Express, and Mongoose with CRUD functionalities. I expect that you have…"/><meta data-react-helmet="true" name="author" content="Rahman Fadhil"/><meta data-react-helmet="true" property="og:title" content="How to Build a REST API with Express and Mongoose – Rahman Fadhil"/><meta data-react-helmet="true" property="og:description" content="This tutorial will guide you to build a RESTful API with Node.js, Express, and Mongoose with CRUD functionalities. I expect that you have…"/><meta data-react-helmet="true" property="og:type" content="website"/><meta data-react-helmet="true" name="twitter:card" content="summary"/><meta data-react-helmet="true" name="twitter:creator" content="@rahmanfadhil14"/><meta data-react-helmet="true" name="twitter:title" content="How to Build a REST API with Express and Mongoose – Rahman Fadhil"/><meta data-react-helmet="true" name="twitter:description" content="This tutorial will guide you to build a RESTful API with Node.js, Express, and Mongoose with CRUD functionalities. I expect that you have…"/><meta data-react-helmet="true" property="og:image" content="https://rahmanfadhil.com/background.jpg"/><meta name="theme-color" content="#202020"/><style data-href="/styles.b3e92eca545fc6dc89d6.css" data-identity="gatsby-global-css">code[class*=language-],pre[class*=language-]{word-wrap:normal;background:none;color:#f8f8f2;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;-webkit-hyphens:none;hyphens:none;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;text-align:left;text-shadow:0 1px rgba(0,0,0,.3);white-space:pre;word-break:normal;word-spacing:normal}pre[class*=language-]{border-radius:.3em;margin:.5em 0;overflow:auto;padding:1em}:not(pre)>code[class*=language-],pre[class*=language-]{background:#272822}:not(pre)>code[class*=language-]{border-radius:.3em;padding:.1em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#8292a2}.token.punctuation{color:#f8f8f2}.token.namespace{opacity:.7}.token.constant,.token.deleted,.token.property,.token.symbol,.token.tag{color:#f92672}.token.boolean,.token.number{color:#ae81ff}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#a6e22e}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url,.token.variable{color:#f8f8f2}.token.atrule,.token.attr-value,.token.class-name,.token.function{color:#e6db74}.token.keyword{color:#66d9ef}.token.important,.token.regex{color:#fd971f}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}@font-face{font-display:swap;font-family:InterVariable;font-style:normal;font-weight:100 900;src:url(/static/inter-cyrillic-variable-wghtOnly-normal-fbe36d91b8952a12c5926bd6b3957815.woff2) format("woff2");unicode-range:u+0301,u+0400-045f,u+0490-0491,u+04b0-04b1,u+2116}@font-face{font-display:swap;font-family:InterVariable;font-style:normal;font-weight:100 900;src:url(/static/inter-cyrillic-ext-variable-wghtOnly-normal-47734aec6134293ca7911bff88e94930.woff2) format("woff2");unicode-range:u+0460-052f,u+1c80-1c88,u+20b4,u+2de0-2dff,u+a640-a69f,u+fe2e-fe2f}@font-face{font-display:swap;font-family:InterVariable;font-style:normal;font-weight:100 900;src:url(/static/inter-greek-variable-wghtOnly-normal-3a3cf1a02598263f24570303a5e44bf2.woff2) format("woff2");unicode-range:u+0370-03ff}@font-face{font-display:swap;font-family:InterVariable;font-style:normal;font-weight:100 900;src:url(/static/inter-greek-ext-variable-wghtOnly-normal-23292101a34e08657a5d24259bdce837.woff2) format("woff2");unicode-range:u+1f??}@font-face{font-display:swap;font-family:InterVariable;font-style:normal;font-weight:100 900;src:url(/static/inter-latin-variable-wghtOnly-normal-5eb4a7768219776c5b918ca271b2df76.woff2) format("woff2");unicode-range:u+00??,u+0131,u+0152-0153,u+02bb-02bc,u+02c6,u+02da,u+02dc,u+2000-206f,u+2074,u+20ac,u+2122,u+2191,u+2193,u+2212,u+2215,u+feff,u+fffd}@font-face{font-display:swap;font-family:InterVariable;font-style:normal;font-weight:100 900;src:url(/static/inter-latin-ext-variable-wghtOnly-normal-fad2a547f18821b21f1f39621edcc5d2.woff2) format("woff2");unicode-range:u+0100-024f,u+0259,u+1e??,u+2020,u+20a0-20ab,u+20ad-20cf,u+2113,u+2c60-2c7f,u+a720-a7ff}@font-face{font-display:swap;font-family:InterVariable;font-style:normal;font-weight:100 900;src:url(data:font/woff2;base64,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) format("woff2");unicode-range:u+0102-0103,u+0110-0111,u+0128-0129,u+0168-0169,u+01a0-01a1,u+01af-01b0,u+1ea0-1ef9,u+20ab}@font-face{font-display:swap;font-family:JetBrains MonoVariable;font-style:normal;font-weight:100 800;src:url(/static/jetbrains-mono-cyrillic-variable-wghtOnly-normal-0f54aa123292be944cb134e08a87e563.woff2) format("woff2");unicode-range:u+0301,u+0400-045f,u+0490-0491,u+04b0-04b1,u+2116}@font-face{font-display:swap;font-family:JetBrains MonoVariable;font-style:normal;font-weight:100 800;src:url(data:font/woff2;base64,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) format("woff2");unicode-range:u+0460-052f,u+1c80-1c88,u+20b4,u+2de0-2dff,u+a640-a69f,u+fe2e-fe2f}@font-face{font-display:swap;font-family:JetBrains MonoVariable;font-style:normal;font-weight:100 800;src:url(data:font/woff2;base64,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) format("woff2");unicode-range:u+0370-03ff}@font-face{font-display:swap;font-family:JetBrains MonoVariable;font-style:normal;font-weight:100 800;src:url(/static/jetbrains-mono-latin-variable-wghtOnly-normal-cff6856c91237cc1fbb845669bd8f688.woff2) format("woff2");unicode-range:u+00??,u+0131,u+0152-0153,u+02bb-02bc,u+02c6,u+02da,u+02dc,u+2000-206f,u+2074,u+20ac,u+2122,u+2191,u+2193,u+2212,u+2215,u+feff,u+fffd}@font-face{font-display:swap;font-family:JetBrains MonoVariable;font-style:normal;font-weight:100 800;src:url(/static/jetbrains-mono-latin-ext-variable-wghtOnly-normal-b7d1cd88710f29e1484d371af3c92134.woff2) format("woff2");unicode-range:u+0100-024f,u+0259,u+1e??,u+2020,u+20a0-20ab,u+20ad-20cf,u+2113,u+2c60-2c7f,u+a720-a7ff}@font-face{font-display:swap;font-family:JetBrains MonoVariable;font-style:normal;font-weight:100 800;src:url(data:font/woff2;base64,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) format("woff2");unicode-range:u+0102-0103,u+0110-0111,u+0128-0129,u+0168-0169,u+01a0-01a1,u+01af-01b0,u+1ea0-1ef9,u+20ab}
/*
! tailwindcss v3.2.4 | MIT License | https://tailwindcss.com
*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:""}html{-webkit-text-size-adjust:100%;font-feature-settings:normal;font-family:InterVariable,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:Jetbrains MonoVariable,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{color:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{color:#9ca3af;opacity:1}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]{display:none}*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.prose{color:var(--tw-prose-body);max-width:65ch}.prose :where([class~=lead]):not(:where([class~=not-prose] *)){color:var(--tw-prose-lead);font-size:1.25em;line-height:1.6;margin-bottom:1.2em;margin-top:1.2em}.prose :where(a):not(:where([class~=not-prose] *)){color:var(--tw-prose-links);font-weight:500;text-decoration:underline}.prose :where(strong):not(:where([class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.prose :where(a strong):not(:where([class~=not-prose] *)){color:inherit}.prose :where(blockquote strong):not(:where([class~=not-prose] *)){color:inherit}.prose :where(thead th strong):not(:where([class~=not-prose] *)){color:inherit}.prose :where(ol):not(:where([class~=not-prose] *)){list-style-type:decimal;margin-bottom:1.25em;margin-top:1.25em;padding-left:1.625em}.prose :where(ol[type=A]):not(:where([class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a]):not(:where([class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=A s]):not(:where([class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a s]):not(:where([class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=I]):not(:where([class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i]):not(:where([class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type=I s]):not(:where([class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i s]):not(:where([class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type="1"]):not(:where([class~=not-prose] *)){list-style-type:decimal}.prose :where(ul):not(:where([class~=not-prose] *)){list-style-type:disc;margin-bottom:1.25em;margin-top:1.25em;padding-left:1.625em}.prose :where(ol>li):not(:where([class~=not-prose] *))::marker{color:var(--tw-prose-counters);font-weight:400}.prose :where(ul>li):not(:where([class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.prose :where(hr):not(:where([class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-bottom:3em;margin-top:3em}.prose :where(blockquote):not(:where([class~=not-prose] *)){border-left-color:var(--tw-prose-quote-borders);border-left-width:.25rem;color:var(--tw-prose-quotes);font-style:italic;font-weight:500;margin-bottom:1.6em;margin-top:1.6em;padding-left:1em;quotes:"\201C""\201D""\2018""\2019"}.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose] *)):before{content:open-quote}.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose] *)):after{content:close-quote}.prose :where(h1):not(:where([class~=not-prose] *)){color:var(--tw-prose-headings);font-size:2.25em;font-weight:800;line-height:1.1111111;margin-bottom:.8888889em;margin-top:0}.prose :where(h1 strong):not(:where([class~=not-prose] *)){color:inherit;font-weight:900}.prose :where(h2):not(:where([class~=not-prose] *)){color:var(--tw-prose-headings);font-size:1.5em;font-weight:700;line-height:1.3333333;margin-bottom:1em;margin-top:2em}.prose :where(h2 strong):not(:where([class~=not-prose] *)){color:inherit;font-weight:800}.prose :where(h3):not(:where([class~=not-prose] *)){color:var(--tw-prose-headings);font-size:1.25em;font-weight:600;line-height:1.6;margin-bottom:.6em;margin-top:1.6em}.prose :where(h3 strong):not(:where([class~=not-prose] *)){color:inherit;font-weight:700}.prose :where(h4):not(:where([class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;line-height:1.5;margin-bottom:.5em;margin-top:1.5em}.prose :where(h4 strong):not(:where([class~=not-prose] *)){color:inherit;font-weight:700}.prose :where(img):not(:where([class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose :where(figure>*):not(:where([class~=not-prose] *)){margin-bottom:0;margin-top:0}.prose :where(figcaption):not(:where([class~=not-prose] *)){color:var(--tw-prose-captions);font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.prose :where(code):not(:where([class~=not-prose] *)){color:var(--tw-prose-code);font-size:.875em;font-weight:600}.prose :where(code):not(:where([class~=not-prose] *)):before{content:"`"}.prose :where(code):not(:where([class~=not-prose] *)):after{content:"`"}.prose :where(a code):not(:where([class~=not-prose] *)){color:inherit}.prose :where(h1 code):not(:where([class~=not-prose] *)){color:inherit}.prose :where(h2 code):not(:where([class~=not-prose] *)){color:inherit;font-size:.875em}.prose :where(h3 code):not(:where([class~=not-prose] *)){color:inherit;font-size:.9em}.prose :where(h4 code):not(:where([class~=not-prose] *)){color:inherit}.prose :where(blockquote code):not(:where([class~=not-prose] *)){color:inherit}.prose :where(thead th code):not(:where([class~=not-prose] *)){color:inherit}.prose :where(pre):not(:where([class~=not-prose] *)){background-color:var(--tw-prose-pre-bg);border-radius:.375rem;color:var(--tw-prose-pre-code);font-size:.875em;font-weight:400;line-height:1.7142857;margin-bottom:1.7142857em;margin-top:1.7142857em;overflow-x:auto;padding:.8571429em 1.1428571em}.prose :where(pre code):not(:where([class~=not-prose] *)){background-color:transparent;border-radius:0;border-width:0;color:inherit;font-family:inherit;font-size:inherit;font-weight:inherit;line-height:inherit;padding:0}.prose :where(pre code):not(:where([class~=not-prose] *)):before{content:none}.prose :where(pre code):not(:where([class~=not-prose] *)):after{content:none}.prose :where(table):not(:where([class~=not-prose] *)){font-size:.875em;line-height:1.7142857;margin-bottom:2em;margin-top:2em;table-layout:auto;text-align:left;width:100%}.prose :where(thead):not(:where([class~=not-prose] *)){border-bottom-color:var(--tw-prose-th-borders);border-bottom-width:1px}.prose :where(thead th):not(:where([class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;padding-bottom:.5714286em;padding-left:.5714286em;padding-right:.5714286em;vertical-align:bottom}.prose :where(tbody tr):not(:where([class~=not-prose] *)){border-bottom-color:var(--tw-prose-td-borders);border-bottom-width:1px}.prose :where(tbody tr:last-child):not(:where([class~=not-prose] *)){border-bottom-width:0}.prose :where(tbody td):not(:where([class~=not-prose] *)){vertical-align:baseline}.prose :where(tfoot):not(:where([class~=not-prose] *)){border-top-color:var(--tw-prose-th-borders);border-top-width:1px}.prose :where(tfoot td):not(:where([class~=not-prose] *)){vertical-align:top}.prose{--tw-prose-body:#374151;--tw-prose-headings:#111827;--tw-prose-lead:#4b5563;--tw-prose-links:#111827;--tw-prose-bold:#111827;--tw-prose-counters:#6b7280;--tw-prose-bullets:#d1d5db;--tw-prose-hr:#e5e7eb;--tw-prose-quotes:#111827;--tw-prose-quote-borders:#e5e7eb;--tw-prose-captions:#6b7280;--tw-prose-code:#111827;--tw-prose-pre-code:#e5e7eb;--tw-prose-pre-bg:#1f2937;--tw-prose-th-borders:#d1d5db;--tw-prose-td-borders:#e5e7eb;--tw-prose-invert-body:#d1d5db;--tw-prose-invert-headings:#fff;--tw-prose-invert-lead:#9ca3af;--tw-prose-invert-links:#fff;--tw-prose-invert-bold:#fff;--tw-prose-invert-counters:#9ca3af;--tw-prose-invert-bullets:#4b5563;--tw-prose-invert-hr:#374151;--tw-prose-invert-quotes:#f3f4f6;--tw-prose-invert-quote-borders:#374151;--tw-prose-invert-captions:#9ca3af;--tw-prose-invert-code:#fff;--tw-prose-invert-pre-code:#d1d5db;--tw-prose-invert-pre-bg:rgba(0,0,0,.5);--tw-prose-invert-th-borders:#4b5563;--tw-prose-invert-td-borders:#374151;font-size:1rem;line-height:1.75}.prose :where(p):not(:where([class~=not-prose] *)){margin-bottom:1.25em;margin-top:1.25em}.prose :where(video):not(:where([class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose :where(figure):not(:where([class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose :where(li):not(:where([class~=not-prose] *)){margin-bottom:.5em;margin-top:.5em}.prose :where(ol>li):not(:where([class~=not-prose] *)){padding-left:.375em}.prose :where(ul>li):not(:where([class~=not-prose] *)){padding-left:.375em}.prose :where(.prose>ul>li p):not(:where([class~=not-prose] *)){margin-bottom:.75em;margin-top:.75em}.prose :where(.prose>ul>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ul>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.25em}.prose :where(.prose>ol>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ol>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.25em}.prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose] *)){margin-bottom:.75em;margin-top:.75em}.prose :where(hr+*):not(:where([class~=not-prose] *)){margin-top:0}.prose :where(h2+*):not(:where([class~=not-prose] *)){margin-top:0}.prose :where(h3+*):not(:where([class~=not-prose] *)){margin-top:0}.prose :where(h4+*):not(:where([class~=not-prose] *)){margin-top:0}.prose :where(thead th:first-child):not(:where([class~=not-prose] *)){padding-left:0}.prose :where(thead th:last-child):not(:where([class~=not-prose] *)){padding-right:0}.prose :where(tbody td,tfoot td):not(:where([class~=not-prose] *)){padding:.5714286em}.prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose] *)){padding-left:0}.prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose] *)){padding-right:0}.prose :where(.prose>:first-child):not(:where([class~=not-prose] *)){margin-top:0}.prose :where(.prose>:last-child):not(:where([class~=not-prose] *)){margin-bottom:0}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{bottom:0;left:0;right:0;top:0}.top-0{top:0}.left-0{left:0}.bottom-0{bottom:0}.top-3{top:.75rem}.right-3{right:.75rem}.z-10{z-index:10}.mx-auto{margin-left:auto;margin-right:auto}.my-8{margin-bottom:2rem;margin-top:2rem}.mt-3{margin-top:.75rem}.mb-8{margin-bottom:2rem}.mt-2{margin-top:.5rem}.mb-4{margin-bottom:1rem}.mt-8{margin-top:2rem}.mb-16{margin-bottom:4rem}.mt-4{margin-top:1rem}.mb-2{margin-bottom:.5rem}.mt-24{margin-top:6rem}.-mt-12{margin-top:-3rem}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.aspect-video{aspect-ratio:16/9}.h-5{height:1.25rem}.h-6{height:1.5rem}.w-full{width:100%}.w-5{width:1.25rem}.w-6{width:1.5rem}.max-w-xs{max-width:20rem}.max-w-screen-sm{max-width:640px}.max-w-screen-md{max-width:768px}.max-w-md{max-width:28rem}.max-w-lg{max-width:32rem}.max-w-sm{max-width:24rem}.grow{flex-grow:1}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-stretch{align-items:stretch}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-8{gap:2rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.gap-y-3{row-gap:.75rem}.gap-x-5{-moz-column-gap:1.25rem;column-gap:1.25rem}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-bottom-width:calc(1px*var(--tw-divide-y-reverse));border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)))}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-lg{border-radius:.5rem}.rounded-full{border-radius:9999px}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-t{border-top-width:1px}.bg-sky-600{--tw-bg-opacity:1;background-color:rgb(2 132 199/var(--tw-bg-opacity))}.bg-slate-200{--tw-bg-opacity:1;background-color:rgb(226 232 240/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity))}.bg-opacity-50{--tw-bg-opacity:0.5}.p-5{padding:1.25rem}.p-4{padding:1rem}.py-8{padding-bottom:2rem;padding-top:2rem}.px-8{padding-left:2rem;padding-right:2rem}.py-3{padding-bottom:.75rem;padding-top:.75rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.px-4{padding-left:1rem;padding-right:1rem}.pb-8{padding-bottom:2rem}.text-center{text-align:center}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-2xl{font-size:1.5rem;line-height:2rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.font-extrabold{font-weight:800}.font-medium{font-weight:500}.font-black{font-weight:900}.font-bold{font-weight:700}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.leading-relaxed{line-height:1.625}.tracking-wider{letter-spacing:.05em}.text-slate-800{--tw-text-opacity:1;color:rgb(30 41 59/var(--tw-text-opacity))}.text-slate-600{--tw-text-opacity:1;color:rgb(71 85 105/var(--tw-text-opacity))}.text-sky-600{--tw-text-opacity:1;color:rgb(2 132 199/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.shadow{--tw-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1);--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}body{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.link{color:rgb(2 132 199/var(--tw-text-opacity));font-weight:500;text-decoration-line:underline}.link,.link:hover{--tw-text-opacity:1}.link:hover{color:rgb(3 105 161/var(--tw-text-opacity))}.code-title{--tw-bg-opacity:1;--tw-text-opacity:1;background-color:rgb(39 40 34/var(--tw-bg-opacity));border-top-left-radius:.375rem;border-top-right-radius:.375rem;color:rgb(255 255 255/var(--tw-text-opacity));font-size:.875rem;font-weight:500;line-height:1.25rem;line-height:1.625;margin-bottom:-1.5rem;margin-top:1.5rem;padding:.75rem 1rem}.code-title+.gatsby-highlight pre[class*=language-]{--tw-border-opacity:1;border-color:rgb(72 73 62/var(--tw-border-opacity));border-top-left-radius:0;border-top-right-radius:0;border-top-width:1px}pre[class*=language-]{border-radius:.375rem;margin-bottom:1.5rem;margin-top:1.5rem;padding:1rem}code[class*=language-],pre[class*=language-]{font-family:Jetbrains MonoVariable,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-size:.875rem;line-height:1.25rem;line-height:1.625}.after\:absolute:after{content:var(--tw-content);position:absolute}.after\:inset-0:after{bottom:0;content:var(--tw-content);left:0;right:0;top:0}.after\:block:after{content:var(--tw-content);display:block}.hover\:border-slate-300:hover{--tw-border-opacity:1;border-color:rgb(203 213 225/var(--tw-border-opacity))}.hover\:bg-sky-700:hover{--tw-bg-opacity:1;background-color:rgb(3 105 161/var(--tw-bg-opacity))}.hover\:bg-slate-300:hover{--tw-bg-opacity:1;background-color:rgb(203 213 225/var(--tw-bg-opacity))}.hover\:text-sky-700:hover{--tw-text-opacity:1;color:rgb(3 105 161/var(--tw-text-opacity))}.hover\:text-sky-600:hover{--tw-text-opacity:1;color:rgb(2 132 199/var(--tw-text-opacity))}.focus\:border-transparent:focus{border-color:transparent}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-sky-600:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(2 132 199/var(--tw-ring-opacity))}.focus\:ring-slate-600:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(71 85 105/var(--tw-ring-opacity))}.focus\:ring-offset-2:focus{--tw-ring-offset-width:2px}@media (min-width:640px){.sm\:w-auto{width:auto}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:gap-4{gap:1rem}.sm\:gap-y-16{row-gap:4rem}.sm\:py-16{padding-bottom:4rem;padding-top:4rem}.sm\:text-4xl{font-size:2.25rem;line-height:2.5rem}.sm\:text-base{font-size:1rem;line-height:1.5rem}.sm\:text-3xl{font-size:1.875rem;line-height:2.25rem}.sm\:text-2xl{font-size:1.5rem;line-height:2rem}}@media (min-width:768px){.md\:order-2{order:2}.md\:flex{display:flex}.md\:hidden{display:none}.md\:max-w-screen-md{max-width:768px}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:items-start{align-items:flex-start}.md\:gap-y-16{row-gap:4rem}.md\:gap-x-8{-moz-column-gap:2rem;column-gap:2rem}.md\:py-16{padding-bottom:4rem;padding-top:4rem}.md\:py-6{padding-bottom:1.5rem;padding-top:1.5rem}.md\:px-4{padding-left:1rem;padding-right:1rem}.md\:px-0{padding-left:0;padding-right:0}.md\:py-8{padding-bottom:2rem;padding-top:2rem}.md\:text-5xl{font-size:3rem;line-height:1}.md\:text-lg{font-size:1.125rem;line-height:1.75rem}}@media (min-width:1024px){.lg\:max-w-screen-lg{max-width:1024px}}</style><title data-react-helmet="true">How to Build a REST API with Express and Mongoose – Rahman Fadhil</title><style>.gatsby-image-wrapper{position:relative;overflow:hidden}.gatsby-image-wrapper picture.object-fit-polyfill{position:static!important}.gatsby-image-wrapper img{bottom:0;height:100%;left:0;margin:0;max-width:none;padding:0;position:absolute;right:0;top:0;width:100%;object-fit:cover}.gatsby-image-wrapper [data-main-image]{opacity:0;transform:translateZ(0);transition:opacity .25s linear;will-change:opacity}.gatsby-image-wrapper-constrained{display:inline-block;vertical-align:top}</style><noscript><style>.gatsby-image-wrapper noscript [data-main-image]{opacity:1!important}.gatsby-image-wrapper [data-placeholder-image]{opacity:0!important}</style></noscript><script type="module">const e="undefined"!=typeof HTMLImageElement&&"loading"in HTMLImageElement.prototype;e&&document.body.addEventListener("load",(function(e){const t=e.target;if(void 0===t.dataset.mainImage)return;if(void 0===t.dataset.gatsbyImageSsr)return;let a=null,n=t;for(;null===a&&n;)void 0!==n.parentNode.dataset.gatsbyImageWrapper&&(a=n.parentNode),n=n.parentNode;const o=a.querySelector("[data-placeholder-image]"),r=new Image;r.src=t.currentSrc,r.decode().catch((()=>{})).then((()=>{t.style.opacity=1,o&&(o.style.opacity=0,o.style.transition="opacity 500ms linear")}))}),!0);</script><link rel="icon" href="/favicon-32x32.png?v=88c156472c4017ff30505dbb5cf8bafe" type="image/png"/><link rel="manifest" href="/manifest.webmanifest" crossorigin="anonymous"/><link rel="apple-touch-icon" sizes="48x48" href="/icons/icon-48x48.png?v=88c156472c4017ff30505dbb5cf8bafe"/><link rel="apple-touch-icon" sizes="72x72" href="/icons/icon-72x72.png?v=88c156472c4017ff30505dbb5cf8bafe"/><link rel="apple-touch-icon" sizes="96x96" href="/icons/icon-96x96.png?v=88c156472c4017ff30505dbb5cf8bafe"/><link rel="apple-touch-icon" sizes="144x144" href="/icons/icon-144x144.png?v=88c156472c4017ff30505dbb5cf8bafe"/><link rel="apple-touch-icon" sizes="192x192" href="/icons/icon-192x192.png?v=88c156472c4017ff30505dbb5cf8bafe"/><link rel="apple-touch-icon" sizes="256x256" href="/icons/icon-256x256.png?v=88c156472c4017ff30505dbb5cf8bafe"/><link rel="apple-touch-icon" sizes="384x384" href="/icons/icon-384x384.png?v=88c156472c4017ff30505dbb5cf8bafe"/><link rel="apple-touch-icon" sizes="512x512" href="/icons/icon-512x512.png?v=88c156472c4017ff30505dbb5cf8bafe"/><style type="text/css">
.anchor.before {
position: absolute;
top: 0;
left: 0;
transform: translateX(-100%);
padding-right: 4px;
}
.anchor.after {
display: inline-block;
padding-left: 4px;
}
h1 .anchor svg,
h2 .anchor svg,
h3 .anchor svg,
h4 .anchor svg,
h5 .anchor svg,
h6 .anchor svg {
visibility: hidden;
}
h1:hover .anchor svg,
h2:hover .anchor svg,
h3:hover .anchor svg,
h4:hover .anchor svg,
h5:hover .anchor svg,
h6:hover .anchor svg,
h1 .anchor:focus svg,
h2 .anchor:focus svg,
h3 .anchor:focus svg,
h4 .anchor:focus svg,
h5 .anchor:focus svg,
h6 .anchor:focus svg {
visibility: visible;
}
</style><script>
document.addEventListener("DOMContentLoaded", function(event) {
var hash = window.decodeURI(location.hash.replace('#', ''))
if (hash !== '') {
var element = document.getElementById(hash)
if (element) {
var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
var clientTop = document.documentElement.clientTop || document.body.clientTop || 0
var offset = element.getBoundingClientRect().top + scrollTop - clientTop
// Wait for the browser to finish rendering before scrolling.
setTimeout((function() {
window.scrollTo(0, offset - 0)
}), 0)
}
}
})
</script><link rel="sitemap" type="application/xml" href="/sitemap-index.xml"/><link rel="preconnect" href="https://www.google-analytics.com"/><link rel="dns-prefetch" href="https://www.google-analytics.com"/></head><body><div id="___gatsby"><div style="outline:none" tabindex="-1" id="gatsby-focus-wrapper"><div class="border-b bg-white"><div class="md:max-w-screen-md lg:max-w-screen-lg mx-auto md:py-6 md:px-4 flex justify-between items-center"><a class="font-bold text-lg text-slate-800 px-5 md:px-0" aria-label="Go to home" href="/">rahman<span class="text-sky-600">fadhil</span></a><button class="block md:hidden p-5"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" class="w-6 h-6"><path fill-rule="evenodd" d="M3 6.75A.75.75 0 013.75 6h16.5a.75.75 0 010 1.5H3.75A.75.75 0 013 6.75zM3 12a.75.75 0 01.75-.75h16.5a.75.75 0 010 1.5H3.75A.75.75 0 013 12zm8.25 5.25a.75.75 0 01.75-.75h8.25a.75.75 0 010 1.5H12a.75.75 0 01-.75-.75z" clip-rule="evenodd"></path></svg></button><div class="hidden md:flex items-center gap-8"><a class="font-semibold text-sm text-slate-800 hover:text-sky-600" href="/">Home</a><a class="font-semibold text-sm text-slate-800 hover:text-sky-600" href="/about/">About</a><a class="font-semibold text-sm text-slate-800 hover:text-sky-600" href="/contact/">Contact</a><a class="font-semibold text-sm text-slate-800 hover:text-sky-600" href="/blog/">Blog</a><a class="font-semibold text-sm text-slate-800 hover:text-sky-600" href="/videos/">Courses</a><a class="font-semibold text-sm text-slate-800 hover:text-sky-600" href="/portfolio/">Portfolio</a></div><div style="position:fixed;top:1px;left:1px;width:1px;height:0;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0;display:none"></div></div></div><div class="md:max-w-screen-md lg:max-w-screen-lg mx-auto px-5 py-8 sm:py-16"><div class="md:py-8"><div class="prose mx-auto pb-8 border-b"><h1>How to Build a REST API with Express and Mongoose</h1><p>Updated at August 24, 2020</p></div><div class="prose mx-auto my-8"><p>This tutorial will guide you to build a RESTful API with Node.js, Express, and Mongoose with CRUD functionalities. I expect that you have the basic knowledge of Node.js and JavaScript. If you do, you're good to go!</p>
<h2 id="prerequisites" style="position:relative;"><a href="#prerequisites" aria-label="prerequisites permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Prerequisites</h2>
<p>These software need to be installed on your machine first:</p>
<ul>
<li><a href="https://nodejs.org">Node.js</a></li>
<li><a href="https://mongodb.com">MongoDB</a></li>
</ul>
<h2 id="getting-started" style="position:relative;"><a href="#getting-started" aria-label="getting started permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Getting Started</h2>
<p>The only thing we need to get started with this project is a blank folder with npm package initialized. So, let's create one!</p>
<div class="gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">$ mkdir learn-express
$ cd learn-express
$ npm init -y</code></pre></div>
<p>Now, let's install some useful packages.</p>
<div class="gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">$ npm install express mongoose</code></pre></div>
<p>Here, we're installing <a href="https://expressjs.com">Express</a> for our web framework and <a href="https://mongoosejs.com">mongoose</a> to interact with our MongoDB database.</p>
<p>I also have published the source-code of this entire project on my <a href="https://github.com/rahmanfadhil/learn-express-mongoose.git">GitHub</a>. Go ahead and clone this into your computer.</p>
<h2 id="basic-express-server" style="position:relative;"><a href="#basic-express-server" aria-label="basic express server permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Basic Express Server</h2>
<p>We can now start to create <code>index.js</code> and create a simple Express server.</p>
<div class="code-title">index.js</div>
<div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> express <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"express"</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">express</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
app<span class="token punctuation">.</span><span class="token function">listen</span><span class="token punctuation">(</span><span class="token number">5000</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Server has started!"</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div>
<p>We first import our <code>express</code> package that we've just installed. Then, create a new express instance and put it into <code>app</code> variable. This <code>app</code> variable let us do everything we need to configure our REST API, like registering our routes, installing necessary middlewares, and much more.</p>
<p>Try to run our server by running this command below.</p>
<div class="gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">$ node index.js
Server has started!</code></pre></div>
<p>Alternatively, we can setup a new npm script to make our workflow much more easier.</p>
<div class="code-title">package.json</div>
<div class="gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
<span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"start"</span><span class="token operator">:</span> <span class="token string">"node index.js"</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre></div>
<p>Then, we can run our server by executing <code>npm start</code>.</p>
<div class="gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">$ npm start
Server has started!</code></pre></div>
<h2 id="setup-mongoose" style="position:relative;"><a href="#setup-mongoose" aria-label="setup mongoose permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Setup mongoose</h2>
<p>Mongoose is the most preferred MongoDB wrapper for Node.js. It allows us to interact with MongoDB database with ease. We can start connecting our server into our MongoDB database.</p>
<div class="code-title">index.js</div>
<div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> express <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"express"</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> mongoose <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"mongoose"</span><span class="token punctuation">)</span> <span class="token comment">// new</span>
<span class="token comment">// Connect to MongoDB database</span>
mongoose
<span class="token punctuation">.</span><span class="token function">connect</span><span class="token punctuation">(</span><span class="token string">"mongodb://localhost:27017/acmedb"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">useNewUrlParser</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">express</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
app<span class="token punctuation">.</span><span class="token function">listen</span><span class="token punctuation">(</span><span class="token number">5000</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Server has started!"</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div>
<p>Here, we're importing <code>mongoose</code> package and use it to connect into our database called <code>acmedb</code>, but you can name it whatever you want though. If you haven't created that database, don't worry, mongoose will create it for ya.</p>
<p>The connect method returns a promise, so we can wait until it resolved, and run our Express server.</p>
<p>Run the server again, and make sure there is no error.</p>
<div class="gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">$ npm start
Server has started!</code></pre></div>
<p>Now, we have successfully connect our server with the database, now it's time to create our first model.</p>
<h2 id="mongoose-model" style="position:relative;"><a href="#mongoose-model" aria-label="mongoose model permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Mongoose model</h2>
<p>In NoSQL world, every single data stored inside a single document. And multiple documents with the same type can be put together inside a collection.</p>
<p>Model is a class, that lets us interact with a specific collection of a database.</p>
<p>Defining a model also requires us to define a schema. Schema is basically tells the model how our document should look like. Even though in NoSQL world, the document schema is flexible, mongoose helps us to keep our data more consistent.</p>
<p>Let's say we have a blog API. So, we obviously going to have a <code>Post</code> model. And the post model has a schema that contains the fields that can be added into a single document. For this example, we will simply have a <code>title</code> and <code>content</code> field.</p>
<p>So, let's add a new folder in our project called <code>models</code>, and create a file called <code>Post.js</code> inside it.</p>
<div class="code-title">models/Post.js</div>
<div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> mongoose <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"mongoose"</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> schema <span class="token operator">=</span> mongoose<span class="token punctuation">.</span><span class="token function">Schema</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
<span class="token literal-property property">title</span><span class="token operator">:</span> String<span class="token punctuation">,</span>
<span class="token literal-property property">content</span><span class="token operator">:</span> String<span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
module<span class="token punctuation">.</span>exports <span class="token operator">=</span> mongoose<span class="token punctuation">.</span><span class="token function">model</span><span class="token punctuation">(</span><span class="token string">"Post"</span><span class="token punctuation">,</span> schema<span class="token punctuation">)</span></code></pre></div>
<p>Here, we're constructing a schema with <code>mongoose.Schema</code>, and define the fields as well as the data types. Then, we create a new model by using the <code>mongoose.model</code> based on the schema that we've just created.</p>
<h2 id="get-all-posts" style="position:relative;"><a href="#get-all-posts" aria-label="get all posts permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Get all posts</h2>
<p>Here, we can create a new file called <code>routes.js</code> which will contains our Express routes.</p>
<div class="code-title">routes.js</div>
<div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> express <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"express"</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> router <span class="token operator">=</span> express<span class="token punctuation">.</span><span class="token function">Router</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
module<span class="token punctuation">.</span>exports <span class="token operator">=</span> router</code></pre></div>
<p>We also need to import <code>express</code> but this time, we want to use the <code>express.Router</code>. It lets us register the routes and use it in our application (in <code>index.js</code>).</p>
<p>Now, we're ready to create our first route in Express that actually do something!</p>
<p>Let's create a route that can get a list of the existing posts.</p>
<div class="code-title">routes.js</div>
<div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> express <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"express"</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> Post <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"./models/Post"</span><span class="token punctuation">)</span> <span class="token comment">// new</span>
<span class="token keyword">const</span> router <span class="token operator">=</span> express<span class="token punctuation">.</span><span class="token function">Router</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token comment">// Get all posts</span>
router<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">"/posts"</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> posts <span class="token operator">=</span> <span class="token keyword">await</span> Post<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
res<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span>posts<span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
module<span class="token punctuation">.</span>exports <span class="token operator">=</span> router</code></pre></div>
<p>Here, we're importing the <code>Post</code> model and create a new <code>GET</code> route with <code>router.get</code> method. This method will accept the endpoint of the route, and the route handler to define what data should be sent to the client. In this case, we're going to fetch all of our posts with the <code>find</code> from our model and send the result with <code>res.send</code> method.</p>
<p>Because fetching documents from the database is asynchronous, we need to use <code>await</code> to wait until the operation is finished. So, don't forget to tag your function as <code>async</code>. Then, after the data is completely fetched, we can send it to the client.</p>
<p>Now, we can install our routes in our <code>index.js</code>.</p>
<div class="code-title">index.js</div>
<div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> express <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"express"</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> mongoose <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"mongoose"</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> routes <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"./routes"</span><span class="token punctuation">)</span> <span class="token comment">// new</span>
mongoose
<span class="token punctuation">.</span><span class="token function">connect</span><span class="token punctuation">(</span><span class="token string">"mongodb://localhost:27017/acmedb"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">useNewUrlParser</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">express</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
app<span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span><span class="token string">"/api"</span><span class="token punctuation">,</span> routes<span class="token punctuation">)</span> <span class="token comment">// new</span>
app<span class="token punctuation">.</span><span class="token function">listen</span><span class="token punctuation">(</span><span class="token number">5000</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Server has started!"</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div>
<p>First, we import the <code>./routes.js</code> file to get all the routes, and register it with <code>app.use</code> method with the prefix of <code>/api</code>, So, all of our posts can be accessed in <code>/api/posts</code>.</p>
<p>Try to run our server and fetch <code>/api/posts</code>, let's see what we got.</p>
<div class="gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">$ curl http://localhost:5000/api/posts
[]</code></pre></div>
<p>Now, we got an empty array from our server. That's because we haven't create any post yet. So, why not create one?</p>
<h2 id="create-post" style="position:relative;"><a href="#create-post" aria-label="create post permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Create Post</h2>
<p>To create a post, we need to accept <code>POST</code> requests from <code>/api/posts</code>.</p>
<div class="code-title">routes.js</div>
<div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token comment">// ...</span>
router<span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string">"/posts"</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> post <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Post</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
<span class="token literal-property property">title</span><span class="token operator">:</span> req<span class="token punctuation">.</span>body<span class="token punctuation">.</span>title<span class="token punctuation">,</span>
<span class="token literal-property property">content</span><span class="token operator">:</span> req<span class="token punctuation">.</span>body<span class="token punctuation">.</span>content<span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">await</span> post<span class="token punctuation">.</span><span class="token function">save</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
res<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span>post<span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div>
<p>Here, we're creating a new <code>Post</code> object and populate the fields from the <code>req.body</code> property. The <code>req</code> object contains the client request data, and the body is one of them.</p>
<p>Then, we also need to save our record with the <code>save</code> method. Saving data is also asynchronous, so we need to use async/await syntax.</p>
<p>By default, Express doesn't know how to read the request body. So, we need to add a middleware to be able to parse them in every single request. That way, our request body will be available in our route handlers via <code>req.body</code>.</p>
<div class="code-title">index.js</div>
<div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> express <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"express"</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> mongoose <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"mongoose"</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> routes <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"./routes"</span><span class="token punctuation">)</span>
mongoose
<span class="token punctuation">.</span><span class="token function">connect</span><span class="token punctuation">(</span><span class="token string">"mongodb://localhost:27017/acmedb"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">useNewUrlParser</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">express</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
app<span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span>express<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// new</span>
app<span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span><span class="token string">"/api"</span><span class="token punctuation">,</span> routes<span class="token punctuation">)</span>
app<span class="token punctuation">.</span><span class="token function">listen</span><span class="token punctuation">(</span><span class="token number">5000</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Server has started!"</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div>
<p>Let's test the create post feature that we have just created!</p>
<div class="gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">$ curl http://localhost:5000/api/posts \
-X POST \
-H "Content-Type: application/json" \
-d '{"title":"Post 1", "content":"Lorem ipsum"}'
{
"_v": 0,
"_id": <OBJECT_ID>,
"title": "Post 1",
"content": "Lorem ipsum"
}</code></pre></div>
<!-- You also can test it with [Postman](https://www.getpostman.com) as well. -->
<!-- TODO: image with postman -->
<h2 id="get-individual-post" style="position:relative;"><a href="#get-individual-post" aria-label="get individual post permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Get individual post</h2>
<p>To grab the individual post, we need to create a new route with <code>GET</code> method.</p>
<div class="code-title">routes.js</div>
<div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token comment">// ...</span>
router<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">"/posts/:id"</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> post <span class="token operator">=</span> <span class="token keyword">await</span> Post<span class="token punctuation">.</span><span class="token function">findOne</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">_id</span><span class="token operator">:</span> req<span class="token punctuation">.</span>params<span class="token punctuation">.</span>id <span class="token punctuation">}</span><span class="token punctuation">)</span>
res<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span>post<span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div>
<p>Here, we're registering a new route with the endpoint of <code>/posts/:id</code>. This is called the URL parameter, it lets us grab the <code>id</code> of our post in our route handler. Because, every single document that we stored into our database has their own uniqe identifier called <code>ObjectID</code>. And we can find it using the <code>findOne</code> method and pass the id from <code>req.params</code> object.</p>
<p>Cool, now try to fetch a single blog post with our HTTP client.</p>
<div class="gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">$ curl http://localhost:5000/api/posts/<OBJECT_ID>
{
"_id": <OBJECT_ID>,
"title": "Post 1",
"content": "Lorem ipsum"
}</code></pre></div>
<p>Looks like its working, but there is one thing though.</p>
<p>If we to the this route and pass the wrong ObjectID, our server is crashed. And the reason why its not working is because when we fetch a single post with an ObjectID that doesn't exist, the promise rejects and our application is stop working.</p>
<p>To prevent this, we can wrap our code with try/catch block, so that we can send a custom error whenever the client request a data that doesn't exist.</p>
<div class="code-title">routes.js</div>
<div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token comment">// ...</span>
router<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">"/posts/:id"</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> post <span class="token operator">=</span> <span class="token keyword">await</span> Post<span class="token punctuation">.</span><span class="token function">findOne</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">_id</span><span class="token operator">:</span> req<span class="token punctuation">.</span>params<span class="token punctuation">.</span>id <span class="token punctuation">}</span><span class="token punctuation">)</span>
res<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span>post<span class="token punctuation">)</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">{</span>
res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">404</span><span class="token punctuation">)</span>
res<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">error</span><span class="token operator">:</span> <span class="token string">"Post doesn't exist!"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div>
<p>Now, if we try to fetch a post that doesn't exist, our server still behaves as it should be.</p>
<div class="gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">$ curl http://localhost:5000/api/posts/<OBJECT_ID>
{
"error": "Post doesn't exist!"
}</code></pre></div>
<h2 id="update-post" style="position:relative;"><a href="#update-post" aria-label="update post permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Update post</h2>
<p>Usually, the preferred HTTP method to do an update operation into a single record is <code>PATCH</code>. So, let's create one!</p>
<div class="code-title">routes.js</div>
<div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token comment">// ...</span>
router<span class="token punctuation">.</span><span class="token function">patch</span><span class="token punctuation">(</span><span class="token string">"/posts/:id"</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> post <span class="token operator">=</span> <span class="token keyword">await</span> Post<span class="token punctuation">.</span><span class="token function">findOne</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">_id</span><span class="token operator">:</span> req<span class="token punctuation">.</span>params<span class="token punctuation">.</span>id <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>req<span class="token punctuation">.</span>body<span class="token punctuation">.</span>title<span class="token punctuation">)</span> <span class="token punctuation">{</span>
post<span class="token punctuation">.</span>title <span class="token operator">=</span> req<span class="token punctuation">.</span>body<span class="token punctuation">.</span>title
<span class="token punctuation">}</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>req<span class="token punctuation">.</span>body<span class="token punctuation">.</span>content<span class="token punctuation">)</span> <span class="token punctuation">{</span>
post<span class="token punctuation">.</span>content <span class="token operator">=</span> req<span class="token punctuation">.</span>body<span class="token punctuation">.</span>content
<span class="token punctuation">}</span>
<span class="token keyword">await</span> post<span class="token punctuation">.</span><span class="token function">save</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
res<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span>post<span class="token punctuation">)</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">{</span>
res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">404</span><span class="token punctuation">)</span>
res<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">error</span><span class="token operator">:</span> <span class="token string">"Post doesn't exist!"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div>
<p>Our update post route relatively similar to the get single post route. We're looking for a post by based on the id, and throw a custom error if the post doesn't exist. But this time, we also update every single field of the post object by populating it with the data provided by the client inside the <code>req.body</code>.</p>
<p>We also want to save our post object with <code>save</code> method, and send the update post data to the client.</p>
<p>Now, we can run a <code>PATCH</code> method to our <code>/api/posts/<OBJECT_ID></code> endpoint.</p>
<div class="gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">$ curl http://localhost:5000/api/posts/<OBJECT_ID> \
-X PATCH \
-H "Content-Type: application/json" \
-d '{"title":"Updated Post", "content":"Updated post content"}'
{
"__v": 0,
"_id": <OBJECT_ID>,
"title": "Updated Post"
"content": "Updated Post content",
}</code></pre></div>
<h2 id="delete-post" style="position:relative;"><a href="#delete-post" aria-label="delete post permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Delete post</h2>
<p>Finally, our last step is to finish the CRUD feature by add the delete functionality.</p>
<div class="code-title">routes.js</div>
<div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token comment">// ...</span>
router<span class="token punctuation">.</span><span class="token function">delete</span><span class="token punctuation">(</span><span class="token string">"/posts/:id"</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token keyword">await</span> Post<span class="token punctuation">.</span><span class="token function">deleteOne</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">_id</span><span class="token operator">:</span> req<span class="token punctuation">.</span>params<span class="token punctuation">.</span>id <span class="token punctuation">}</span><span class="token punctuation">)</span>
res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">204</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">{</span>
res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">404</span><span class="token punctuation">)</span>
res<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">error</span><span class="token operator">:</span> <span class="token string">"Post doesn't exist!"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div>
<p>In the delete post route, we basically just run the delete operation directly to the database with <code>deleteOne</code> method and pass the document id. And we return nothing to the user.</p>
<div class="gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">$ curl http://localhost:5000/posts/<OBJECT_ID> -X DELETE -I
HTTP/1.0 204 NO CONTENT
...</code></pre></div>
<p>That's it! I hope you learn something from this tutorial. If you have any questions, please <a href="https://rahmanfadhil.com/contact/">let me know</a>. If you want to learn how to implement unit and integration tests in this project, go ahead and read this <a href="https://rahmanfadhil.com/test-express-with-supertest/">tutorial</a>!</p></div><div class="max-w-screen-sm mx-auto relative flex flex-col items-center text-center border-t border-b pb-8 mt-24 gap-6"><div data-gatsby-image-wrapper="" style="width:96px;height:96px" class="gatsby-image-wrapper rounded-full -mt-12"><div aria-hidden="true" data-placeholder-image="" style="opacity:1;transition:opacity 500ms linear;background-color:#d8c8a8;width:96px;height:96px;position:relative"></div><picture><source type="image/avif" data-srcset="/static/8a3ed00f9df4233e83008644affec547/b9f10/avatar.avif 96w,/static/8a3ed00f9df4233e83008644affec547/f4a4f/avatar.avif 192w" sizes="96px"/><source type="image/webp" data-srcset="/static/8a3ed00f9df4233e83008644affec547/bb677/avatar.webp 96w,/static/8a3ed00f9df4233e83008644affec547/5a28d/avatar.webp 192w" sizes="96px"/><img data-gatsby-image-ssr="" class="rounded-full" layout="fixed" data-main-image="" style="opacity:0" sizes="96px" decoding="async" loading="lazy" data-src="/static/8a3ed00f9df4233e83008644affec547/707b5/avatar.png" data-srcset="/static/8a3ed00f9df4233e83008644affec547/707b5/avatar.png 96w,/static/8a3ed00f9df4233e83008644affec547/fb5f6/avatar.png 192w" alt="Profile picture"/></picture><noscript><picture><source type="image/avif" srcSet="/static/8a3ed00f9df4233e83008644affec547/b9f10/avatar.avif 96w,/static/8a3ed00f9df4233e83008644affec547/f4a4f/avatar.avif 192w" sizes="96px"/><source type="image/webp" srcSet="/static/8a3ed00f9df4233e83008644affec547/bb677/avatar.webp 96w,/static/8a3ed00f9df4233e83008644affec547/5a28d/avatar.webp 192w" sizes="96px"/><img data-gatsby-image-ssr="" class="rounded-full" layout="fixed" data-main-image="" style="opacity:0" sizes="96px" decoding="async" loading="lazy" src="/static/8a3ed00f9df4233e83008644affec547/707b5/avatar.png" srcSet="/static/8a3ed00f9df4233e83008644affec547/707b5/avatar.png 96w,/static/8a3ed00f9df4233e83008644affec547/fb5f6/avatar.png 192w" alt="Profile picture"/></picture></noscript><script type="module">const t="undefined"!=typeof HTMLImageElement&&"loading"in HTMLImageElement.prototype;if(t){const t=document.querySelectorAll("img[data-main-image]");for(let e of t){e.dataset.src&&(e.setAttribute("src",e.dataset.src),e.removeAttribute("data-src")),e.dataset.srcset&&(e.setAttribute("srcset",e.dataset.srcset),e.removeAttribute("data-srcset"));const t=e.parentNode.querySelectorAll("source[data-srcset]");for(let e of t)e.setAttribute("srcset",e.dataset.srcset),e.removeAttribute("data-srcset");e.complete&&(e.style.opacity=1,e.parentNode.parentNode.querySelector("[data-placeholder-image]").style.opacity=0)}}</script></div><h1 class="text-xl font-extrabold">Abdurrahman Fadhil</h1><p class="text-sm text-slate-600 leading-relaxed">I'm a software engineer specialized in iOS and full-stack web development. If you have a project in mind, feel free to<!-- --> <a class="link" href="/contact/">contact me</a> <!-- -->and start the conversation.</p></div></div><nav role="navigation" class="max-w-lg mx-auto py-8 sm:py-16"><ul class="flex gap-y-3 gap-x-5 md:gap-x-8 flex-wrap justify-center"><li><a class="link text-sm" href="/">Home</a></li><li><a class="link text-sm" href="/about/">About</a></li><li><a class="link text-sm" href="/contact/">Contact</a></li><li><a class="link text-sm" href="/blog/">Blog</a></li><li><a class="link text-sm" href="/videos/">Courses</a></li><li><a class="link text-sm" href="/portfolio/">Portfolio</a></li><li><a href="https://twitter.com/rahmanfadhil14" class="link text-sm">Twitter</a></li><li><a href="https://github.com/rahmanfadhil" class="link text-sm">GitHub</a></li><li><a href="https://www.linkedin.com/in/rahmanfadhil/" class="link text-sm">LinkedIn</a></li><li><a href="https://www.instagram.com/rahmanfadhil14/" class="link text-sm">Instagram</a></li><li><a href="https://www.youtube.com/@rahmanfadhil" class="link text-sm">YouTube</a></li></ul></nav></div></div><div id="gatsby-announcer" style="position:absolute;top:0;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0" aria-live="assertive" aria-atomic="true"></div></div><script>
if(true) {
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
}
if (typeof ga === "function") {
ga('create', 'UA-133172956-2', 'auto', {});
}</script><script id="gatsby-script-loader">/*<![CDATA[*/window.pagePath="/express-rest-api/";/*]]>*/</script><!-- slice-start id="_gatsby-scripts-1" -->
<script
id="gatsby-chunk-mapping"
>
window.___chunkMapping="{\"app\":[\"/app-9d78c2f07dba16b04f82.js\"],\"component---src-pages-404-js\":[\"/component---src-pages-404-js-8b5861ae077a558bdce2.js\"],\"component---src-pages-about-js\":[\"/component---src-pages-about-js-c3023486f44549dbe07c.js\"],\"component---src-pages-blog-js\":[\"/component---src-pages-blog-js-fc54e4844c0ffa9cbabc.js\"],\"component---src-pages-contact-js\":[\"/component---src-pages-contact-js-41192a457481109ac5fe.js\"],\"component---src-pages-index-js\":[\"/component---src-pages-index-js-e52dd48894514a70e7ed.js\"],\"component---src-pages-portfolio-js\":[\"/component---src-pages-portfolio-js-cf1bf20de6caad154e45.js\"],\"component---src-pages-videos-js\":[\"/component---src-pages-videos-js-5f2c820eef24f69b5959.js\"],\"component---src-templates-post-template-js\":[\"/component---src-templates-post-template-js-2ee2f7fdea2628b83651.js\"],\"component---src-templates-series-template-js\":[\"/component---src-templates-series-template-js-05d683a74ad57007281b.js\"],\"component---src-templates-video-template-js\":[\"/component---src-templates-video-template-js-2e97b2ea9af5f44cb777.js\"]}";
</script>
<script>window.___webpackCompilationHash="48d8a077cb1f1832d07b";</script><script src="/webpack-runtime-78811e6c2d5593e91b3b.js" async></script><script src="/framework-6e68b7056956344bfd29.js" async></script><script src="/app-9d78c2f07dba16b04f82.js" async></script><!-- slice-end id="_gatsby-scripts-1" --></body></html>