I've said it in other responses, but maybe I should have been specific that I was referring to HTTP RPC (explicitly not citing REST for a reason).
Perhaps a combination of both is best, but in my experience a nice clean break between these 2 layers at the protocol level helps clients simplify their handling of responses.
2xx: Go ahead and parse (another commenter pointed out Content-Type. That one always gets me)
4xx/5xx: Something bad happened and the request wasn't processed by the server, either because it blew up (5xx) or because you did something _very_ wrong (4xx)
The objective is clarity to the caller.
It's a little obtuse but I think it works well with that objective in mind.
I've said it in other responses, but maybe I should have been specific that I was referring to HTTP RPC (explicitly not citing REST for a reason).
Perhaps a combination of both is best, but in my experience a nice clean break between these 2 layers at the protocol level helps clients simplify their handling of responses.
2xx: Go ahead and parse (another commenter pointed out Content-Type. That one always gets me)
4xx/5xx: Something bad happened and the request wasn't processed by the server, either because it blew up (5xx) or because you did something _very_ wrong (4xx)
The objective is clarity to the caller.
It's a little obtuse but I think it works well with that objective in mind.