I am just learning FastAPI (and loving it), so it is quite likely I am doing something wrong. But here is my problem:
In the code snippet below, I am creating a new user, if there is no user already.
The code works fine, but it is the error handling that I am having trouble with. The errors are properly being pushed forward to FastAPI's internal docs or to an API client like Postman, but not back to the actual client that I am using or the command line.
#app.post("/users/", response_model=schemas.User)
def create_user(user: schemas.UserCreate, db: Session = Depends(get_db)):
db_user = crud.get_user_by_username(db, username=user.username)
if db_user:
raise HTTPException(
status_code=400, detail=f"Username '{user.username}' already registered"
)
return crud.create_user(db=db, user=user)
If I use the auto-generated FastAPI docs (or Postman) and monitor the response in that way, I get the error I am expecting:
But when I look at what I am receiving at the client end (Vue) or what the uvicorn server is logging, it does not contain that information:
As you can see, it just says Bad Request instead of responding with the JSON dict of {"detail": "Username 'miketest' already registered"}
What am I doing wrong? What can I do to make sure that the full HTTPException information is being returned? I am pretty sure the problem is on the FastAPI end, because the client is receiving exactly what the server is outputting as well.
I figured out the problem, and it was not a FastAPI issue, per se, but it was on how it passes information back to the front end.
I thought I should keep this question in case someone has the same issue.
Solution:
try {
await api().post('register',JSON.stringify(data);
} catch (err) {
error = err.response.data.detail;
}
That is to say, the error sent from FastAPI is an object that has a response, and in it a data, and in that a detail.
The response from Postman or anything similar just gives an object with detail. I did not see that there was a middle data layer, and I was having trouble seeing the entire object from within Vue.
This screenshot belongs to console log and it will not contain the API response, the JSON response.
You can see the actual response if you send the request the API using some client, like POSTMAN.
Related
"The request's session was deleted before the request completed. The user may have logged out in a concurrent request" I am facing this error when trying to use 2 request.session().
In my code my using two request.session() to store variables.After one request successfully completed,its going to another request and throwing this error.
request.session['dataset1'] = dataset1.to_json()
request.session['total_cols'] = total_cols // getting error here
Please help to resolve the same.
Since my dataset has 8000 rows, It was not a good idea to store in session variables. I have written some rest calls and that solved my problem.
I've been working with the spotipy python API for a few days, trying to get it to work. Each time I try for a login request, it tracebacks with bad oauth request.
I've used this code:
id='my_client_id'
secret='my_client_secret'
url='https://mywebsite.mydomain/callback'
username='myusername'
scope='a list of scopes'
token=util.prompt(username, scope, client_id=id, client_secret=secret, url)
I then paste in a url that looks like:
https://mywebsite.mydomain/callback?code=a_long_code
But each time it gives me a bad request from oauth. Am I missing something? It seems to go through the login process fine, it's just it tracebacks at the end.
Just in case people have this issue in the future, here is what I did:
In oauth2.py, find where it raises the error, and before that put something like: self.problem=response.
Run the steps that util.prompt does by hand, I.E, do the oauth_url requests yourself, rather than through util.prompt.
See what sp_oauth.problem.text says.
In my case, it was an incorrect app secret.
MORTIFIED!
i hope this isn't a duplicate. I searched through other entries and none seemed to address the problem i'm seeing.
We have an AWS Lambda function written in Python 3.6. The Lambda function is executed through API Gateway using the Lambda proxy integration. The function is initiated without problem and the processing executes without a problem. However, no matter what we seem to do in trying to send a response, the client receives "{"message": "Internal server error"}" I don't know that it's important, but the client for our test is Postman.
We've stripped out all of our business logic and isolated the code that does the return and we still get have the same problem.
the code is:
import json
def lambdaTest(event, context)
response = {}
dummybody = {'body':'something'}
response['statusCode'] = 200
response['body'] = dummybody
response["headers"] = {"Content-Type": "application/json"},
return json.dumps(response)
i'm sure I'm doing something wrong that's simple as I don't seem many posts about this problem. I would very much appreciate any help. Thanks.
Folks,
I figured it out... one silly problem and one thing I didn't realize about the format of the response. The silly problem was that I turned the header element into an array because I had a trailing comma (I looked at the 100 times and didn't see it). But even when I commented out setting up the header, it still had the same problem.
The aspect of the response that i didn't realize is that the body is expected to be a string. So, I had to encapsulate the JSON document I wanted to return in a string. That fixed the problem.
i hope this can help someone else
The default message for Flask 400 exception (abort()) is:
{
"message": "The browser (or proxy) sent a request that this server could not understand."
}
For 404:
{
"message": "The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. You have requested this URI [/obj/] but did you mean /obj/ or /obj/<int:id>/ or /obj/<int:id>/kill/ ?"
}
I have trouble comprehending these messages when I'm getting them as replies in my API (especially the first one, I thought there's something wrong with encryption or headers) and I thing it's kinda tiresome to try to override text manually for every abort() exception. So I change the mapping:
from flask import abort
from werkzeug.exceptions import HTTPException
class BadRequest(HTTPException):
code = 400
description = 'Bad request.'
class NotFound(HTTPException):
code = 404
description = 'Resource not found.'
abort.mapping.update({
400: BadRequest,
404: NotFound
})
For the case of 400 it works beautifully. But when it comes to 404 it is still the same message. I tested it in the same place in my code - it works for abort(400), abort(403) and some of the others, but it gets mysteriously overridden by default message on abort(404). Debugging didn't help much. What may be the culprit here?
Update. Yes, I'm using abort imported from flask not flask_restful as the latter doesn't have the mapping and it's a function not an Aborter object. Besides, it does work for most exceptions, so it's probably not the real issue here.
Update 2. The abort.mapping seems to be perfectly fine on execution. The exceptions in question are overridden, including 404.
Update 3: I've put together a little sandbox, that I use for debugging. (removed the repo since the mystery is long solved).
It took me some time, but now I actually found the place, where it all derails on 404 error. It's actually an undocumented feature in flask-restful. Look at the code here. Whatever message you chose persists until that very place and then it becomes the default. What we need now is just put ERROR_404_HELP = False to our config and everything works as intended.
Why is this code even there in the first place? OK, perhaps, I can live with that, but it should be all over the documentation. Even when I googled the name of the constant, I only got a couple of GitHub issues (1, 2).
Anyways, the mystery is officially solved.
By the way... I can't point to documentation for how I discovered this, I just tried it (that's how I learn most development!) but, you can simply abort with the desired response code but instead return a custom string with it. I think this makes sense because you're using the framework the way it's intended, you're not writing tons of code, you're returning the correct response code and in the fashion the framework expects, and you're informing any human who reads it as to the application's context for the error.
from flask import abort
abort(404, "And here's why.")
In the Flask documentation on testing (http://flask.pocoo.org/docs/testing/), it has a line of code
rv = self.app.get('/')
And below it, it mentions "By using self.app.get we can send an HTTP GET request to the application with the given path."
Where can the documentation be found for these direct access methods (I'm assuming that there's one for all of the restful methods)? Specifically, I'm wondering what sort of arguments they can take (for example, passing in data, headers, etc). Looking around on flask's documentation for a Flask object, it doesn't seem to list these methods, even though it uses them in the above example.
Alternatively, a knowledgeable individual could answer what I am trying to figure out: I'm trying to simulate sending a POST request to my server, as I would with the following line, if I were doing it over HTTP:
res = requests.post("http://localhost:%d/generate" % port,
data=json.dumps(payload),
headers={"content-type": "application/json"})
The above works when running a Flask app on the proper port. But I tried replacing it with the following:
res = self.app.post("/generate",
data=json.dumps(payload),
headers={"content-type": "application/json"})
And instead, the object I get in response is a 400 BAD REQUEST.
This is documented in the Werkzeug project, from which Flask gets the test client: Werkzeug's test client.
The test client does not issue HTTP requests, it dispatches requests internally, so there is no need to specify a port.
The documentation isn't very clear about support for JSON in the body, but it seems if you pass a string and set the content type you should be fine, so I'm not exactly sure why you get back a code 400. I would check if your /generate view function is invoked at all. A debugger should be useful to figure out where is the 400 coming from.