Microservices with Node JS and React
Event-Based Architecture? Covered! Server side rendering with React? Yep. Scalable, production-ready code? Its here! Microservices are the number one solution for building and scaling out apps that are intended to grow. Just one little issue: there are few resources online that delve into the most complex and nasty issues around them! I built this course to fix that. This course tackles every major issues around microservices head on. From challenges with data replication to confusing unordered event streams, every major challenge of building microservices is covered.
More
Beyond focusing on the basics of microservices, this course is a perfect introduction to the world of full-stack development. You will work all the way from the frontend, assembling a React app using Hooks, to the backend, including database design and deployment strategies. Every step along the way is covered in tremendous detail, with ample diagrams to ensure every step is crystal clear.
Many other resources show only the easiest, simplest apps written with microservices. This course does the opposite: we focus on the most challenging aspects of microservices, challenges that you will likely encounter every single day. You will see these difficulties first hand, then solve them with easy-to-understand strategies.
How This Course Works
This course doesn't focus on using an off-the-shelf microservices framework. Many exist, but they hide the inner workings and challenges of microservices away from you. Instead, we will be using a minimal number of libraries, and write as much custom code as possible. This will expose you to challenging problems and clever solutions when handling subjects like async events!
What Technology You'll Use
Because we are building a full stack application, we will use a variety of technologies. On the frontend, we'll use React and Next JS to present content to users. Each service is created using Node and Express. Data for each service is held in either a Mongo database or Redis. The entire app is deployed and runs in Docker containers executed in a Kubernetes cluster. Finally, almost all of the code in this course is written with Typescript.
This is a scary list of technologies! Not familiar with some of these? No problem! The course is built assuming that you only know the basics of Javascript and Express. No other knowledge is needed - you will learn everything you need to know.
What You'll Be Able to Do
By the time you complete this course, you will be able to:
Architect a multi-service application
Determine whether your app is a good fit for a microservices approach
Understand and solve the challenges in async, event-based communication between services
Use Docker and Kubernetes to deploy a multi-service app to any cloud provider
Organize and enhance the reusability of code in large projects
What You'll Learn
An absolute incredible number of topics are covered in this course. Here is a partial list of what you'll do:
Practice patterns to create scalable microservices for a variety of app domains
Build a Server-Side-Rendered React app using Hooks and Next JS
Write a custom implementation of an event bus
Optionally, run a development environment through a cloud provider
Guarantee consistently structured responses from your different API's
See best practices in communication between different services
Configure and scale your services using Kubernetes Deployments
Document and enforce structure constraints on events shared across microservices
Limit access to your APIs using JWT-based authentication
And much more!
This is the course I wish I had when I was learning microservices. A course that focuses on the hardest parts, gives clear explanations, and discusses the pros and cons of different design options. Sign up today and join me in mastering microservices!
- Basic knowledge of Javascript and Express is required
- Knowledge of React is good, but not needed
- You must be familiar and comfortable with the command line
- Javascript engineers looking to build large, scalable applications
- This course is *not* designed for sysadmins focused on infrastructure deployment
What you'll learn:
- Architect large, scalable apps using a collection of microservices
- Deploy a multi-service app to the cloud with Docker and Kubernetes
- Solve concurrency issues in a distributed systems environment
- Leverage your Javascript skills to build a complex web app
- Build a Server-Side Rendered React App to render data from your microservices
- Understand how enterprise companies design their infrastructure
- Share reusable code between multiple Express servers using custom NPM packages
- Write comprehensive tests to ensure each service works as designed
- Communicate data between services using a lightning-fast event bus
- Write nothing but production-level code. No cutting corners!
Watch Online Microservices with Node JS and React
# | Title | Duration |
---|---|---|
1 | How to Get Help | 00:57 |
2 | What Is a Microservice? | 03:20 |
3 | Data in Microservices | 07:35 |
4 | Big Problems with Data | 05:09 |
5 | Sync Communication Between Services | 06:54 |
6 | Event-Based Communication | 05:20 |
7 | A Crazy Way of Storing Data | 09:50 |
8 | Pros and Cons of Async Communication | 06:16 |
9 | App Overview | 05:45 |
10 | Project Setup | 04:58 |
11 | Posts Service Creation | 08:19 |
12 | Testing the Posts Service | 04:06 |
13 | Implementing a Comments Service | 08:23 |
14 | Quick Comments Test | 03:58 |
15 | React Project Setup | 05:01 |
16 | Building Post Submission | 09:55 |
17 | Handling CORS Errors | 04:10 |
18 | Fetching and Rendering Posts | 10:05 |
19 | Creating Comments | 08:10 |
20 | Displaying Comments | 07:24 |
21 | Request Minimization Strategies | 04:55 |
22 | An Async Solution | 07:17 |
23 | Common Questions Around Async Events | 04:15 |
24 | Event Bus Overview | 05:15 |
25 | A Basic Event Bus Implementation | 05:23 |
26 | Emitting Events | 05:19 |
27 | Emitting Comment Creation Events | 03:46 |
28 | Receiving Events | 04:34 |
29 | Creating the Data Query Service | 04:43 |
30 | Parsing Incoming Events | 07:03 |
31 | Using the Query Service | 07:11 |
32 | Adding a Simple Feature | 04:47 |
33 | Issues with Comment Filtering | 07:44 |
34 | A Second Approach | 05:38 |
35 | How to Handle Resource Updates | 04:46 |
36 | Creating the Moderation Service | 04:53 |
37 | Adding Comment Moderation | 04:27 |
38 | Handling Moderation | 05:31 |
39 | Updating Comment Content | 05:00 |
40 | A Quick Test | 05:58 |
41 | Rendering Comments by Status | 03:27 |
42 | Dealing with Missing Events | 10:25 |
43 | Implementing Event Sync | 06:12 |
44 | Event Syncing in Action | 04:17 |
45 | Deployment Issues | 06:56 |
46 | Why Docker? | 02:56 |
47 | Why Kubernetes? | 05:48 |
48 | Don't Know Docker? Watch This. | 01:18 |
49 | Dockerizing the Posts Service | 04:03 |
50 | Review Some Basic Commands | 05:24 |
51 | Dockering Other Services | 03:02 |
52 | Installing Kubernetes | 03:20 |
53 | A Kubernetes Tour | 09:46 |
54 | Important Kubernetes Terminology | 02:53 |
55 | Notes on Config Files | 03:12 |
56 | Creating a Pod | 06:42 |
57 | Understanding a Pod Spec | 05:16 |
58 | Common Kubectl Commands | 04:45 |
59 | A Time-Saving Alias | 02:27 |
60 | Introducing Deployments | 03:29 |
61 | Creating a Deployment | 06:12 |
62 | Common Commands Around Deployments | 04:37 |
63 | Updating Deployments | 06:03 |
64 | Preferred Method for Updating Deployments | 05:43 |
65 | Networking With Services | 04:16 |
66 | Creating a NodePort Service | 07:53 |
67 | Accessing NodePort Services | 05:10 |
68 | Setting Up Cluster IP Services | 03:13 |
69 | Building a Deployment for the Event Bus | 05:36 |
70 | Adding ClusterIP Services | 07:38 |
71 | How to Communicate Between Services | 04:10 |
72 | Updating Service Addresses | 06:28 |
73 | Verifying Communication | 05:01 |
74 | Adding Query, Moderation and Comments | 09:58 |
75 | Testing Communication | 05:30 |
76 | Load Balancer Services | 05:14 |
77 | Load Balancers and Ingress | 06:40 |
78 | Installing Ingress-Nginx | 07:41 |
79 | Writing Ingress Config Files | 04:48 |
80 | Hosts File Tweak | 06:17 |
81 | Deploying the React App | 06:10 |
82 | Unique Route Paths | 06:56 |
83 | Final Route Config | 06:33 |
84 | Introducing Skaffold | 03:09 |
85 | Skaffold Setup | 09:18 |
86 | First Time Skaffold Startup | 01:01 |
87 | A Few Notes on Skaffold | 06:31 |
88 | Big Ticket Items | 15:12 |
89 | App Overview | 08:54 |
90 | Resource Types | 03:24 |
91 | Service Types | 03:39 |
92 | Events and Architecture Design | 03:49 |
93 | Auth Service Setup | 04:52 |
94 | Auth K8s Setup | 08:16 |
95 | Adding Skaffold | 05:37 |
96 | Ingress-Nginx Setup | 07:20 |
97 | Hosts File and Security Warning | 04:07 |
98 | Note on Remote Development | 02:52 |
99 | Remote Dev with Skaffold | 06:36 |
100 | Google Cloud Initial Setup | 02:44 |
101 | Kubernetes Cluster Creation | 04:00 |
102 | Kubectl Contexts | 03:50 |
103 | Initializing the GCloud SDK | 05:04 |
104 | Installing the GCloud Context | 04:18 |
105 | Updating the Skaffold Config | 04:36 |
106 | More Skaffold Updates | 01:07 |
107 | Creating a Load Balancer | 05:13 |
108 | Final Config and Test | 06:26 |
109 | Creating Route Handlers | 05:42 |
110 | Scaffolding Routes | 04:06 |
111 | Adding Validation | 08:39 |
112 | Handling Validation Errors | 06:19 |
113 | Surprising Complexity Around Errors | 06:08 |
114 | Other Sources of Errors | 04:18 |
115 | Solution for Error Handling | 04:51 |
116 | Building an Error Handling Middleware | 07:39 |
117 | Communicating More Info to the Error Handler | 05:25 |
118 | Encoding More Information In an Error | 04:36 |
119 | Subclassing for Custom Errors | 08:18 |
120 | Determining Error Type | 03:11 |
121 | Converting Errors to Responses | 10:13 |
122 | Moving Logic Into Errors | 08:37 |
123 | Verifying Our Custom Errors | 08:35 |
124 | Final Error Related Code | 10:20 |
125 | How to Define New Custom Errors | 05:02 |
126 | Uh Oh... Async Error Handling | 05:51 |
127 | Creating Databases in Kubernetes | 08:26 |
128 | Connecting to MongoDB | 07:54 |
129 | Understanding the Signup Flow | 04:26 |
130 | Getting TypeScript and Mongoose to Cooperate | 05:22 |
131 | Creating the User Model | 04:55 |
132 | Type Checking User Properties | 06:02 |
133 | Adding Static Properties to a Model | 06:01 |
134 | Defining Extra Document Properties | 04:54 |
135 | What's That Angle Bracket For? | 03:53 |
136 | User Creation | 06:48 |
137 | Proper Error Handling | 07:27 |
138 | Reminder on Password Hashing | 04:59 |
139 | Adding Password Hashing | 06:58 |
140 | Comparing Hashed Password | 02:55 |
141 | Mongoose Pre-Save Hooks | 05:54 |
142 | Fundamental Authentication Strategies | 08:59 |
143 | Huge Issues with Authentication Strategies | 07:33 |
144 | So Which Option? | 02:59 |
145 | Solving Issues with Option #2 | 08:27 |
146 | Reminder on Cookies vs JWT's | 06:22 |
147 | Microservices Auth Requirements | 11:01 |
148 | Issues with JWT's and Server Side Rendering | 09:59 |
149 | Cookies and Encryption | 04:52 |
150 | Adding Session Support | 03:12 |
151 | Generating a JWT | 08:30 |
152 | JWT Signing Keys | 04:58 |
153 | Securely Storing Secrets with Kubernetes | 02:14 |
154 | Creating and Accessing Secrets | 09:19 |
155 | Accessing Env Variables in a Pod | 05:19 |
156 | Common Response Properties | 04:42 |
157 | Formatting JSON Properties | 10:39 |
158 | The Signin Flow | 07:50 |
159 | Common Request Validation Middleware | 05:34 |
160 | Sign In Logic | 06:50 |
161 | Quick Sign In Test | 01:54 |
162 | Current User Handler | 03:02 |
163 | Returning the Current User | 08:56 |
164 | Signing Out | 02:49 |
165 | Creating a Current User Middleware | 06:56 |
166 | Augmenting Type Definitions | 07:47 |
167 | Requiring Auth for Route Access | 07:47 |
168 | Scope of Testing | 04:29 |
169 | Testing Goals | 04:33 |
170 | Testing Architecture | 07:52 |
171 | Index to App Refactor | 02:55 |
172 | A Few Dependencies | 03:34 |
173 | Test Environment Setup | 08:13 |
174 | Our First Test | 06:25 |
175 | An Important Note | 01:32 |
176 | Testing Invalid Input | 05:14 |
177 | Requiring Unique Emails | 01:47 |
178 | Changing Node Env During Tests | 05:44 |
179 | Tests Around Sign In Functionality | 06:27 |
180 | Testing Sign Out | 04:32 |
181 | Issues with Cookies During Testing | 05:20 |
182 | Easy Auth Solution | 03:04 |
183 | Auth Helper Function | 07:13 |
184 | Testing Non-Authed Requests | 01:45 |
185 | Starting the React App | 02:12 |
186 | Reminder on Server Side Rendering | 03:39 |
187 | Basics of Next JS | 05:25 |
188 | Building a Next Image | 04:29 |
189 | Running Next in Kubernetes | 10:13 |
190 | Note on File Change Detection | 04:27 |
191 | Adding Global CSS | 05:10 |
192 | Adding a Sign Up Form | 03:12 |
193 | Handling Email and Password Inputs | 03:43 |
194 | Successful Account Signup | 05:13 |
195 | Handling Validation Errors | 06:54 |
196 | The useRequest Hook | 07:00 |
197 | Using the useRequest Hook | 03:41 |
198 | An onSuccess Callback | 05:39 |
199 | Overview on Server Side Rendering | 06:48 |
200 | Fetching Data During SSR | 05:08 |
201 | Why the Error? | 09:01 |
202 | Two Possible Solutions | 07:05 |
203 | Cross Namespace Service Communication | 07:46 |
204 | When is GetInitialProps Called? | 06:47 |
205 | On the Server or the Browser | 02:02 |
206 | Specifying the Host | 08:24 |
207 | Passing Through the Cookies | 04:02 |
208 | A Reusable API Client | 07:06 |
209 | Content on the Landing Page | 02:02 |
210 | The Sign In Form | 03:13 |
211 | A Reusable Header | 05:01 |
212 | Moving GetInitialProps | 02:12 |
213 | Issues with Custom App GetInitialProps | 06:43 |
214 | Handling Multiple GetInitialProps | 06:09 |
215 | Passing Props Through | 03:04 |
216 | Building the Header | 05:06 |
217 | Conditionally Showing Links | 05:59 |
218 | Signing Out | 04:37 |
219 | Shared Logic Between Services | 04:35 |
220 | Options for Code Sharing | 04:47 |
221 | NPM Organizations | 04:28 |
222 | Publishing NPM Modules | 04:07 |
223 | Project Setup | 07:35 |
224 | An Easy Publish Command | 07:27 |
225 | Relocating Shared Code | 07:30 |
226 | Updating Import Statements | 05:18 |
227 | Updating the Common Module | 05:35 |
228 | Ticketing Service Overview | 03:04 |
229 | Project Setup | 05:26 |
230 | Running the Ticket Service | 06:06 |
231 | Mongo Connection URI | 08:15 |
232 | Quick Auth Update | 01:48 |
233 | Test-First Approach | 04:20 |
234 | Creating the Router | 04:57 |
235 | Adding Auth Protection | 08:05 |
236 | Faking Authentication During Tests | 07:11 |
237 | Building a Session | 05:40 |
238 | Testing Request Validation | 04:13 |
239 | Validating Title and Price | 04:10 |
240 | Reminder on Mongoose with TypeScript | 07:13 |
241 | Defining the Ticket Model | 03:50 |
242 | Creation via Route Handler | 08:22 |
243 | Testing Show Routes | 06:53 |
244 | Unexpected Failure! | 05:30 |
245 | What's that Error?! | 08:58 |
246 | Better Error Logging | 05:12 |
247 | Complete Index Route Implementation | 06:32 |
248 | Ticket Updating | 06:16 |
249 | Handling Updates | 04:16 |
250 | Permission Checking | 06:50 |
251 | Final Update Changes | 09:05 |
252 | Manual Testing | 05:37 |
253 | What Now? | 02:51 |
254 | Three Important Items | 04:35 |
255 | Creating a NATS Streaming Deployment | 06:26 |
256 | Big Notes on NATS Streaming | 09:54 |
257 | Building a NATS Test Project | 07:32 |
258 | Port-Forwarding with Kubectl | 04:41 |
259 | Publishing Events | 06:22 |
260 | Listening For Data | 06:56 |
261 | Accessing Event Data | 06:57 |
262 | Client ID Generation | 04:49 |
263 | Queue Groups | 07:29 |
264 | Manual Ack Mode | 09:53 |
265 | Client Health Checks | 09:46 |
266 | Graceful Client Shutdown | 06:43 |
267 | Core Concurrency Issues | 12:57 |
268 | Common Questions | 08:09 |
269 | [Optional] More Possible Concurrency Solutions | 16:43 |
270 | Solving Concurrency Issues | 20:06 |
271 | Concurrency Control with the Tickets App | 09:41 |
272 | Event Redelivery | 04:36 |
273 | Durable Subscriptions | 09:00 |
274 | Reusable NATS Listeners | 04:34 |
275 | The Listener Abstract Class | 09:28 |
276 | Extending the Listener | 05:54 |
277 | Quick Refactor | 03:19 |
278 | Leveraging TypeScript for Listener Validation | 05:29 |
279 | Subjects Enum | 03:30 |
280 | Custom Event Interface | 02:27 |
281 | Enforcing Listener Subjects | 07:23 |
282 | Enforcing Data Types | 03:55 |
283 | Where Does this Get Used? | 02:50 |
284 | Custom Publisher | 08:12 |
285 | Using the Custom Publisher | 03:51 |
286 | Awaiting Event Publication | 04:29 |
287 | Common Event Definitions Summary | 06:27 |
288 | Updating the Common Module | 07:36 |
289 | Restarting NATS | 02:11 |
290 | Publishing Ticket Creation | 03:49 |
291 | More on Publishing | 03:20 |
292 | NATS Client Singleton | 05:25 |
293 | Remember Mongoose? | 04:58 |
294 | Singleton Implementation | 09:05 |
295 | Accessing the NATS Client | 04:29 |
296 | Graceful Shutdown | 06:56 |
297 | Successful Listen! | 03:24 |
298 | Ticket Update Publishing | 04:29 |
299 | Failed Event Publishing | 07:04 |
300 | Handling Publish Failures | 06:03 |
301 | Fixing a Few Tests | 03:53 |
302 | Redirecting Imports | 05:36 |
303 | Providing a Mock Implementation | 09:10 |
304 | Test-Suite Wide Mocks | 02:13 |
305 | Ensuring Mock Invocations | 09:14 |
306 | NATS Env Variables | 08:01 |
307 | The Orders Service | 05:03 |
308 | Scaffolding the Orders Service | 04:40 |
309 | A Touch More Setup | 07:34 |
310 | Ingress Routing Rules | 01:55 |
311 | Scaffolding a Few Route Handlers | 09:56 |
312 | Subtle Service Coupling | 06:44 |
313 | Associating Orders and Tickets | 06:50 |
314 | Order Model Setup | 08:53 |
315 | The Need for an Enum | 05:57 |
316 | Creating an Order Status Enum | 08:32 |
317 | More on Mongoose Refs | 02:59 |
318 | Defining the Ticket Model | 07:10 |
319 | Order Creation Logic | 05:46 |
320 | Finding Reserved Tickets | 06:11 |
321 | Convenience Document Methods | 07:38 |
322 | Order Expiration Times | 06:06 |
323 | Test Suite Setup | 02:37 |
324 | Asserting Tickets Exist | 06:09 |
325 | Asserting Reserved Tickets | 05:06 |
326 | Testing the Success Case | 04:10 |
327 | Fetching a User's Orders | 05:25 |
328 | A Slightly Complicated Test | 12:24 |
329 | Fetching Individual Orders | 04:37 |
330 | Does Fetching Work? | 07:18 |
331 | Cancelling an Order | 04:33 |
332 | Can We Cancel? | 09:13 |
333 | Orders Service Events | 04:44 |
334 | Creating the Events | 09:24 |
335 | Implementing the Publishers | 03:14 |
336 | Publishing the Order Creation | 05:04 |
337 | Publishing Order Cancellation | 02:34 |
338 | Testing Event Publishing | 05:34 |
339 | Time for Listeners! | 02:13 |
340 | Reminder on Listeners | 01:55 |
341 | Blueprint for Listeners | 03:40 |
342 | A Few More Reminders | 05:27 |
343 | Simple onMessage Implementation | 02:18 |
344 | ID Adjustment | 05:45 |
345 | Ticket Updated Listener Implementation | 04:33 |
346 | Initializing the Listeners | 02:45 |
347 | A Quick Manual Test | 03:17 |
348 | Clear Concurrency Issues | 13:00 |
349 | Reminder on Versioning Records | 06:42 |
350 | Optimistic Concurrency Control | 05:38 |
351 | Mongoose Update-If-Current | 03:47 |
352 | Implementing OCC with Mongoose | 04:03 |
353 | Testing OCC | 09:08 |
354 | One More Test | 03:46 |
355 | Who Updates Versions? | 06:30 |
356 | Including Versions in Events | 03:00 |
357 | Updating Tickets Event Definitions | 03:56 |
358 | Applying a Version Query | 07:15 |
359 | Did it Work? | 04:32 |
360 | Abstracted Query Method | 05:43 |
361 | [Optional] Versioning Without Update-If-Current | 18:35 |
362 | Testing Listeners | 04:56 |
363 | A Complete Listener Test | 09:26 |
364 | Testing the Ack Call | 02:10 |
365 | Testing the Ticket Updated Listener | 08:22 |
366 | Success Case Testing | 04:50 |
367 | Out-Of-Order Events | 04:52 |
368 | The Next Few Videos | 03:40 |
369 | Fixing a Few Tests | 06:37 |
370 | Listeners in the Tickets Service | 01:48 |
371 | Building the Listener | 05:00 |
372 | Strategies for Locking a Ticket | 05:29 |
373 | Reserving a Ticket | 03:43 |
374 | Setup for Testing Reservation | 07:01 |
375 | Test Implementation | 04:30 |
376 | Missing Update Event | 06:15 |
377 | Private vs Protected Properties | 06:55 |
378 | Publishing While Listening | 06:43 |
379 | Mock Function Arguments | 09:50 |
380 | Order Cancelled Listener | 06:52 |
381 | A Lightning-Quick Test | 07:29 |
382 | Don't Forget to Listen! | 02:22 |
383 | Rejecting Edits of Reserved Tickets | 06:16 |
384 | The Expiration Service | 02:39 |
385 | Expiration Options | 07:56 |
386 | Initial Setup | 06:15 |
387 | A Touch of Kubernetes Setup | 07:45 |
388 | File Sync Setup | 02:33 |
389 | Listener Creation | 03:43 |
390 | What's Bull All About? | 03:57 |
391 | Creating a Queue | 09:08 |
392 | Queueing a Job on Event Arrival | 05:11 |
393 | Testing Job Processing | 03:18 |
394 | Delaying Job Processing | 05:24 |
395 | Defining the Expiration Complete Event | 03:51 |
396 | Publishing an Event on Job Processing | 06:28 |
397 | Handling an Expiration Event | 06:01 |
398 | Emitting the Order Cancelled Event | 05:38 |
399 | Testing the Expiration Complete Listener | 05:53 |
400 | A Touch More Testing | 07:21 |
401 | Listening for Expiration | 02:21 |
402 | Don't Cancel Completed Orders! | 02:12 |
403 | The Payments Service | 08:47 |
404 | Initial Setup | 05:58 |
405 | Replicated Fields | 07:31 |
406 | Another Order Model! | 01:18 |
407 | Update-If-Current | 04:08 |
408 | Replicating Orders | 06:13 |
409 | Testing Order Creation | 05:40 |
410 | Marking an Order as Cancelled | 06:43 |
411 | Cancelled Testing | 03:55 |
412 | Starting the Listeners | 05:11 |
413 | Payments Flow with Stripe | 08:33 |
414 | Implementing the Create Charge Handler | 04:04 |
415 | Validating Order Payment | 07:00 |
416 | Testing Order Validation Before Payment | 05:11 |
417 | Testing Same-User Validation | 03:59 |
418 | Stripe Setup | 03:21 |
419 | Creating a Stripe Secret | 06:10 |
420 | Creating a Charge with Stripe | 06:36 |
421 | Manual Testing of Payments | 06:28 |
422 | Automated Payment Testing | 04:24 |
423 | Mocked Stripe Client | 09:17 |
424 | A More Realistic Test Setup | 06:16 |
425 | Realistic Test Implementation | 07:19 |
426 | Tying an Order and Charge Together | 06:14 |
427 | Testing Payment Creation | 06:32 |
428 | Publishing a Payment Created Event | 03:19 |
429 | More on Publishing | 06:19 |
430 | Marking an Order as Complete | 01:02 |
431 | A Few More Pages | 06:17 |
432 | Reminder on Data Fetching with Next | 06:10 |
433 | Two Quick Fixes | 05:44 |
434 | Scaffolding a Form | 03:44 |
435 | Sanitizing Price Input | 06:30 |
436 | Ticket Creation | 06:45 |
437 | Listing All Tickets | 07:42 |
438 | Linking to Wildcard Routes | 07:08 |
439 | Creating an Order | 07:26 |
440 | Programmatic Navigation to Wildcard Routes | 04:17 |
441 | The Expiration Timer | 10:55 |
442 | Displaying the Expiration | 01:02 |
443 | Showing a Stripe Payment Form | 03:07 |
444 | Configuring Stripe | 04:24 |
445 | Test Credit Card Numbers | 01:59 |
446 | Paying for an Order | 09:25 |
447 | Filtering Reserved Tickets | 02:28 |
448 | Header Links | 01:48 |
449 | Rendering a List of Orders | 06:21 |
450 | Development Workflow | 03:40 |
451 | Git Repository Approaches | 06:06 |
452 | Creating a GitHub Action | 07:12 |
453 | Adding a CI Test Script | 02:43 |
454 | Running Tests on PR Creation | 04:49 |
455 | Output of Failing Tests | 05:49 |
456 | Running Tests in Parallel | 07:29 |
457 | Verifying a Test Run | 03:02 |
458 | Selective Test Execution | 05:45 |
459 | Deployment Options | 07:41 |
460 | Creating a Hosted Cluster | 02:40 |
461 | Reminder on Kubernetes Context | 03:33 |
462 | Reminder on Swapping Contexts | 03:57 |
463 | The Deployment Plan | 04:05 |
464 | Building an Image in an Action | 08:41 |
465 | Testing the Image Build | 02:31 |
466 | Restarting the Deployment | 07:19 |
467 | Applying Kubernetes Manifests | 03:28 |
468 | Prod vs Dev Manifest Files | 04:24 |
469 | Manual Secret Creation | 03:40 |
470 | Don't Forget Ingress-Nginx! | 05:32 |
471 | Testing Automated Deployment | 02:52 |
472 | Additional Deploy Files | 07:13 |
473 | A Successful Deploy! | 06:08 |
474 | Buying a Domain Name | 03:11 |
475 | Configuring the Domain Name | 05:28 |
476 | I Really Hope This Works | 01:59 |
477 | Next Steps | 04:37 |
478 | Why Use Docker? | 03:44 |
479 | What is Docker? | 02:54 |
480 | Docker for Mac / Windows | 01:58 |
481 | Installing Docker on macOS | 04:46 |
482 | Installing Docker for Windows - Professional and Enterprise | 02:04 |
483 | More Windows Setup - Professional and Enterprise | 00:41 |
484 | One Last Piece of Windows Setup - Professional and Enterprise | 01:10 |
485 | Using the Docker Client | 05:04 |
486 | But Really... What's a Container? | 08:31 |
487 | How's Docker Running on Your Computer? | 02:45 |
488 | Docker Run in Detail | 01:55 |
489 | Overriding Default Commands | 05:13 |
490 | Listing Running Containers | 04:10 |
491 | Container Lifecycle | 05:17 |
492 | Restarting Stopped Containers | 03:44 |
493 | Removing Stopped Containers | 01:40 |
494 | Retrieving Output Logs | 02:34 |
495 | Stopping Containers | 05:22 |
496 | Multi-Command Containers | 04:17 |
497 | Executing Commands in Running Containers | 02:54 |
498 | The Purpose of the 'it' Flag | 04:36 |
499 | Getting a Command Prompt in a Container | 04:07 |
500 | Starting with a Shell | 02:14 |
501 | Container Isolation | 03:10 |
502 | Creating Docker Images | 02:37 |
503 | Building a Dockerfile | 04:52 |
504 | Dockerfile Teardown | 02:42 |
505 | What's a Base Image? | 05:41 |
506 | The Build Process in Detail | 11:10 |
507 | A Brief Recap | 03:25 |
508 | Rebuilds with Cache | 07:03 |
509 | Tagging an Image | 04:27 |
510 | Manual Image Generation with Docker Commit | 05:01 |
511 | Project Outline | 02:36 |
512 | Node Server Setup | 05:04 |
513 | A Few Planned Errors | 05:13 |
514 | Base Image Issues | 07:51 |
515 | A Few Missing Files | 03:19 |
516 | Copying Build Files | 04:51 |
517 | Container Port Forwarding | 07:27 |
518 | Specifying a Working Directory | 07:53 |
519 | Unnecessary Rebuilds | 04:17 |
520 | Minimizing Cache Busting and Rebuilds | 04:59 |
521 | How to Get Help | 01:05 |
522 | TypeScript Overview | 06:20 |
523 | Environment Setup | 08:00 |
524 | A First App | 04:44 |
525 | Executing Typescript Code | 05:04 |
526 | One Quick Change | 03:36 |
527 | Catching Errors with TypeScript | 07:23 |
528 | Catching More Errors! | 05:16 |
529 | Do Not Skip - Course Overview | 03:37 |
530 | Types | 05:13 |
531 | More on Types | 05:54 |
532 | Examples of Types | 04:50 |
533 | Where Do We Use Types? | 00:50 |
534 | Type Annotations and Inference | 02:04 |
535 | Annotations With Variables | 04:54 |
536 | Object Literal Annotations | 06:54 |
537 | Annotations Around Functions | 05:57 |
538 | Understanding Inference | 03:52 |
539 | The Any Type | 07:48 |
540 | Fixing the "Any" Type | 01:50 |
541 | Delayed Initialization | 03:06 |
542 | When Inference Doesn't Work | 04:38 |
543 | Annotations Around Functions | 04:57 |
544 | Inference Around Functions | 06:09 |
545 | Annotations for Anonymous Functions | 01:43 |
546 | Void and Never | 02:50 |
547 | Destructuring with Annotations | 03:36 |
548 | Annotations Around Objects | 07:06 |
549 | Arrays in TypeScript | 05:06 |
550 | Why Typed Arrays? | 04:31 |
551 | Multiple Typees in Arrays | 02:58 |
552 | When to Use Typed Arrays | 00:55 |
553 | Tuples in TypeScript | 04:06 |
554 | Tuples in Action | 05:29 |
555 | Why Tuples? | 03:21 |
556 | Interfaces | 01:27 |
557 | Long Type Annotations | 04:43 |
558 | Fixing Annotations With Interfaces | 04:37 |
559 | Syntax Around Interfaces | 03:32 |
560 | Functions in Interfaces | 04:47 |
561 | Code Reuse with Interfaces | 04:16 |
562 | General Plan with Interfaces | 03:13 |
563 | Classes | 03:48 |
564 | Basic Inheritance | 03:04 |
565 | Class Method Modifiers | 06:42 |
566 | Fields in Classes | 06:19 |
567 | Fields with Inheritance | 04:19 |
568 | Where to Use Classes | 01:11 |
569 | App Overview | 02:46 |
570 | Parcel in Action | 04:56 |
571 | Project Structure | 03:20 |
572 | Generating Random Data | 05:30 |
573 | Type Definition Files | 05:18 |
574 | Using Type Definition Files | 06:21 |
575 | Export Statements in TypeScript | 05:07 |
576 | Defining a Company | 04:44 |
577 | Adding Google Maps Support | 07:39 |
578 | Google Maps Integration with TypeScript | 04:07 |
579 | Exploring Type Definition Files | 12:47 |
580 | Hiding Functionality | 06:29 |
581 | Why Use Private Modifiers? Here's Why | 08:26 |
582 | Adding Markers | 09:19 |
583 | Duplicate Code | 02:46 |
584 | One Possible Solution | 06:39 |
585 | Restricting Access with Interfaces | 05:36 |
586 | Implicit Type Checks | 03:27 |
587 | Showing Popup Windows | 06:48 |
588 | Updating Interface Definitions | 07:12 |
589 | Optional Implements Clauses | 06:07 |
590 | App Wrapup | 08:09 |