2025-03-23 | Modern Full-Stack Development with TypeScript (Cont.)

Introduction

This seminar is the second part of the Modern Full-Stack Development with TypeScript seminar.

Part 4: Database Layer with PostgreSQL and Prisma (25 minutes)

PostgreSQL Overview

PostgreSQL is a powerful, open-source object-relational database system with over 30 years of active development.

Key features:

  • Strong standards compliance
  • Extensibility
  • Robust transaction support
  • Multi-version concurrency control
  • Advanced data types and indexing

Prisma: Modern Database Access

Prisma is an open-source database toolkit that includes:

  1. Prisma Client: Auto-generated and type-safe query builder
  2. Prisma Migrate: Declarative data modeling and migration system
  3. Prisma Studio: GUI to view and edit data

Demo: Defining a Data Model with Prisma

// schema.prisma
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  name      String?
  password  String
  role      Role     @default(USER)
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  orders    Order[]
}

model Product {
  id          Int      @id @default(autoincrement())
  name        String
  description String?
  price       Decimal  @db.Decimal(10, 2)
  stock       Int      @default(0)
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt
  orderItems  OrderItem[]
}

model Order {
  id        Int         @id @default(autoincrement())
  userId    Int
  user      User        @relation(fields: [userId], references: [id])
  status    OrderStatus @default(PENDING)
  createdAt DateTime    @default(now())
  updatedAt DateTime    @updatedAt
  items     OrderItem[]
}

model OrderItem {
  id        Int     @id @default(autoincrement())
  orderId   Int
  order     Order   @relation(fields: [orderId], references: [id])
  productId Int
  product   Product @relation(fields: [productId], references: [id])
  quantity  Int
  price     Decimal @db.Decimal(10, 2)
}

enum Role {
  USER
  ADMIN
}

enum OrderStatus {
  PENDING
  PROCESSING
  SHIPPED
  DELIVERED
  CANCELLED
}

Connecting Prisma to Nest.js

// prisma.service.ts
import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
  async onModuleInit() {
    await this.$connect();
  }

  async onModuleDestroy() {
    await this.$disconnect();
  }
}

Best Practices for Database Management

  • Transaction management
  • Database migration strategies
  • Query optimization
  • Connection pooling
  • Data validation and integrity
  • Seeding strategies for development and testing

Part 5: API Documentation with Swagger (15 minutes)

Swagger Overview

Swagger (OpenAPI) provides a standard, language-agnostic interface to RESTful APIs.

Benefits:

  • Interactive documentation
  • Client SDK generation
  • Standardized API description
  • Testing capabilities

Integrating Swagger with Nest.js

// main.ts
import { NestFactory } from '@nestjs/core';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  
  // Global validation pipe
  app.useGlobalPipes(new ValidationPipe({ transform: true }));
  
  // Swagger setup
  const config = new DocumentBuilder()
    .setTitle('E-commerce API')
    .setDescription('The e-commerce API description')
    .setVersion('1.0')
    .addTag('e-commerce')
    .addBearerAuth()
    .build();
    
  const document = SwaggerModule.createDocument(app, config);
  SwaggerModule.setup('api', app, document);
  
  await app.listen(3000);
}
bootstrap();

Documenting API Endpoints

  • Using decorators to document controllers and methods
  • Describing data transfer objects (DTOs)
  • Adding authentication requirements
  • Managing API versions

Part 6: Containerization with Docker (20 minutes)

Docker Overview

Docker provides a way to package applications with all their dependencies into standardized units called containers.

Benefits:

  • Consistent environments
  • Isolation
  • Portability
  • Efficiency
  • Scalability

Dockerizing Our Application

# Dockerfile
FROM node:16 AS builder

WORKDIR /app

# Copy package files and install dependencies
COPY package*.json ./
RUN npm ci

# Copy source files and build application
COPY . .
RUN npm run build

# Production stage
FROM node:16-alpine

WORKDIR /app

# Copy built application from builder stage
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package*.json ./

# Set environment variables
ENV NODE_ENV production
ENV PORT 3000

# Expose application port
EXPOSE 3000

# Start the application
CMD ["node", "dist/main"]

Docker Compose for Multi-Container Setup

# docker-compose.yml
version: '3.8'

services:
  api:
    build:
      context: ./backend
      dockerfile: Dockerfile
    ports:
      - '3000:3000'
    depends_on:
      - postgres
    environment:
      - DATABASE_URL=postgresql://postgres:postgres@postgres:5432/myapp
      - NODE_ENV=production
      - JWT_SECRET=your_jwt_secret
    restart: always

  client:
    build:
      context: ./frontend
      dockerfile: Dockerfile
    ports:
      - '80:80'
    depends_on:
      - api
    restart: always

  postgres:
    image: postgres:14
    ports:
      - '5432:5432'
    environment:
      - POSTGRES_PASSWORD=postgres
      - POSTGRES_USER=postgres
      - POSTGRES_DB=myapp
    volumes:
      - postgres-data:/var/lib/postgresql/data
    restart: always

volumes:
  postgres-data:

Best Practices for Containerization

  • Multi-stage builds for smaller images
  • Using specific versions for stability
  • Security considerations
  • Resource constraints
  • Container orchestration with Kubernetes

Part 7: Integration and Deployment (15 minutes)

Bringing Everything Together

  1. CI/CD Pipeline Setup

    • GitHub Actions or GitLab CI
    • Build and test automation
    • Docker image creation and pushing
    • Deployment to cloud platforms
  2. Environment Management

    • Managing environment variables
    • Development, staging, and production configurations
    • Secrets management
  3. Monitoring and Logging

    • Health checks and monitoring
    • Centralized logging
    • Performance metrics

Deployment Options

  • AWS, Google Cloud, or Azure
  • Kubernetes clusters
  • Cloud database services
  • Managed Kubernetes services

Conclusion and Q&A (15 minutes)

Summary of Key Points

  • Angular and Nest.js provide a consistent TypeScript experience
  • Prisma simplifies database interactions with type safety
  • PostgreSQL offers a robust and reliable data store
  • Swagger enhances API documentation and testing
  • Docker ensures consistency across environments

Resource List

  • Official documentation links
  • GitHub repositories with sample code
  • Recommended books and courses
  • Community resources and forums

Open Floor for Questions

Thank you for attending! I’m now open to questions about any aspect of the stack we’ve covered today.


Additional Workshop Materials (Optional Add-ons)

Hands-on Lab Instructions

Step-by-step guides for:

  • Setting up the development environment
  • Creating an Angular application
  • Building a Nest.js API
  • Configuring Prisma with PostgreSQL
  • Integrating Swagger documentation
  • Containerizing with Docker

Code Templates and Starter Projects

  • GitHub repository links to starter templates
  • Common patterns and solutions
  • Best practices implementation examples

Angular Series



Last modified March 27, 2025: Edit members.yaml (21070ed)