Welcome to the first lesson of the course. In this lesson, we’ll introduce user friendships to the reading tracker. Friendships enable users to connect and motivate each other by sharing progress. By the end, you’ll model friendships in the in-memory store, create a dedicated friends module, and implement a secure endpoint for sending friend requests that uses the authenticated user from the JWT (no trusting IDs in the body).
Our API already has users, books, and reading features wired through modules and services, plus a global JWT auth guard (requests are protected by default; public routes opt-out via @Public() where used). We’ll integrate friendships by:
- Extending the in-memory data model (
mock-db.ts) withfriendIdsand aFriendRequestcollection. - Adding a minimal accessor in
DatabaseServiceto read/write friend requests. - Creating a
FriendsModulethat composes existing services (notablyUsersService) and derives the sender from@CurrentUser().
No extra per-route guards are needed because the global guard is already active.
To support friendships, we need two additions:
- A
friendIds: number[]array on each user to store confirmed friends. - A
FriendRequestcollection to track pending/accepted/declined requests.
Also ensure seeded users include friendIds: [] by default, so new friendships can be recorded
Next, we will create a new module called FriendsModule. This module will handle all friendship-related logic, including sending and managing friend requests.
Here is how we set up the module, controller, and service:
Explanation:
- The
FriendsModuleimports theUsersModuleso it can access user data. - It provides a
FriendsServicefor business logic and aFriendsControllerfor handling HTTP requests.
We also need to add the FriendsModule to our main app module:
Why this design? The friends feature stays cohesive and reuses existing building blocks (UsersService, global auth). This keeps responsibilities clear and minimizes changes elsewhere.
Now, let’s build the endpoint that lets a user send a friend request to another user. This will be a POST request to /friends/request. We will make sure to validate the request so users cannot send requests to themselves, cannot send duplicate requests, and can only send requests to existing users.
We’ll take the sender from the JWT via @CurrentUser() and the recipient from the body. The service will prevent self-requests, check both users exist, and reject duplicate pending requests.
Here is the code for the controller, DTO, and service:
Let’s see how to test the new endpoint using cURL. Here are some example commands:
Admin login (default seed: admin/admin)
- Notice how we store ADMIN_TOKEN as a variable which can be reused later._
Lookup Alice id (seeded: username 'alice'):
- This should return ALICE_ID
Admin sends friend request to Alice:
- This should return the new friend request object with status "pending".
In this lesson, you learned how to model friendships in your app, set up a dedicated friends module, and build a secure endpoint for sending friend requests. You also saw how to test your endpoint and handle common errors. These are the building blocks for managing user connections in your reading tracker.
Next up (Unit 2): you’ll implement listing incoming requests and accepting/declining them with proper authorization so confirmed friendships can form.
