HACKER Q&A
📣 palberg7

Other than REST and GraphQL, what do you guys use?


I'm building a web app and REST and GraphQL seem to be overkill for what I want to achieve. All I want is to get data for my React front-end and do couple of HTTP POSTs.

I'm thinking of simply creating express routes (I'm using Node.js) and using JSON but it seems cumbersome. Or is that a common practice?

I'm wondering what the alternatives to REST and GraphQL are.

Curious to know what y'all use for simple web apps.


  👤 ptttr Accepted Answer ✓
If you're looking for potential alternatives to REST and GraphQL, I suggest checking out how Fulcro [1] works together with Pathom [2] using EQL [3].

It's a data-driven full-stack application programming system centered around graph-based UI and data management implemented in Clojure [4].

While React lets you be declarative about your UI, Fulcro lets you be declarative about your entire system - both backend and frontend.

Check out this discussion too: https://news.ycombinator.com/item?id=21743720

[1] https://fulcro.fulcrologic.com/ [2] https://github.com/wilkerlucio/pathom [3] https://github.com/edn-query-language/eql [4] https://clojure.org/


👤 ser0
If you all need to do is basic persistence and don't want to bother with setting up your own backend, look into services such as https://restdb.io/ or https://fauna.com/ - be careful about security if you are embedding this in your front-end app.

Otherwise, writing your own backend using RPC-named express routes is more than sufficient. The reason why REST became common is that RPC routes can become messy.

Another poster gave the example of "SaveWidget" as an RPC endpoint. This can cause problems for some teams that have no conventions and they end up with "SaveFoo" and "BarSave" endpoints. REST solves this somewhat by relying on HTTP verbs so both endpoints are normalised to "POST /foo" and "POST /bar".

Finally, if your web app is truely simple with only a couple of backend endpoints needed, then whatever you choose is generally fine. Structural and architectural patterns exist to provide a framework around managing complexity.

If your app is not complex, most people - and it's important to consider this includes your future self that has forgotten your implementation details - can grok the codebase without too much trouble. If anything, as your question suggest, over-engineering a simple app can lead to greater confusion.


👤 davismwfl
If you are building a simple web app, do you really need to separate it into a different layer/call? Having a monolith isn't evil for simple apps, just have a library or function you call to get the data and populate it server side. My general rule is unless there are many separate types of clients (e.g. mobile app, web app, backend services etc) needing the same thing, then it can just be part of the primary application and returned server side. Lots of separate client based calls are not necessary for a basic app (but some frameworks kinda push you towards this). In fact, much of the time people would be better putting a caching layer in first and returning the data with the server render, at least initially until they have users and reasons to change.

Outside of that, yes, you can also just make it a route in the web app and call it if you really want, nothing says it has to conform to a specific standard. A simple HTTP get or post is good enough many times. GraphQL is also overkill if you simply need to run a basic query.


👤 iofiiiiiiiii
My preferred API design is RPC - expose various method calls to other systems. In practice, this means gRPC whenever possible, basic HTTP RPC when not, and finally SOAP is also fine if you are on a platform that has a sane implementation.

I could try think of why but in practice, it just seems to work out the best. Are there reasons? Sure. But coming up with a detailed rationale would take some days of thinking. It just works very well.

This means on my service side I expose SaveWidget(id, body) ReadWidget(id) PatchWidget(id, changes) QueryForWidgetsByFoo(foo) QueryForWidgetsByFooBarAndSomeOtherSTuff(foo, bar, otherstuff) and on the client side I just call them as if they were local (but rather slow performing) functions.

Lots of little ifs and buts but this has proven the superior approach in all scenarios where I control both client and server. I might go for REST for wide-audience APIs just for the recognizability.


👤 status_quo69
Rest is (simplified) just a way of expressing your routes as resources. If you want to post and get some things that's perfectly fine but you'll probably wind up accidentally fitting into a different paradigm (rpc for example if you start naming your routes getFooBar and newFooBar).

You can also post form data instead of json if you think json is overkill but getting data from the server is probably limited to something like json unless you want to decide on a custom format or your data is truly so simple that you can just return a single text blob.


👤 silviogutierrez
Possibly inflammatory, but not only are REST or GraphQL overkill. They're outright wrong for many domains. If you are not exposing your service to others, this is especially true.

Look at any mature framework (Django, Laravel) and either use that or emulate it.

Why?

REST and GraphQL deal with discrete resources. yes, GraphQL can deal with many, but it's still an abstraction to group calls.

In my experience, I'm dealing with user input that does not map cleanly to resources. Ultimately, if you persist things, of course resources are affected. But the input is its own world.

The sign REST/GraphQL abstractions are breaking is when you create ad-hoc endpoints/entry-points to serve these resources.

Classic example would be a call to "copy 5 widgets from Y category to Z category".

In resource-oriented world, you could do:

1. PUT/POST for each widget, changing the category label sending the full resource.

2. Or you could write an ad-hoc endpoint that accepts more than 1 widget, repeat as above.

3. You still need to figure out the "proper" way to handle the category. If Z doesn't exist, do you make them PUT/POST to /categories/ to create one first? Or do you auto create it for them? How do you auto create it? Does the category field accept the primary key of a category and arbitrary text in case you're creating a new one? That's odd.

4. So on and so forth.

How would I do it in Django world, at least?

1. Create a view, it will have 2 forms on the view and process them together.

2. Form 1 is a formset with a row per widget you wan to copy. Any number of rows can be sent. Django will validate they are valid widgets.

3. Form 2 is a form with a "from_category" and a "to_category" as well as a "new_category_name".

4. Form 2 has a validation rule, if to_category is null, new_category_name must have a label for a new category.

5. In the view, process Form 1 and 2 together, if valid, handle a create everything.

The difference is subtle. But you're decoupling input from resources. I yearn for an API-centric way to do this.


👤 lgl
> I'm thinking of simply creating express routes (I'm using Node.js) and using JSON but it seems cumbersome. Or is that a common practice?

Yes, it's common practice. As for being cumbersome, as cumbersome as creating conforming ReST or GraphQL endpoints? Keep it simple I'd say.


👤 alexfromapex
Flask is a pretty simple REST API to setup that is relatively performant

👤 lukasfischer
JSONAPI, we use Drupal a lot, and Drupal 8 comes with JSONAPI out of the box.