Appearance
FIXES.md โ
From Week 4 in-class: REST layers ยท original: si-679-f-26-week-04-nyt-jessicadonoho/FIXES.md ยท all files in this project
md
# Fixes: get-product-by-id, through the layers
The error showed up in `product-controllers.ts`, but the bugs ran all the way
down through the service and db layers. Each fix is marked in the code with a
`// FIXED:` comment. Search for `FIXED:` to find them all.
Routes were fixed in a second pass, after you wrote the `/:id` route (see the
Routes section below).
## Controller: `src/controllers/product-controllers.ts`
| What was wrong | Fix |
| --- | --- |
| `getProductbyId` called **itself** instead of the service, so it recursed forever. The TS error was `Expected 2 arguments, but got 1`, because it called itself with 1 arg when it takes `(req, res)`. | It now calls `productService.getProductById(...)`. |
| It never sent a response, so the request would hang. | Sends `res.json(product)`. |
| No handling for "no such product". | Sends `404 NOT FOUND` when the service returns `null`. |
| It wasn't in `productControllers`, so routes couldn't use it. | Added to the export. |
| Named `getProductbyId` (lowercase b). | Renamed to `getProductById` to match the service. |
## Service: `src/services/product-service.ts`
| What was wrong | Fix |
| --- | --- |
| `import { getThroughID } from '../db/db.js'` was a compile error, because `db.ts` only exports the `db` object. | Removed the import. The code already uses `db.getThroughID`. |
| `db.getThroughID(db.PRODUCTS, id)` had its **arguments swapped**. The function signature is `(id, collectionName)`. | Changed to `db.getThroughID(id, db.PRODUCTS)`. |
| Return type was `Promise<Document \| null>`, but the function returns a `Product`. | Changed to `Promise<Product \| null>`. |
| Unused type imports `Db`, `Document`, `InsertOneResult`. | Removed. |
## DB: `src/db/db.ts` (in `getThroughID`)
| What was wrong | Fix |
| --- | --- |
| `await init;` had no parentheses, so `init` was never called. | Changed to `await init();`. |
| `new ObjectId(id)` **throws** on an id that isn't 24 hex characters (e.g. `/products/abc`), which became a 500 error. | Returns `null` when `!ObjectId.isValid(id)`, so the controller sends a 404. |
## How the request flows now
```
controller.getProductById(req, res)
-> productService.getProductById(id) returns Product | null
-> db.getThroughID(id, db.PRODUCTS) returns Document | null
```
## Verified
- `npm run typecheck` passes. Before the fixes it had 2 errors.
- I ran the controller against an in-memory MongoDB:
- an existing id returns the product as JSON
- a valid id that doesn't exist returns `404`
- an invalid id like `abc` returns `404`, not a 500 crash
## Routes: `src/routes/product-routes.ts` (second pass)
You wrote:
```ts
productRouter.get('/:id', async (req: Request, res: Response) => {
res.json(productControllers.getProductById(req.params.id))
});
```
| What was wrong | Fix |
| --- | --- |
| `Request`/`Response` weren't imported from express, so TypeScript used the built-in fetch types, which have no `.params`. | The wrapper is gone, so these types aren't needed. |
| The controller was called with only an id, but it takes `(req, res)`. | Express calls it with `(req, res)`. |
| The controller already sends its own response (JSON or 404), and it returns a Promise. `res.json(...)` around it would try to send a second response containing a Promise. | Pass the controller straight to the route. |
Now:
```ts
productRouter.get('/:id', productControllers.getProductById);
```
Verified over HTTP (supertest + in-memory MongoDB):
```
GET /products/<real id> 200 {"id":..., "modelName":"X", "price":5}
GET /products/000000000000000000000000 404 {"error":"Not found: ..."}
GET /products/abc 404 {"error":"Not found: ..."}
```