Ok so I've officially migrated the site off of GraphQL, to now just a plain boring REST API, and react-query. (backend in Node.js + express.js). Took way longer than I anticipated. Still some work left so some things on the site are currently broken.

I'd initially built this site a year ago using GraphQL and Apollo just because it was what I was most familiar with having used it at my last job.

Why did I migrate off GraphQL? A few reasons:

  • N+1 problem, or multiple SQL calls getting made instead of just one. Maybe there's a way to solve this with GraphQL, but honestly I'm not sure how to do this, and it's certainly more complicated than with a REST API
  • REST API is simpler, and more people are familiar with it. The API is public and I'm planning to open source it, so I want it to be accessible
  • Tooling and resources more limited than REST APIs. Standards less defined
  • Too much lock-in with apollo. I don't like to be dependent on anybody. Sure there are alternatives, but not really. Apollo also updates a lot, and old code gets deprecated.
  • My frustration with dealing with Apollo's cache on the frontend
  • Having to type the entire schema is actually time-consuming. I'm trying to optimize for developer speed here since this is a startup / side project and I'm the sole developer at the moment. Also I don't love decorators (funny since I'm using TypeORM and TypeGraphQL)
  • Wanting to personally get better with REST APIs. Since my previous employment had been with GraphQL, I wanted to improve my REST API skills, as well as try out react-query.

For the record, the thinking was that I'd eventually back in the GraphQL API. The way the code is setup, that should be fairly easy on the backend, could maybe even write some code to automate that. The frontend of course is a different beast.

Also I like and probably prefer the concept of GraphQL. It makes more sense for a client to specify just the data they want. The problem is just the tooling on the backend is pretty immature, and with GraphQL it's more difficult to optimize the SQL queries (or someone please tell me if there's an effective way to do this that I'm not aware of, ideally pointing me to an example GitHub repository)

Ok now that the site is migrated, was it the promise land I was hoping for?

No. I've realized that react-query's cache control is way worse than Apollo's, and right now it looks like I'll be moving off

The API does seem to be faster as it should, but not as much as I expected - though I admit I didn't test this very rigorously.

React-query caching kinda sucks

There doesn't seem to be a nice simple way to set and retrieve items in the cache: https://stackoverflow.com/questions/76563755/how-to-normalize-react-query-cache-to-only-use-a-single-key-when-there-are-multi

Apollo's caching is far superior because you can use cache.identify() to directly modify any entity in the cache (btw Apollo's documentation never mentioned that for whatever reason, wasting a lot of my time before I discovered that). React-query doesn't seem to have an equivalent. The only way to update the cache seems to be to manually do it for each API endpoint utilizing the data, using the exact same inputs that were used to call each API endpoint. What a pain in the ass.

Upvoting/downvoting doesn't live reflect anymore on this site, and I'm not sure how to even fix it with react-query without making the code incredibly convoluted.

Thus my plan is to get rid of react-query and handle the caching myself - or maybe make something similar to react-query, but with the control over the cache that I desire.

Anyways don't get me wrong react-query is great for simple sites, but for anything more complex I'm going to pass going forward. Or maybe I'm missing some information, but I don't see any explanation in the docs or online, and never got any real responses on StackOverflow, GitHub discussions, or tweeting at the tanner guy on Twitter.

All that being said, I'm happy the codebase migration is finished, and CI/CD is setup (I do that on all my projects now, but back when I made this I was still fairly new to Google Cloud Run and manually deploying like a caveman) so I can start developing on this site again! Maybe no one's noticed, but the last few weeks I haven't actually updated anything on this site because none of that stuff was setup, and I didn't want to touch the codebase as it was anyways.

But now I'm ready to pump out a ton of features on Zsync. Just need to undo this react-query monstrosity.

jeremybernier🔗 | 11 months ago

Cleaned up code, fixed bugs, wrote a lot of SQL. I think one more round of cleanup, modernize the UI, and then prob ready for open source.

jeremybernier🔗 | 11 months ago

Yesterday fixed some of the caching issues with react-query - basically by just calling invalidateQueries(['posts']) on user actions. I didn't realize the react-query keys were hierarchical in the sense that calling invalidateQueries on ['posts'] automatically resets all cache keys of the form ['posts', ...], which is cool. I don't like that this causes a refetch on something as trivial as an upvote which is totally unnecessary (actually I'm seeing two refetches, but I'll investigate before I point fingers), but I'm glad it at least works.

Beyond that did some less exciting stuff - added recaptcha on signups, forgot/change password functionality, toast messages / alerts, cleaned up the signup/login forms, and some code migration stuff.

Main issue now is the bug with upvote counts - again, sick of TypeORM's querybuilder, so will migrate that to knex as I debug that.

Earlier this week was inspired to redesign the UX, but now not as inspired - though maybe that's because it's currently Saturday and all this other boring stuff kinda sapped my energy. But I'll still go through with it. I think the UX is too boring now and hard to get away with unless you're HN