I'd estimate 2-3 hours of total work writing the server code and tests.
I wouldn't have taken as long if I had already been experienced with TypeScript and Vitest, but I had to go through a refresher and learn from scratch since lecture wasn't super helpful. Once I got the hang of writing endpoints and tests from Activity 1a, everything fell into place. I spent more time learning the code than actually writing it and I was able to copy and paste a lot of the code I wrote.
Probably learning Zod schemas and understanding how they work. I was completely new to it, so I had to learn it from scratch and edit the widgets schema to fit books and authors. I did some outside research and it helped a lot with understanding why they're important and how to validate input using them. If I had a page on the course website explaining them in full, that would've helped a lot and improved my experience.
TypeScript doesn't help with string logic or routing errors. For example, I mistyped one of the endpoints as app.get("/books:id") instead of ("/books/:id"), which TypeScript saw as a perfectly valid string. It doesn't help with database schemas or SQL queries either, so when I accidentally tried to filter books by name instead of title, TypeScript didn't help and just viewed the query as text. You can also lie to TypeScript through type casting (such as when you write db.get<BookDB>) to make it think the result is a full BookDB, but it won't be able to tell types are accurate since it can't check the database.
TypeScript does help with variable scope issues. When I tried to write the GET /books, I used name in the parameter array [name], which wasn't defined, which TypeScript immediately flagged in the IDE as I wrote it. It also helps with consistency in response shapes, so when I define Book or Author using z.infer<...>, TypeScript makes sure that it has the exact same properties everywhere (title, author_id, etc.), so it can block you from accessing non-existent properties. Finally, TypeScript works great with Zod, so it can ensure that data from parseResult matches the schema so you don't have to guess anything regarding properties.
I had trouble typing the errors in try/catch blocks, since err is unknown by default. I couldn't access err.message to check for foreign key constraints, so I had to explicitly cast it as error = err as any to read its properties. There's not much I find confusing about TypeScript quite yet just because we're still scratching the surface, but I guess I'd say Generics.
Writing tests is kinda boring, but the process of running tests after you're finished and seeing them pass is really satisfying. I'm coming off a term where I took SE 320 (Software Verification and Validation, which involves writing lots of tests), so I'm not super keen on them right now. Tests made the development process a bit drawn out, but they bolstered my confidence a lot and made me understand my code better, so they did help.
Yeah, they definitely helped. My endpoint testing helped me find the routing bug I mentioned earlier where I mistyped "/books/:id" as "/books:id", so I went back and fixed it when I saw my test fail. My tests also verified my error handling, such as throwing a foreign key constraint error when an author who still has books tries to be deleted. It also made sure my status codes were correct.
I wrote the server code first and then the tests after, but since tests help catch bugs, I'd opt for a TDD approach next time where I write tests before endpoints. It would've helped me catch bugs better and earlier to avoid wasting time. I learned that automated tests are the only way to verify database constraints, but they can't check SQL logic. I also realized that test isolation is important, so I didn't make tests dependent on one another and it made writing the test suite way smoother.
I used Gemini to help teach me Zod schemas and come up with test cases, but that's about it. It's helpful for boilerplate code to save time and reinforce concepts I've learned. Gemini was also able to help me think of more endpoints I needed and ensure my API complies with RESTful principles.
LLMs definitely made my coding a lot smoother and more fun. Since it helps clear up confusing topics for me such as type casting and Zod schemas, the assignment went by a lot smoother with less confusion. It saved me a lot of time with writing repetitive boilerplate code like I mentioned earlier and it affected what I learned by helping me understand new concepts and ideas.