I am making an anvil.http.request to a fastapi based back-end which fails on data validation.
FastAPI uses Pydantic to validate request data. If your endpoint is correct but the request is in error you’ll end up with an error 400 or 422. The HTTP_422 comes if the Pydantic validation discovers data that doesn’t agree with the validation model. One of the strong points of FastAPI are the extensive validation error messages, which are returned as json payload in the response.
Unfortunately when anvil.http.request gets an error status back it raises an exception. There is no reply from the request call, so no Pydantic error messages there. The anvil.http.HTTPError exception object as raised by anvil.http.request does contain the content
attribute which is supposed to contain the response payload according to Anvil Docs | Making HTTP requests.
But it comes up empty
Code Sample:
def login(username, password):
url = AUTH_API_URL + "browse/login"
data = f"username={username}&password={password}"
try:
response = request(
url = url,
method = "POST",
data = url_encode(data),
headers = {
"Content-Type" : "application/x-www-form-urlencoded",
"Accept" : "application/json",
}
)
except Exception as e:
response = f"Exception status={e.status}, content={e.content}, args={e.args}"
return response
Found the error:
Here is the actual $.ajax call:
return PyDefUtils.suspensionPromise(function(resolve, reject) {
$.ajax(params).done(function(r, ts, xhr) {
window.setLoading(false);
resolve(pyGetResponse(r, xhr, kwargs["json"]))
}).fail(function(xhr, textStatus, errorThrown) {
window.setLoading(false);
const status = xhr.status;
const content = pyGetResponse(xhr, kwargs["json"]); // WRONG!
let message = textStatus || errorThrown;
if (message === "error") {
message = null; // instead use a HttpError's nicer message.
}
reject(PyDefUtils.pyCall(pyMod["HttpError"], [Sk.ffi.toPy(status), content, Sk.ffi.toPy(message)]));
});
This is wrong because:
const content = pyGetResponse(xhr, kwargs["json"]);
will always set content to null because xhr is not an ArrayBuffer!
I think the line should be:
const content = pyGetResponse(xhr.response, xhr, kwargs["json"]);