Course Overview
Event-Based Architecture? Covered! Server side rendering with React? Yep. Scalable, production-ready code? Its here!
This course requires you to download Docker Desktop from Docker. If you are a Udemy Business user, please check with your employer before downloading software.
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.
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!
FAQ
FAQ area empty
Course curriculum
-
App Overview
-
Project Setup
-
Posts Service Creation
-
Testing the Posts Service
-
Implementing a Comments Service
-
Quick Comments Test
-
React Project Setup
-
Building Post Submission
-
Handling CORS Errors
-
Fetching and Rendering Posts
-
Creating Comments
-
Displaying Comments
-
Request Minimization Strategies
-
An Async Solution
-
Common Questions Around Async Events
-
Event Bus Overview
-
A Basic Event Bus Implementation
-
Emitting Events
-
Emitting Comment Creation Events
-
Receiving Events
-
Creating the Data Query Service
-
Parsing Incoming Events
-
Using the Query Service
-
Adding a Simple Feature
-
Issues with Comment Filtering
-
A Second Approach
-
How to Handle Resource Updates
-
Creating the Moderation Service
-
Adding Comment Moderation
-
Handling Moderation
-
Updating Comment Content
-
A Quick Test
-
Rendering Comments by Status
-
Dealing with Missing Events
-
Implementing Event Sync
-
Event Syncing in Action
-
Important - Optional Boilerplate
-
Note on the React App
-
Addressing Default Export and ReactDom.render Warnings
-
Completed React App
-
Important Note about Node and Unhandled Promise Rejections
-
Reminder about Error Catching
-
Required Error Handling Update for Query Service
-
Installing Kubernetes
-
A Kubernetes Tour
-
Important Kubernetes Terminology
-
Notes on Config Files
-
Creating a Pod
-
Understanding a Pod Spec
-
Common Kubectl Commands
-
A Time-Saving Alias
-
Introducing Deployments
-
Creating a Deployment
-
Common Commands Around Deployments
-
Updating Deployments
-
Preferred Method for Updating Deployments
-
Networking With Services
-
Creating a NodePort Service
-
Accessing NodePort Services
-
Setting Up Cluster IP Services
-
Building a Deployment for the Event Bus
-
Adding ClusterIP Services
-
How to Communicate Between Services
-
Updating Service Addresses
-
Verifying Communication
-
Adding Query, Moderation and Comments
-
Testing Communication
-
Load Balancer Services
-
Load Balancers and Ingress
-
Installing Ingress-Nginx
-
Writing Ingress Config Files
-
Hosts File Tweak
-
Deploying the React App
-
Unique Route Paths
-
Final Route Config
-
Introducing Skaffold
-
Skaffold Setup
-
First Time Skaffold Startup
-
A Few Notes on Skaffold
-
IMPORTANT Note for Minikube and MicroK8s Users
-
ErrImagePull, ErrImageNeverPull and ImagePullBackoff Errors
-
Important - DO NOT SKIP - Ingress Nginx Installation Info
-
Ingress v1 API Required Update + pathType Warning
-
Important Note About Port 80
-
Important Note to Add Environment Variable
-
Skaffold API version Update
-
Note on Remote Development
-
Remote Dev with Skaffold
-
Google Cloud Initial Setup
-
Kubectl Contexts
-
Installing the GCloud Context
-
Updating the Skaffold Config
-
More Skaffold Updates
-
Creating a Load Balancer
-
Final Config and Test
-
Free Google Cloud Trial and Credits
-
Kubernetes Cluster Creation with Autopilot
-
Initializing the GCloud SDK
-
Creating Route Handlers
-
Scaffolding Routes
-
Adding Validation
-
Handling Validation Errors
-
Surprising Complexity Around Errors
-
Other Sources of Errors
-
Solution for Error Handling
-
Building an Error Handling Middleware
-
Communicating More Info to the Error Handler
-
Encoding More Information In an Error
-
Subclassing for Custom Errors
-
Determining Error Type
-
Converting Errors to Responses
-
Moving Logic Into Errors
-
Verifying Our Custom Errors
-
Final Error Related Code
-
How to Define New Custom Errors
-
Uh Oh... Async Error Handling
-
Postman HTTPS Issues
-
Property 'param' does not exist on type 'AlternativeValidationError'
-
SerializeErrors' not assignable to the same property in base type 'CustomError'
-
Creating Databases in Kubernetes
-
Connecting to MongoDB
-
Understanding the Signup Flow
-
Getting TypeScript and Mongoose to Cooperate
-
Creating the User Model
-
Type Checking User Properties
-
Adding Static Properties to a Model
-
Defining Extra Document Properties
-
What's That Angle Bracket For?
-
User Creation
-
Proper Error Handling
-
Reminder on Password Hashing
-
Adding Password Hashing
-
Comparing Hashed Password
-
Mongoose Pre-Save Hooks
-
Note on Password Hashing
-
Fundamental Authentication Strategies
-
Huge Issues with Authentication Strategies
-
So Which Option?
-
Solving Issues with Option #2
-
Reminder on Cookies vs JWT's
-
Microservices Auth Requirements
-
Issues with JWT's and Server Side Rendering
-
Cookies and Encryption
-
Adding Session Support
-
Generating a JWT
-
JWT Signing Keys
-
Securely Storing Secrets with Kubernetes
-
Creating and Accessing Secrets
-
Accessing Env Variables in a Pod
-
Common Response Properties
-
Formatting JSON Properties
-
The Signin Flow
-
Common Request Validation Middleware
-
Sign In Logic
-
Quick Sign In Test
-
Current User Handler
-
Returning the Current User
-
Signing Out
-
Creating a Current User Middleware
-
Augmenting Type Definitions
-
Requiring Auth for Route Access
-
Scope of Testing
-
Testing Goals
-
Testing Architecture
-
Index to App Refactor
-
A Few Dependencies
-
Test Environment Setup
-
Our First Test
-
An Important Note
-
Testing Invalid Input
-
Requiring Unique Emails
-
Changing Node Env During Tests
-
Tests Around Sign In Functionality
-
Testing Sign Out
-
Issues with Cookies During Testing
-
Easy Auth Solution
-
Auth Helper Function
-
Testing Non-Authed Requests
-
Replacing --only=prod Install Flag
-
Required MongoMemoryServer Updates
-
Cookie Request is Possibly Undefined Error
-
No Overload Matches This Call Error with Cookie
-
GlobalThis has no index signature TS Error
-
Starting the React App
-
Reminder on Server Side Rendering
-
Basics of Next JS
-
Building a Next Image
-
Running Next in Kubernetes
-
Note on File Change Detection
-
Adding Global CSS
-
Adding a Sign Up Form
-
Handling Email and Password Inputs
-
Successful Account Signup
-
Handling Validation Errors
-
The useRequest Hook
-
Using the useRequest Hook
-
An onSuccess Callback
-
Overview on Server Side Rendering
-
Fetching Data During SSR
-
Why the Error?
-
Two Possible Solutions
-
Cross Namespace Service Communication
-
When is GetInitialProps Called?
-
On the Server or the Browser
-
Specifying the Host
-
Passing Through the Cookies
-
A Reusable API Client
-
Content on the Landing Page
-
The Sign In Form
-
A Reusable Header
-
Moving GetInitialProps
-
Issues with Custom App GetInitialProps
-
Handling Multiple GetInitialProps
-
Passing Props Through
-
Building the Header
-
Conditionally Showing Links
-
Signing Out
-
Suggestion Regarding a Default Export Warning
-
Small Update for Custom Webpack Config
-
A note about ECONNREFUSED errors
-
Ingress-Nginx Namespace and Service - Important Update
-
Error: Invalid <Link> with <a> child
-
React App Catchup & Checkpoint
-
Ticketing Service Overview
-
Project Setup
-
Running the Ticket Service
-
Mongo Connection URI
-
Quick Auth Update
-
Test-First Approach
-
Creating the Router
-
Adding Auth Protection
-
Faking Authentication During Tests
-
Building a Session
-
Testing Request Validation
-
Validating Title and Price
-
Reminder on Mongoose with TypeScript
-
Defining the Ticket Model
-
Creation via Route Handler
-
Testing Show Routes
-
Unexpected Failure!
-
What's that Error?!
-
Better Error Logging
-
Complete Index Route Implementation
-
Ticket Updating
-
Handling Updates
-
Permission Checking
-
Final Update Changes
-
Manual Testing
-
A Required Session Fix and a Global Signin Reminder
-
What Now?
-
Three Important Items
-
Creating a NATS Streaming Deployment
-
Big Notes on NATS Streaming
-
Building a NATS Test Project
-
Port-Forwarding with Kubectl
-
Publishing Events
-
Listening For Data
-
Accessing Event Data
-
Client ID Generation
-
Queue Groups
-
Manual Ack Mode
-
Client Health Checks
-
Graceful Client Shutdown
-
Core Concurrency Issues
-
Common Questions
-
[Optional] More Possible Concurrency Solutions
-
Solving Concurrency Issues
-
Concurrency Control with the Tickets App
-
Event Redelivery
-
Durable Subscriptions
-
NATS Server Status - IMPORTANT NOTE
-
Small Required Command Change
-
Reusable NATS Listeners
-
The Listener Abstract Class
-
Extending the Listener
-
Quick Refactor
-
Leveraging TypeScript for Listener Validation
-
Subjects Enum
-
Custom Event Interface
-
Enforcing Listener Subjects
-
Enforcing Data Types
-
Where Does this Get Used?
-
Custom Publisher
-
Using the Custom Publisher
-
Awaiting Event Publication
-
Common Event Definitions Summary
-
Updating the Common Module
-
Restarting NATS
-
Quick Note: 'readonly' in Typescript
-
Publishing Ticket Creation
-
More on Publishing
-
NATS Client Singleton
-
Remember Mongoose?
-
Singleton Implementation
-
Accessing the NATS Client
-
Graceful Shutdown
-
Successful Listen!
-
Ticket Update Publishing
-
Failed Event Publishing
-
Handling Publish Failures
-
Fixing a Few Tests
-
Redirecting Imports
-
Providing a Mock Implementation
-
Test-Suite Wide Mocks
-
Ensuring Mock Invocations
-
NATS Env Variables
-
Node Nats Streaming Installation
-
TS Error - Did you forget to include 'void' in your type argument
-
The Orders Service
-
Scaffolding the Orders Service
-
A Touch More Setup
-
Ingress Routing Rules
-
Scaffolding a Few Route Handlers
-
Subtle Service Coupling
-
Associating Orders and Tickets
-
Order Model Setup
-
The Need for an Enum
-
Creating an Order Status Enum
-
More on Mongoose Refs
-
Defining the Ticket Model
-
Order Creation Logic
-
Finding Reserved Tickets
-
Convenience Document Methods
-
Order Expiration Times
-
Test Suite Setup
-
Asserting Tickets Exist
-
Asserting Reserved Tickets
-
Testing the Success Case
-
Fetching a User's Orders
-
A Slightly Complicated Test
-
Fetching Individual Orders
-
Does Fetching Work?
-
Cancelling an Order
-
Can We Cancel?
-
GlobalThis has no index signature TS Error
-
Small Update for "Value of type 'typeof ObjectId' is not callable"
-
Time for Listeners!
-
Reminder on Listeners
-
Blueprint for Listeners
-
A Few More Reminders
-
Simple onMessage Implementation
-
ID Adjustment
-
Ticket Updated Listener Implementation
-
Initializing the Listeners
-
A Quick Manual Test
-
Clear Concurrency Issues
-
Reminder on Versioning Records
-
Optimistic Concurrency Control
-
Mongoose Update-If-Current
-
Implementing OCC with Mongoose
-
Testing OCC
-
One More Test
-
Who Updates Versions?
-
Including Versions in Events
-
Updating Tickets Event Definitions
-
Applying a Version Query
-
Did it Work?
-
Abstracted Query Method
-
[Optional] Versioning Without Update-If-Current
-
Testing Listeners
-
A Complete Listener Test
-
Testing the Ack Call
-
Testing the Ticket Updated Listener
-
Success Case Testing
-
Out-Of-Order Events
-
The Next Few Videos
-
Fixing a Few Tests
-
Listeners in the Tickets Service
-
Building the Listener
-
Strategies for Locking a Ticket
-
Reserving a Ticket
-
Setup for Testing Reservation
-
Test Implementation
-
Missing Update Event
-
Private vs Protected Properties
-
Publishing While Listening
-
Mock Function Arguments
-
Order Cancelled Listener
-
A Lightning-Quick Test
-
Don't Forget to Listen!
-
Rejecting Edits of Reserved Tickets
-
Heads Up Regarding Some Mongoose TS Errors
-
Test functions cannot both take a 'done' callback and return something Error
-
Property 'version' is missing TS Errors After Running Skaffold
-
The Expiration Service
-
Expiration Options
-
Initial Setup
-
A Touch of Kubernetes Setup
-
File Sync Setup
-
Listener Creation
-
What's Bull All About?
-
Creating a Queue
-
Queueing a Job on Event Arrival
-
Testing Job Processing
-
Delaying Job Processing
-
Defining the Expiration Complete Event
-
Publishing an Event on Job Processing
-
Handling an Expiration Event
-
Emitting the Order Cancelled Event
-
Testing the Expiration Complete Listener
-
A Touch More Testing
-
Listening for Expiration
-
Skaffold errors - Expiration Image Can't be Pulled
-
The Payments Service
-
Initial Setup
-
Replicated Fields
-
Another Order Model!
-
Update-If-Current
-
Replicating Orders
-
Testing Order Creation
-
Marking an Order as Cancelled
-
Cancelled Testing
-
Starting the Listeners
-
Payments Flow with Stripe
-
Implementing the Create Charge Handler
-
Validating Order Payment
-
Testing Order Validation Before Payment
-
Testing Same-User Validation
-
Stripe Setup
-
Creating a Stripe Secret
-
Creating a Charge with Stripe
-
Manual Testing of Payments
-
Automated Payment Testing
-
Mocked Stripe Client
-
A More Realistic Test Setup
-
Realistic Test Implementation
-
Tying an Order and Charge Together
-
Testing Payment Creation
-
Publishing a Payment Created Event
-
More on Publishing
-
Marking an Order as Complete
-
Don't Cancel Completed Orders!
-
GlobalThis has no index signature TS Error
-
Important Info About the Next Lecture - Don't Skip
-
A Few More Pages
-
Reminder on Data Fetching with Next
-
Two Quick Fixes
-
Scaffolding a Form
-
Sanitizing Price Input
-
Ticket Creation
-
Listing All Tickets
-
Linking to Wildcard Routes
-
Creating an Order
-
Programmatic Navigation to Wildcard Routes
-
The Expiration Timer
-
Displaying the Expiration
-
Showing a Stripe Payment Form
-
Configuring Stripe
-
Test Credit Card Numbers
-
Paying for an Order
-
Filtering Reserved Tickets
-
Header Links
-
Rendering a List of Orders
-
Reminder on Invalid <Link> with <a> child Errors
-
Module not found: Can't resolve 'prop-types'
-
Development Workflow
-
Git Repository Approaches
-
Creating a GitHub Action
-
Adding a CI Test Script
-
Running Tests on PR Creation
-
Output of Failing Tests
-
Running Tests in Parallel
-
Verifying a Test Run
-
Selective Test Execution
-
Deployment Options
-
Creating a Hosted Cluster
-
Reminder on Kubernetes Context
-
Reminder on Swapping Contexts
-
The Deployment Plan
-
Building an Image in an Action
-
Testing the Image Build
-
Restarting the Deployment
-
Applying Kubernetes Manifests
-
Prod vs Dev Manifest Files
-
Manual Secret Creation
-
Don't Forget Ingress-Nginx!
-
Testing Automated Deployment
-
Additional Deploy Files
-
A Successful Deploy!
-
Buying a Domain Name
-
Configuring the Domain Name
-
I Really Hope This Works
-
Next Steps
-
Tests in GitHub Actions Hang - Jest did not exit
-
Three Important Changes Needed to Deploy - Do Not Skip!
-
Why Use Docker?
-
What is Docker?
-
Docker for Mac / Windows
-
Using the Docker Client
-
But Really... What's a Container?
-
How's Docker Running on Your Computer?
-
Docker Run in Detail
-
Overriding Default Commands
-
Listing Running Containers
-
Container Lifecycle
-
Restarting Stopped Containers
-
Removing Stopped Containers
-
Retrieving Output Logs
-
Stopping Containers
-
Multi-Command Containers
-
Executing Commands in Running Containers
-
The Purpose of the 'it' Flag
-
Getting a Command Prompt in a Container
-
Starting with a Shell
-
Container Isolation
-
Creating Docker Images
-
Building a Dockerfile
-
Dockerfile Teardown
-
What's a Base Image?
-
The Build Process in Detail
-
A Brief Recap
-
Rebuilds with Cache
-
Tagging an Image
-
Manual Image Generation with Docker Commit
-
Project Outline
-
Node Server Setup
-
A Few Planned Errors
-
Base Image Issues
-
A Few Missing Files
-
Copying Build Files
-
Container Port Forwarding
-
Specifying a Working Directory
-
Unnecessary Rebuilds
-
Minimizing Cache Busting and Rebuilds
-
Finished Code and Diagrams
-
Installing Docker on macOS
-
Installing Docker with WSL2 on Windows 10/11
-
Installing Docker on Linux
-
Buildkit for Docker Desktop
-
Quick Note for Windows Users
-
Reminder on Build Kit
-
How to Get Help
-
TypeScript Overview
-
Environment Setup
-
A First App
-
Executing Typescript Code
-
One Quick Change
-
Catching Errors with TypeScript
-
Catching More Errors!
-
Do Not Skip - Course Overview
-
Types
-
More on Types
-
Examples of Types
-
Where Do We Use Types?
-
Type Annotations and Inference
-
Annotations With Variables
-
Object Literal Annotations
-
Annotations Around Functions
-
Understanding Inference
-
The Any Type
-
Fixing the "Any" Type
-
Delayed Initialization
-
When Inference Doesn't Work
-
More on Annotations Around Functions
-
Inference Around Functions
-
Annotations for Anonymous Functions
-
Void and Never
-
Destructuring with Annotations
-
Annotations Around Objects
-
Arrays in TypeScript
-
Why Typed Arrays?
-
Multiple Typees in Arrays
-
When to Use Typed Arrays
-
Tuples in TypeScript
-
Tuples in Action
-
Why Tuples?
-
Interfaces
-
Long Type Annotations
-
Fixing Annotations With Interfaces
-
Syntax Around Interfaces
-
Functions in Interfaces
-
Code Reuse with Interfaces
-
General Plan with Interfaces
-
Classes
-
Basic Inheritance
-
Class Method Modifiers
-
Fields in Classes
-
Fields with Inheritance
-
Where to Use Classes
-
App Overview
-
Bundling with Parcel
-
Project Structure
-
Generating Random Data
-
Type Definition Files
-
Using Type Definition Files
-
Export Statements in TypeScript
-
Defining a Company
-
Adding Google Maps Support
-
Google Maps Integration with TypeScript
-
Exploring Type Definition Files
-
Hiding Functionality
-
Why Use Private Modifiers? Here's Why
-
Adding Markers
-
Duplicate Code
-
One Possible Solution
-
Restricting Access with Interfaces
-
Implicit Type Checks
-
Showing Popup Windows
-
Updating Interface Definitions
-
Optional Implements Clauses
-
App Wrapup
-
Important Update About ts-node and Axios
-
Updated Parcel Instructions
-
IMPORTANT Info About Faker Installation
-
Important Note About Google Maps Key
-
Required Update for New @types Library
Requirment
-
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
Outcomes
-
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!
Instructor
Nguyễn Đình Cường
1.2
-
1 Student
-
330 Courses
-
1253 reviews
Xin chào các bạn, tôi là Nguyễn Đình Cường, một lập trình viên và giảng viên đam mê công nghệ với hơn 15 năm kinh nghiệm trong ngành công nghiệp phần mềm. Tôi tốt nghiệp từ Bưu Chính Viễn Thông và đã từng làm việc cho một số công ty công nghệ hàng đầu như FPT Software và VinGroup. Với chuyên môn chính là phát triển ứng dụng web, tôi đã làm việc với nhiều công nghệ như HTML, CSS, JavaScript, React cho front-end và Node.js, Express, MongoDB cho back-end. Không chỉ dừng lại ở việc viết mã, tôi còn yêu thích tìm hiểu sâu về thiết kế hệ thống và kiến trúc phần mềm. Tôi tin rằng quá trình học lập trình không chỉ đơn thuần là lý thuyết, mà còn là sự trải nghiệm thực tế và giải quyết vấn đề. Trong các khóa học của mình, tôi cố gắng cung cấp cho học viên những bài giảng thú vị và dễ hiểu, cùng với các bài tập thực hành giúp củng cố kiến thức. Tôi hy vọng rằng qua các khóa học của mình, bạn sẽ không chỉ học được cách viết mã, mà còn phát triển tư duy lập trình và kỹ năng giải quyết vấn đề. Hãy cùng nhau khám phá thế giới lập trình và biến ý tưởng của bạn thành hiện thực! Nếu bạn có bất kỳ câu hỏi nào, đừng ngần ngại liên hệ với tôi. Tôi rất vui được hỗ trợ bạn trong hành trình học tập của mình!
View Details