Page
1
(This page has no text content)
Page
2
Scalable Application Development with NestJS Leverage REST, GraphQL, microservices, testing, and deployment for seamless growth Pacifique Linjanja
Page
3
Scalable Application Development with NestJS Copyright © 2025 Packt Publishing All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews. The author acknowledges the use of cutting-edge AI, such as ChatGPT, with the sole aim of enhancing the language and clarity within the book, thereby ensuring a smooth reading experience for readers. It’s important to note that the content itself has been crafted by the author and edited by a professional publishing team. Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the author, nor Packt Publishing or its dealers and distributors, will be held liable for any damages caused or alleged to have been caused directly or indirectly by this book. Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information. Group Product Manager: Kaustubh Manglurkar Publishing Product Manager: Chayan Majumdar Book Project Manager: Srinidhi Ram Senior Content Development Editor: Feza Shaikh Technical Editor: Simran Ali Copy Editor: Safis Editing Indexer: Tejal Soni Production Designer: Ponraj Dhandapani DevRel Marketing Coordinator: Nivedita Pandey First published: January 2025 Production reference: 1051224 Published by Packt Publishing Ltd. Grosvenor House 11 St Paul’s Square Birmingham B3 1RB, UK. ISBN 978-1-83546-860-9 www.packtpub.com
Page
4
To my parents, my sisters, and my brothers for their love and support. – Pacifique Linjanja
Page
5
Contributors About the author Pacifique Linjanja is a skilled software engineer known for building enterprise-level applications with technologies such as NestJS. He has led diverse development teams globally, delivering scalable, efficient software solutions across multiple projects. In addition to his work, Pacifique actively contributes to open source communities, sharing his expertise and insights through technical talks and coding workshops. He enjoys mentoring new developers and continues to broaden his knowledge by exploring various fields beyond technology, believing in the importance of learning and giving back to the tech community. I want to thank the people who have been close to me and supported me, especially my brother Ansima and my parents.
Page
6
About the reviewer Piyush Kacha is the co-founder of Anwit, where technology becomes a canvas for creativity and innovation is the brush. He graduated with a Bachelor of Engineering from Gujarat Technological University in 2019. While still in college, he joined Kevit Technologies in 2018 as a backend engineer and advanced to team lead over four years. In 2022, driven by an entrepreneurial spirit, he co-founded Anwit to craft IT solutions that not only work but also bring joy. A lifelong learner, he is currently exploring Gleam, a functional programming language designed to eliminate runtime errors. Piyush is passionate about transforming challenges into opportunities, continually pushing the boundaries of innovation in the tech world. I owe my deepest gratitude to my family and colleagues for their unwavering support and belief in my vision. Your encouragement has been the cornerstone of my journey, inspiring me to overcome challenges and strive for excellence. A heartfelt thank you to the incredible teams at Kevit Technologies and Anwit for fostering an environment where innovation thrives. This accomplishment would not have been possible without all of you.
Page
7
(This page has no text content)
Page
8
Preface xix Part 1: Introduction to NestJS and Scalable Application Architecture 1 Overview of NestJS 3 Technical requirements 3 Introduction to NestJS 4 Historical context 4 Problem statement – the need for NestJS 5 NestJS versus other frameworks – a comparative analysis 5 Key advantages of using NestJS 8 The power of TypeScript 8 Why TypeScript? 9 The value proposition – what does TypeScript offer? 9 Code snippet – TypeScript in action 10 TypeScript and NestJS – a perfect synergy 10 Code snippet – NestJS with TypeScript 11 Key features of NestJS 11 Modularity 11 Dependency injection 13 Decorators 14 Guards 15 Exception filters 16 Pipes 19 Interceptors 20 The ecosystem of NestJS 21 Third-party modules 21 Nest CLI 21 Community support 22 Why choose NestJS? 23 Summary 24 Table of Contents
Page
9
Table of Contentsviii 2 Understanding Scalable Application Architecture Principles and Design Patterns 25 Technical requirements 26 Principles of Scalable Application Architecture 26 Your app as a growing city 26 The three Ss of scalability 27 The importance of modular design – a double-edged sword 27 Statelessness – the cornerstone of horizontal scaling 29 Database scalability – sharding, replication, and partitioning 30 The social network of microservices – event- driven architecture 30 Load balancing and horizontal scaling 32 Caching strategies for performance optimization 33 Types of caching – knowing your tools 33 The ABCs of caching strategies 33 Caching in the NestJS universe 34 Design patterns for building scalable NestJS applications 36 Why design patterns matter 36 The singleton pattern for managing global state 36 The factory pattern for object creation 37 Dependency injection for loose coupling 37 The decorator pattern for extending functionality in NestJS 38 Why decorators make NestJS outstanding 42 Understanding asynchronous programming for scalability 43 What is asynchronous programming? 43 Why asynchrony is important for scalability 43 Improved user experience 43 Asynchronous programming in NestJS 44 Event loop and non-blocking I/O 44 Best practices for building scalable applications 45 Code organization is key 45 Optimizing data storage and retrieval 45 Embracing microservices for decoupling 46 Automating testing and deployment 46 Making use of middleware and interceptors 46 Don’t neglect security 46 Leveraging load balancing 46 Using application metrics for insights 47 Summary 47 3 Setting Up Your NestJS Environment and Exploring NestJS – Building a Robust App 49 Technical requirements 50 Installing Node.js and NestJS 50 Step 1 – Install Node.js 50 Step 2 – Install the NestJS CLI 51 Scaffolding a new NestJS project 51 Creating a new NestJS project 51
Page
10
Table of Contents ix The birth of a NestJS project 52 Understanding the NestJS project structure 55 Why is NestJS’s project structure important? 55 The src/ directory 55 The dist/ directory 57 The node_modules/ directory 57 The test/ directory 57 Configuration files – tsconfig.json and nest- cli.json 58 Creating and managing modules 58 What are modules in NestJS? 58 The role of the root module 58 Creating a new module 59 Managing modules 61 Building controllers for handling requests 62 What is a controller in NestJS? 62 Crafting your first controller 62 Handling requests with decorators 63 Dynamic routes and parameters 64 Implementing providers for business logic 64 What is a provider in NestJS? 64 Crafting your first provider 64 Dependency injection – the magic behind providers 65 Custom providers – beyond classes 66 Handling exceptions with exception filters 67 What are exception filters? 67 Crafting a basic exception filter 67 Validating data with pipes and guards 68 Pipes – transforming and validating 68 Guards – protecting routes 70 Summary 71 4 Advanced Concepts – Modules, Controllers, Providers, Exception Filters, Pipes, Guards, and Decorators 73 Technical requirements 74 Diving deeper into modules 74 The essence of modular thinking 74 Why it’s more than just organization 74 The fundamental role of modules in NestJS 75 Creating and initializing a module 76 The application module graph 78 Sharing modules across the application 85 Modular organization for large-scale applications 86 NestJS controller essentials and advanced practices 87 Creating your first controller 88 Basic routing in controllers 88 Parameterized routes 89 Scaling your controllers 92 Refined request handling 93 Advanced Data Transfer Objects and validation pipelines 96 Response transformation – interceptors in action 101 Middleware – the uncelebrated controller companions 103 Deep dive into route guards 108 Streaming data with NestJS controllers 112
Page
11
Table of Contentsx Advanced WebSocket patterns 114 Understanding providers in depth 118 Brief recap – providers and modules 118 What constitutes a provider in NestJS? 119 Injecting providers into modules, controllers, and other providers 120 Custom providers 121 Asynchronous providers 122 Exporting providers from modules 123 Enhancers as a special kind of provider 123 Advanced techniques and best practices 124 Understanding request lifecycle 124 Summary 126 Part 2: REST APIs and GraphQL in NestJS 5 Building and Optimizing REST APIs with NestJS 129 Technical requirements 129 Introduction to REST APIs in NestJS 130 Building a basic REST API 130 Setting up your REST API project 130 Designing your first RESTful endpoint 131 Integrating advanced concepts into your API 135 Reflecting on REST API best practices 153 Versioning your API 156 Context for v2 156 Introduction to API versioning concepts 157 Setting up the version 2 infrastructure 157 Robust error handling in REST APIs 162 Understanding error handling 162 Key aspects of robust error handling 163 Implementing error handling in the user management API 163 Best practices for client-friendly errors 164 Documenting your API 165 The importance of API documentation 165 Key components of effective API documentation 165 Implementing documentation in the user management API 166 Adding Swagger annotations to DTOs and entities 166 Setting up Swagger in the controller 167 Generating Swagger documentation 168 Keeping documentation up to date 169 Example – complete user management API Swagger documentation 170 Best practices for maintaining API documentation 170 Summary 171
Page
12
Table of Contents xi 6 Unleashing the Power of GraphQL and the Apollo Federation Architecture in NestJS 173 Technical requirements 174 Understanding GraphQL fundamentals in NestJS 174 What is GraphQL? 174 GraphQL and NestJS – a perfect match 175 Advantages of using GraphQL with NestJS 175 Big companies using GraphQL in production 176 Building and optimizing a GraphQL API with NestJS 176 Contextualizing our application 176 Two approaches to GraphQL with NestJS 177 Code-first approach 177 Schema-first approach 185 Learning about GraphQL subscriptions 189 Implementing and testing subscriptions in NestJS 189 Securing GraphQL – authentication and authorization 193 Understanding the differences 194 Authentication in GraphQL 194 Authorization in GraphQL 195 Introduction to Apollo Federation 195 Federation in microservices architecture 196 What is Apollo Federation? 196 Summary 197 Part 3: Testing and Debugging APIs in NestJS 7 Testing and Debugging REST APIs in NestJS 201 Technical requirements 202 Understanding the importance of testing 202 The painful cost of skipping tests 202 The powers of testing in NestJS 203 Unit testing in NestJS 203 Identifying units in the existing application 204 Writing unit tests for the users’ service 204 Test coverage 209 Integration testing in NestJS 210 Preparation for integration testing 211 Overview of the user management application 213 Preparing the test environment 214 Simulating HTTP requests and asserting responses 215 Testing controller files 219 Testing guards, interceptors, and middleware 222 Testing MockAuthguard 223 Testing the response interceptor 225 Testing middleware 227
Page
13
Table of Contentsxii Debugging REST APIs 230 Understanding the issue 230 Leveraging debugging tools 231 Enhancing debugging with environment variables 232 Leveraging NestJS DevTools for a streamlined development experience 232 Real-world debugging scenario revisited 233 Common pitfalls and how to address them 234 Debugging in action – a step-by-step example 234 Summary 235 8 Testing and Debugging GraphQL APIs in NestJS 237 Technical requirements 238 Unit testing for GraphQL resolvers 238 Setting up for testing 238 Writing unit tests for resolvers 238 Mocking dependencies 239 Testing resolver logic 240 E2E testing in GraphQL 242 Debugging GraphQL APIs 247 Understanding debugging challenges for GraphQL APIs 248 Leveraging debugging with built-in NestJS tools 249 Using exception filters for enhanced error handling 251 Apollo Server debugging tools 252 Best practices for debugging GraphQL APIs in production 255 Summary 257 Part 4: Scaling with Microservices and NestJS 9 Deep Dive into Microservices: Concepts and Architectural Styles 261 Technical requirements 262 Understanding microservices 262 What are microservices? 262 Benefits of microservices architecture 263 Microservices architectural styles 264 Key microservices architectural styles 264 EDA 264 Database per service 266 API Gateway 267 Command-Query Responsibility Segregation (CQRS) 269 Saga pattern 270 API composition 270 Best practices and considerations 270 Summary 271
Page
14
Table of Contents xiii 10 Building Scalable Microservices with NestJS 273 Technical requirements 274 Defining and implementing microservices in NestJS 274 Setting up a new project 274 Setting up a new microservice project 275 Overview of the microservices package in NestJS 276 Introduction to @nestjs/microservices 276 Key features and advantages 276 Implementing a simple communication example 277 Inter-service communication and data integrity in NestJS 278 Key features of the application 280 The order service 281 API gateway, our gatekeeper 295 Service discovery with Consul in NestJS 298 Best practices for building microservices with NestJS 303 Structure and modularization 303 Configuration management 303 Inter-service communication 303 Resilience and error handling 303 Data management 304 Logging and monitoring 304 Testing and CI/CD 304 API Gateway and security 304 Troubleshooting and debugging microservices 305 Centralized logging 305 Tracing and monitoring 305 Service health and resilience 305 Debugging techniques 306 Version control and rollback 306 Dependency management 306 Service isolation and testing 306 Documentation and knowledge sharing 307 Summary 307 11 Testing and Debugging Microservices in NestJS 309 Technical requirements 310 Unit testing for microservices 310 Testing createOrder in the order service 310 Integration testing for microservices 313 Integration testing for order creation and inventory update 314 Emitting events and testing inventory processing 317 Debugging common issues and solutions in microservices testing 319 Issue 1 – microservices failing to connect 319 Issue 2 – unreliable event emission between microservices 321 Issue 3 – inconsistent data between microservices 323 Issue 4 – slow performance in inter-service communication 325
Page
15
Table of Contentsxiv Best practices for testing and debugging microservices 327 Isolating microservices for unit testing 327 Using environment variables for configurations 329 Leveraging integration testing for cross-service communication 329 Enabling retry mechanisms for robustness 331 Using NestJS DevTools for real-time debugging 331 Monitoring and tracing distributed systems 332 Using sagas for distributed transactions 336 Summary 337 Part 5: Real-World Application Examples and Case Studies 12 Case Study 1 - E-commerce Application 341 Technical requirements 342 Understanding the requirements of an e-commerce application 342 Identifying user needs 342 Defining functional requirements 343 Setting performance requirements 344 Designing the application architecture and data modeling 344 Steps to design a REST API 345 Creating resource URIs 345 Representing resources 346 Assigning HTTP methods 347 Writing APIs 349 Implementing REST APIs for products and orders 351 Setting up the development environment 351 Database setup and configuration 351 Implementing the product API endpoints 354 Implementing the Order API endpoints 372 Common logic and interceptors 381 User authentication and authorization in an e-commerce context 388 Setting up the User module 389 Creating the User entity 389 Implementing the service file 390 Route handlers and the controller file 392 Authentication module 396 Authentication controllers 400 Authentication guard 401 Summary 403 13 Case Study 2 – Social Networking Platform 405 Technical requirements 406 Understanding the requirements of a social networking platform 406 Users’ needs 406 Functional requirements 406 Non-functional requirements 407
Page
16
Table of Contents xv Designing the application structure for social networking 408 Object model 408 Relationships between objects 410 Database schema design 410 API design 412 Implementing GraphQL APIs for users, posts, and interactions 413 Setting up the project 413 Creating the Users module 414 Creating the Posts module 418 Creating the Interaction module 421 Creating the Reactions module 425 User relationships and social features 429 Adding social features 429 Implementing these features 430 Posting real-time updates and notifications in a social networking context 431 Customizing notifications based on user preferences 438 Summary 442 14 Case Study 3 – Enterprise Resource Planning System 443 Technical requirements 444 Understanding the requirements of an ERP system 444 Functional requirements 444 Non-functional requirements 445 Designing the system architecture for an ERP system 447 High-level architecture overview 447 Microservices architecture design 448 Database design and data management 449 API gateway and communication patterns 449 Implementing microservices for scalability and modularity 450 Creating individual microservices 450 Setting up communication between microservices 455 Ensuring scalability and modularity 457 Example code for a complete microservice 460 Complete guide to Dockerizing microservices 462 Deploying microservices to Kubernetes 464 Implementing security best practices 466 Data synchronization and consistency in an ERP context 468 Understanding data consistency models 468 Data synchronization strategies 468 Implementing data synchronization in an ERP system 473 Handling complex business processes and workflows 478 Understanding business processes and workflows 478 Modeling business processes 479 Orchestrating business processes 480 Automating business processes 481 Error handling in workflows 482 Integrating with external systems 483 Monitoring and managing workflows 484 Summary 486
Page
17
Table of Contentsxvi Part 6: Deployment, DevOps, and Beyond 15 Deploying NestJS Applications 489 Technical requirements 490 Configuring a local server for production-like testing 490 Preparing your NestJS application for deployment 490 Setting up a local server (NGINX, Apache, etc.) 491 Configuring SSL for HTTPS 493 Basic monitoring and logging 495 Deployment using Docker 496 Creating a Dockerfile for your NestJS application 497 Building and running your Docker container 498 Optimizing your Docker image for production 499 Deployment on Cloud platforms 500 Deploying to AWS Elastic Beanstalk 500 Deploying to Google Cloud Run 501 Deploying to Azure App Service 501 Post-deployment best practices 502 Monitoring and logging 502 Security and updates 503 Backup and disaster recovery 503 Scaling and load balancing 504 Summary 505 Further reading 505 16 Embracing DevOps: Continuous Integration and Continuous Deployment for NestJS 507 Understanding continuous integration and continuous deployment 508 Continuous integration 508 Continuous deployment 508 Why is CI/CD important for your NestJS application? 508 Choosing your CI/CD tools 509 Criteria to consider when selecting CI/CD tools 510 Popular CI/CD tools 511 Setting up a CI/CD pipeline for NestJS 512 Writing CI/CD actions in GitHub 513 Deploying to staging 515 CI/CD best practices 517 Summary 518
Page
18
Table of Contents xvii 17 NestJS Performance Optimization 521 Technical requirements 522 Understanding performance optimization 522 Code optimization techniques 522 Efficient data handling 523 Reduce middleware and route complexity 523 Optimizing dependency management 523 Memory management 524 Database optimization techniques 524 Optimizing database queries 524 Caching strategies for NestJS 526 In-memory caching with cache-manager 526 Distributed caching with Redis 527 HTTP caching with @CacheKey and @CacheTTL 528 Cache busting 528 Profiling and load testing 529 Profiling a NestJS application 529 Load testing a NestJS application 532 Best practices for performance optimization 533 Monitor and benchmark regularly 534 Optimize resource allocation 535 Leverage asynchronous programming and non-blocking I/O 535 Minimize payload sizes 536 Implement efficient logging 536 Summary 539 18 NestJS Security Best Practices 541 Technical requirements 541 Understanding application security 542 The importance of application security 542 Common security challenges 542 Risks of unsecured applications 543 Defense-in-depth – a layered approach to security 543 Data security in NestJS 544 Securing data in transit 544 Securing data at rest 545 Access control 547 Authentication and authorization in NestJS 548 A quick review – authentication 549 Strengthening authorization mechanisms 549 Best practices for authentication and authorization 550 Preventing common security threats 550 Overview of common security threats 550 XSS prevention 551 SQL injection mitigation 551 CSRF prevention 552 Defending against DoS and DDoS attacks 552 Protecting against MitM attacks 552 Security best practices in NestJS 553 Secure development practices 553 Secure configuration management 554
Page
19
Table of Contentsxviii Access control and least privilege 554 Secure data handling 554 Regular security audits and penetration testing 555 Incident response planning 555 Summary 555 Appendix Concluding Remarks and Next Steps 557 Key takeaways from the book 558 Mastering the NestJS core concepts 558 Building robust APIs with NestJS 558 Implementing security best practices 558 Embracing testing and validation 558 Scaling applications for the real world 558 Exploring the NestJS ecosystem further 559 Diving into official modules and libraries 559 Integrating with third-party tools 559 Contributing to the NestJS community 559 Keeping up with NestJS updates and best practices 559 Following the official NestJS repository 559 Participating in NestJS conferences and meetups 560 Continuous learning and experimentation 560 Other useful resources 560 Books and online courses 560 Blogs and tutorials 560 Official and community forums 560 Real-world success stories with NestJS 561 Avoiding common pitfalls 561 Final words 562 Embrace lifelong learning 562 Stay connected with the community 562 Your journey ahead 563 Index 565 Other Books You May Enjoy 584
Page
20
Preface NestJS is a powerful framework for building efficient, scalable, and maintainable server-side applications. With its modular architecture and native TypeScript support, NestJS allows developers to streamline the process of building REST APIs, GraphQL APIs, and microservices. This book, Scalable Application Development with NestJS, is a complete guide to using NestJS to develop robust applications that can grow with your business needs. Through practical examples, you’ll learn how to integrate testing strategies, deploy seamlessly with CI/CD pipelines, and scale effortlessly in production environments. Who this book is for If you are a software engineer, developer, or tech lead aiming to gain a deeper understanding of how to build scalable applications using NestJS, REST, GraphQL, and microservices, this book is for you. Whether you’re new to NestJS or a seasoned developer, this guide provides a comprehensive approach to leverage NestJS for your next big project. It’s also ideal for project managers and other IT professionals seeking insights into enterprise-level efficient development, testing strategies, and deployment processes. Even technology enthusiasts will find this book enlightening. What this book covers Chapter 1, Overview of NestJS, is an introduction to what NestJS NestJS is and what it is capable of. Chapter 2, Understanding Scalable Application Architecture Principles and Design Patterns, dives into the principles of scalable application architecture and the essential design patterns and best practices used for building scalable applications in NestJS. This chapter covers the fundamental concepts of scalability, such as load balancing, caching, and horizontal scaling. Chapter 3, Setting Up Your NestJS Environment and Exploring NestJS – Building a Robust App, is a comprehensive guide to setting up the development environment for NestJS and exploring the framework by building a robust application. It covers the installation of NestJS and NestJS, along with the configuration of essential tools such as npm and TypeScript. Chapter 4, Advanced Concepts – Modules, Controllers, Providers, Exception Filters, Pipes, Guards, and Decorators, delves deeper into NestJS and its advanced features. You will discover modules, controllers, providers, exception filters, pipes, guards, and decorators – all crucial components for building scalable and efficient NestJS applications.