Hacker News new | past | comments | ask | show | jobs | submit login

Why the assumption that an API endpoint should be a 1:1 mapping to a database table? There is no reason we need to force that constraint. It's perfectly legitimate to consider your resource to encompass the business logic for that use case. For example, updating a user profile can involve a single API call that updates multiple data objects - Profile, Address, Email, Phone. The UI should be concerned with "Update Profile" and let the API controller orchestrate all the underlying data relationships and updates.





You seem to be in agreement with the parent, who argues 1 model (aka database row) = 1 rest entity (aka /widgets/123) is a bad paradigm.

Different widget related front-end views will need different fields and relations (like widget prices, widget categories, user widget history and so on).

There are lots of different solutions:

- Over fetching. /widgets/123 returns not only all the fields for a widget, but more or less every possible relation. So a single API call can support any view, but with the downside that the payload contains far more data than is used by any given view. This not only increases bandwidth but usually also load on the database.

- Lots of API calls. API endpoints are tightly scoped and the front-end picks whichever endpoints are needed for a given view. One view calls /widgets/123 , /widgets/123/prices and /widgets/123/full-description. Another calls /widgets/123 and /widgets/123/categories. And so on. Every view only gets the data it needs, so no over fetching, but now we're making far more HTTP requests and more database queries.

- Tack a little "query language" onto your RESTful endpoints. Now endpoints can do something like: /widgets/123?include=categories,prices,full-description . Everyone gets what they want, but a lot of complexity is added to support this on the backend. Trying to automate this on the backend by having code that parses the parameters and automatically generates queries with the needed fields and joins is a minefield of security and performance issues.

- Ditch REST and go with something like GraphQL. This more or less has the same tradeoffs as the option above on the backend, with some additional tradeoffs from switching out the REST paradigm for the GraphQL one.

- Ditch REST and go RPC. Now, endpoints don't correspond to "Resources" (the R in rest), they are just functions that take arguments. So you do stuff like `/get-widget-with-categories-and-prices?id=123`, `/get-widget?id=123&include=categories,prices`, `/fetch?model=widget&id=123&include=categories,prices` or whatever. Ultimate flexibility, but you lose the well understood conventions and organization of a RESTful API.

After many years of doing this lots of time, I pretty much dislike all the options.


Lots of API calls scales pretty well, as long as those APIs aren't all hitting the same database. You can do them in parallel. If you really need to you can build a view specific service on the backend to do them in parallel but with shorter round-trips and perhaps shared caches, and then deliver a more curated response to the frontend.

If you just have one single monolithic database, anything clever you do on the other levels just lets you survive until the single monolithic database becomes the bottle-neck, where unexpected load in one endpoint breaks several others.


"you can do them in parallel" - not in Rails.

Webapps are going back to multiple requests because of http2 / quic multiplexing.

This solves the problem of slow transport between your frontend and your backend, but it will still incur a lot of unnecessary load on the database as well as compute on your backend (which isn't normally a problem unless you're using something really slow like Rails).

So what do you do instead?

I do one or some combination of the options above. I've also tried some more exotic variations of things on the list like Hasura or following jsonapi.org style specs. I haven't found "the one true way" to structure APIs.

When a project is new and small, whatever approach I take feels amazing and destined to work well forever. On big legacy projects or whenever a new project gets big and popular, whatever approach I took starts to feel like a horrible mess.


No, it's an API Entity can be composed of sub-entities which may or may not exposed directly via API.

That's what https://guides.rubyonrails.org/association_basics.html is for.

However, Rails scaffolding is heavily geared towards that 1:1 mapping - you can make all CRUD endpoints, model and migration with a single command.


If you lean into more 1:1 mappings (not that a model can't hold FKs to submodels), then everything gets stupid easy. Not that what you're saying is hard... just if you lean into 1:1 it's _very easy_. At least for Django that's the vibe.

Rails began that trend by auto-generating "REST" routes for 1:1 table mapping to API resource. By making that so easy, they tricked people into idealizing it

Rails' initial rise in popularity coincided with the rise of REST so these patterns spread widely and outlasted Rails' mindshare




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: