Fork me on GitHub
#ring
<
2023-09-26
>
Saket19:09:56

When I return a (bad-request! {:message "Something is wrong with the request"}) I get 500 Internal error on the client. How to get 400 Bad request instead ?

seancorfield20:09:25

What is bad-request! -- you'll need to show a bit more code. In addition, if you're getting a 500 Internal Server Error, you should see exceptions somewhere (depending on how you're starting the app).

DrLjótsson20:09:21

I believe bad-request! throws so you need to catch that exception . Try using bad-request instead (without !)

Saket05:09:26

Hey, sorry for the late response. @U04V70XH6, bad-request! is the standard ring.util.response/bad-request! It is supposed to throw an error, which it does. But that exception gets translated into 500 Internal for the client. It should ideally be converted to 400 Bad request error, like it does in other language's frameworks.

Saket05:09:34

@UGDTSFM4M, bad-request just returns 200 OK with error info in the response body.

seancorfield05:09:59

It shouldn't be 400 Bad Request. That's not the semantically correct HTTP status code.

seancorfield05:09:15

4xx are client errors -- indicating that the client needs to do something different.

seancorfield05:09:46

I don't know of any language framework that returns a 4xx error for an unhandled error on the server -- that's just semantically wrong.

Saket05:09:23

According to MDN: The server has encountered a situation it does not know how to handle. But, I would say that the server handled the situation and returned the bad-request so that the client gets 400. Am I missing a middleware here? I used django and spring boot in the past and noticed the behaviour that I was expecting. Let me double check if I missed a middleware somewhere that translates responses and throws corresponding http error

seancorfield05:09:29

ring.util.response/bad-request is for returning a 400:

> clj -Sdeps '{:deps {ring/ring {:mvn/version "RELEASE"}}}'
Clojure 1.12.0-alpha4
user=> (require '[ring.util.response :as resp])
nil
user=> (resp/bad-request {:error "failed!"})
{:status 400, :headers {}, :body {:error "failed!"}}
user=>

seancorfield05:09:46

If you are using bad-request and don't get a 400 status like I showed, then maybe you have middleware that is messing with the response?

Saket05:09:34

I do get a response just like the one you shared. But the client gets the http response 200 and this map in the response body. Now, if I have to handle this on client I have to write extra code that checks for this response for any possible error (as the server said: well, it worked and here is an error in the response body) If it threw the exception I could wrap the client request in a try/catch block and be done with it.

seancorfield05:09:00

bad-request returns a 400 status, not a 200 status.

seancorfield05:09:11

You must have something else messing with the response.

seancorfield05:09:06

(I know this works -- we return 4xx status a lot in our app at work)

Saket05:09:52

I believe we are talking about two different places when we talk about status. You're talking about the return value of (bad-request ...) I am talking about when it translates finally for a client that sent the http request. It translates to HTTP 200 and the response body has:

{:status 400
 ...}

seancorfield05:09:33

Then you have SOMETHING ELSE MESSING WITH THE RESPONSE. I'm telling you that does not happen by default.

Saket05:09:33

Oh let me check again, maybe I missed something here. I'll update here if I find anything.

seancorfield05:09:55

If you shared some code, that might help.

seancorfield05:09:29

But, right now, I'm pretty sure you're just doing something "wrong" with the Ring response somewhere in your stack.

seancorfield05:09:17

Perhaps you're doing the equivalent of this?

user=> (resp/response (resp/bad-request {:error "failed!"}))
{:status 200, :headers {}, :body {:status 400, :headers {}, :body {:error "failed!"}}}

1
Saket05:09:40

Got it. I'll share a snippet when I get back to the project.

seancorfield05:09:36

Somewhere in your code, you probably need logic like this:

user=> (let [r (resp/bad-request {:error "failed!"})]
         (if (resp/response? r)
           r
           (resp/response r)))
{:status 400, :headers {}, :body {:error "failed!"}}

seancorfield05:09:14

i.e., in your middleware, you might need to see if you already have a Ring response before just wrapping the result in a response.

seancorfield05:09:42

And a regular (non-error) flow would be:

user=> (let [r {:success true :message "Yay!"}]
         (if (resp/response? r)
           r
           (resp/response r)))
{:status 200, :headers {}, :body {:success true, :message "Yay!"}}

seancorfield05:09:12

(your avatar might trigger coulrophobia 🙂 🙂 🙂 )

Saket06:09:38

Sean, you are right. There's no middleware issue, just my dumb ass wrapped the response in ok at the top level. Sorry for wasting your time. These ok, bad-request! are a part of metosin/ring-http-response lib.

Saket06:09:46

Updated the profile picture.