DEV Community

Cover image for REST is often THE WRONG CHOICE, it is a lazy default for too many, and I am sick of it.
Davor Hrg
Davor Hrg

Posted on • Edited on

REST is often THE WRONG CHOICE, it is a lazy default for too many, and I am sick of it.

TL;DR: Rant: When the frontend simply calls backend methods(it's RPC), REST is the wrong choice there. It’s your decision if you still want to use it, sure it gets the job done, but it’s not really ok when forced on those who don’t need or want it. You should at least know JSON-RPC exists (and has actual good spec, unlike REST).

Thumbnail from The Family Guy :

  • dick, you ever wonder what's outside those walls ?
  • now, that's dangerous thinking Paul, you better stick to your work

Why I rant about it

This wouldn’t be as bad if it weren’t affecting the freedom to choose the best fit for a specific project in practice. The problem with trendy tech is that it trickles down, so it’s shoved down our throats regardless of whether it fits or not. All kinds of "experts" who influence the choice of technology in specifications, auditing, and management go along with those trends, because deviating would make them look less "expertly."... Also AI loves statistically average slop.

Scope

This text applies to use cases where two sets of code communicate through method calls. A persistent backend that exposes API methods to perform some work, and a frontend that uses a wrapper—such as Axios to turn the API into convenient methods for components to call. Using REST as the communication layer in this scenario is downright disgusting. REST may be better fit for PHP depending on how URLs are routed, or whatever else.

I prefer making single-page applications and do not care even slightly for SSE. I’ve done my share of PHP programming, experienced some horrible things in Java EE, ASP and .NET, and I’m never going back to that.

Why REST is wrong here

On both sides of the communication, you have code that is neatly defined as a method or an interface. It has a method name, some parameters, a return value, and it can throw an exception (or, if you prefer, return a union type with an error).

Instead of providing a clear and simple mapping, you are using REST, and it introduces an unnecessary layer of noise:

  • Different HTTP methods
  • Different content types in responses, especially in case of errors
  • Sometimes parameters are passed in the URL
  • Sometimes they are passed in the request body

This gives me flashbacks to SOAP, where values could be passed either in tags or in attributes, creating a mess when you try to map everything.

Look at this simple example in Java

@GetMapping("/users/{userId}/orders")
public List<Order> getUserOrders(
    @PathVariable Long userId,       // From path: /users/123/orders
    @RequestParam String status  // ?status=PENDING
) {
    return orderRepository.findByUserIdAndStatus(userId, status);
}
Enter fullscreen mode Exit fullscreen mode

It may not look too bad because people are used to it. But there is so much pointless noise here.

@Rpc()
public List<Order> getUserOrders(Long userId, String status) {
    return orderRepository.findByUserIdAndStatus(userId, status);
}
Enter fullscreen mode Exit fullscreen mode

R: But I like REST

Why are you reading this? Just move along.

R: But REST is better because of X...

Why are you still here? GTFO.

There are better ways

Anything consistent is better. I’m sure there are great options like gRPC, but it’s easy to build your own. And if you’re used to sending JSON around, it will probably end up looking like JSON-RPC .

R: But I like shiny generated Swagger/OpenApi

You can still generate that easily without the REST mess. I have written code to generate API swagger few times, and it is not rocket science. You should be ashamed If you can't use some Java reflection to do the same.

R: Are you sending HTTP 200 for errors too ?

By default yes, because I do not care, HTTP is just one of possible transport layers. Errors are communicated inside the JSONRPC protocol. Why do you care? If really needed it is rather simple to also send different HTTP codes.

Adding security to routes

I would not do it by default. It is trivial to do, just enforce method names are part of the URL (even if it means they are redundantly in the RPC payload).

On the other hand it is actually not a bad idea to add method name to url in a way it can be ignored by the backend, as it helps you see method names when inspecting in browser (instead a slew of requests to /rpc).

Compact API on JS side

Mapping API methods can be done in type safe way without bloating the bundle with a simple proxy and types declaration.

const handler = () =>{
  const makeRpcHandler = method =>{
    return function(params){
      return new Promise((resolve,reject)=>{
        // call api method here and resolve / reject
      })
    }
  }
  return {
    get(target, prop, receiver) {
      if(prop in target)  return target[prop]
      return target[prop] = makeRpcHandler(prop)
    },
}}

/** @typedef { import('./MyApiInterface.js').MyApi } MyApi */
/** @type {MyApi} */ 
export const MyApi = new Proxy(target, handler())
Enter fullscreen mode Exit fullscreen mode

And the MyApiInterface.ts

export interface SearchParam {
  filter?: Array<Object>
  order?: Array<string>
}
export interface Book {
  id: number
  title: string
}
export interface SearchResult<T> {
  data: Array<T>
  limit: number
  offset: number
  rowcount: number
}

export interface MyApi{
  bookSearch(search: SearchParam): Promise<SearchResult<Book>>
}
Enter fullscreen mode Exit fullscreen mode

Later in your code, just import MyApi and use with all of the types visible in your editor.

import {MyApi} from './MyApi.js'

function someThing(){
  // IDE will know result is SearchResult<Book>
  const result = await MyApi.bookSearch({filter:[...]})
  console.log(result.data)
}
Enter fullscreen mode Exit fullscreen mode

Notice that you have a single proxy that routes methods, and type safety is achieved through type definitions that will not be part of the bundle. Therefore, whether you have one method or one hundred, the bundled code for the bridge remains the same size.

More details

How about NO. The point here is that you think about it a bit and decide if you still think REST is so great, and then accept the consequences of your decision. Code examples here are not a full solution, just to explain a bit deeper, what things could be.

If you think SOAP is terrible but REST is great.

I have news for you. SOAP is objectively much better technology than REST, but that also makes it complicated, and then sprinkle complication by big companies(MS, IBM, Oracle) and SOAP becomes even bigger pain in the ass to use as a developer.

Enshittification

https://en.wikipedia.org/wiki/Enshittification is really nice term that I would like to draw some parallels here. REST by itself is not the sole issue here, it is part of a pattern.

I can not speak about other languages, but in Java this ties neatly into Spring. These systems are intentionally made complicated so a ecosystem of consultants earn money. You are lured into using it by "Look how easy it is to make XY" but then for every little step you have to learn (or pay consultants) how to do it with Spring. Soon you are not coding, but configuring Spring. After you are hooked with "simple to start a project" you pay the price later (search: Spring cloud Gateway).

AI can help

I strongly disagree here. AI will just make it worse. It will help produce more of the same bloated code that is in-line with short term corporate thinking, and will create a long term nightmare.

Top comments (10)

Collapse
 
eliasa profile image
Elias A

Thank you for the article !

TIL about JSON-RPC. For some reason, I never came across this in any codebase I worked on. In hindsight, there were a couple of situations in which it could have been nice to use... I'll definitely keep it in mind.

Your approach is very "purist". Perhaps a bit too much. If REST is the current norm and every developer knows it relatively well, a pragmatic choice would be to avoid introducing new technologies into codebases and stick with something that works and is easily adopted, even if it's not the optimal solution. It's not like we're building software for the sake of building it perfectly. We're paid to build efficiently.

Collapse
 
hrgdavor profile image
Davor Hrg • Edited

Thanks, this is just my rant, REST feels off so I am personally looking into why I don't like it. I am a proponent of ppl using what they prefer.

I got angry when some fancy auditor came along and made us switch from JSON-RPC to REST, where I had to guess which HTTP methods to use depending on what api does (PUT,GET,DELETE,PATCH,...).

When both ends are just functions that have parameters and some may throw Exceptions, why add that extra burden ? And there is no clear RFC that says clearly. And then as a bonus, for exceptions you also need extra burden of defining different HTTP codes.

We're paid to build efficiently.

That is arguable :D and efficiency means different things to different people. I would argue that adding bloat of REST to situations where communication is clearly RPC is opposite of efficient ;) .

Anyway, If REST is better fit for you, that is absolutely fine. I am glad I could influence you to consider a RPC in the future.

Collapse
 
eliasa profile image
Elias A

Alas, this is probably one of the greatest curses in the development field.

I must agree with the fact that forcing REST in such a situation is just short-sightedness. Especially given the fact that it was literally adding more work to the pile by rewriting something that's already been implemented to replace it by a more inefficient option.

By the way, you talk about an auditor : was it simply their opinion or instead part of some kind of compliance ruleset ? I wouldn't be shocked to read something like "all public APIs in this branch of the field must be REST-compatible".

Thread Thread
 
hrgdavor profile image
Davor Hrg

no, it was part of auditor's push to use spring the "right way"

Thread Thread
 
eliasa profile image
Elias A

Facepalm intensifies

Collapse
 
muhfred profile image
Mohamed Naga

If you want to check other opinions: stackoverflow.com/a/15116562

here is what is written for your convenience:

The fundamental problem with RPC is coupling. RPC clients become tightly coupled to service implementation in several ways and it becomes very hard to change service implementation without breaking clients:

  • Clients are required to know procedure names;
  • Procedure parameters order, types and count matters. It's not that easy to change procedure signatures(number of arguments, order of arguments, argument types etc...) on server side without breaking client implementations;
  • RPC style doesn't expose anything but procedure endpoints + procedure arguments. It's impossible for client to determine what can be done next.

On the other hand in REST style it's very easy to guide clients by including control information in representations(HTTP headers + representation). For example:

  • It's possible (and actually mandatory) to embed links annotated with link relation types which convey meanings of these URIs; Client implementations do not need to depend on particular procedure names and arguments. Instead, clients depend on message formats. This creates possibility to use already implemented libraries for particular media formats (e.g. Atom, HTML, Collection+JSON, HAL etc...)
  • It's possible to easily change URIs without breaking clients as far as they only depend on registered (or domain specific) link relations;
  • It's possible to embed form-like structures in representations, giving clients the possibility to expose these descriptions as UI capabilities if the end user is human;
  • Support for caching is additional advantage;
  • Standardised status codes;

There are many more differences and advantages on the REST side.

Collapse
 
hrgdavor profile image
Davor Hrg

I ma not sure that you read the "Scope" section. So many codebases are backend API and something like react with axios layer. The codebase actually has identical method names and parameters ... and to add to htat, it is ususal to keep it consistent for maintenance ... I really see no benefits in your REST pros for that type of appliaction.

  • why would you ever need caching there
  • it is also trivial to chenge url for RPS as it is singe url

I am not gonna bother to elaborate further, you completely missed the use case point.

Collapse
 
halink0803 profile image
Hoàng Hà

The comment section of the answer you posted having enough counter arguments for the answer itself. This answer having many upvote does not make it the correct one.

Collapse
 
hrgdavor profile image
Davor Hrg

True. Decide for your self :)

Collapse
 
hrgdavor profile image
Davor Hrg

If you thought I was mean, check this linkedin.com/posts/vvoss_thereplac...