{
  "id": 7584591,
  "title": "Building a Choose-Your-Own-Adventure API with NestJS — Part 2: Persistence",
  "url": "https://urgent.news/2026/09/15/building-a-choose-your-own-adventure-api-with-nestjs-part-2",
  "topic": "tech",
  "section": "Tech",
  "published": "2026-09-15T16:05:45.000Z",
  "source": {
    "name": "Dev.to",
    "slug": "dev-to",
    "url": "https://dev.to/_notbu7ch/building-a-choose-your-own-adventure-api-with-nestjs-part-2-persistence-4321"
  },
  "original_language": "en",
  "account": "In the second part of building the Choose-Your-Own-Adventure API with NestJS, the focus is on persistence to ensure a player's progress remains intact even if the server restarts. Part 1 covered controllers, providers, dependency injection, and validation with a single read-only endpoint. This section introduces making a player's progress survive a server restart by leveraging a database.\n\nThe issue with Part 1 was that every request started from scratch, with no concept of a player or where they were in the story. A database is necessary to remember the player's progress between requests. For this project, PostgreSQL and TypeORM are chosen as the database and ORM pairing, respectively. TypeORM is a common choice with NestJS, well-documented, and closely integrated with NestJS's dependency injection.\n\nTypeORM entities map to database tables. The `PlayerProgress` entity represents a player's progress in the story, with properties for the player's ID, current page ID, and XP. The relationship to the `User` entity is established using `@OneToOne` and `@JoinColumn`. The decision not to include a `level` column is based on the premise that level is calculated from XP and should never be stored as an independent value. This approach eliminates the possibility of inconsistencies between XP and level, ensuring the API cannot lie to the player about their progress.\n\nTo integrate TypeORM with the module, `TypeOrmModule.forFeature([PlayerProgress])` is used. This makes the `PlayerProgress` repository available for injection inside the module. The repository pattern is then utilized in the `ProgressService`, where raw SQL is avoided, and repository methods such as `findOne`, `save`, and `update` are employed. The `findForUser` method retrieves a player's progress, while the `advance` method updates the progress by advancing the player to the next page.",
  "summary": "Part 2 of a series building \"Grimoire API\" — a choose-your-own-adventure backend in NestJS, learned one milestone at a time. Part 1 covered controllers, providers, DI and validation with a single read-only endpoint. This time: making a player's progress survive a server restart. The problem with Part 1 By the end of Part 1, GET /pages/:id worked — but every request started from scratch. There was…",
  "key_points": [],
  "editors_take": null,
  "illustration": null,
  "coverage": {
    "outlets": 1,
    "also_reported_by": []
  },
  "ai_generated": true,
  "disclaimer": "Summaries, key points and the editor’s take are written by software from other outlets’ reporting and may contain errors — always check the linked original."
}