Can anybody help me to understand why not raise an HTTPException when the status is 200 instead a return ?
working with fastApi
A code as example:
#app.delete("/delete")
def delete(id = Query(...,description="Delete ID to be deleted")):
if id not in dictionary:
raise HTTPException(status_code=404,detail="Delete Id doesn't exists.")
del dictionary[id]
return {"Success":"Delete deleted!"}
I want to understand why not to use as example:
raise HTTPException(status_code=200,detail="Delete deleted!")
Is this a correct way to use it?
First of all because of the semantics: an exception is a language construct that means something else than returning the result of a function. It breaks the normal flow of the FastAPI application, and I'm guessing it will/could break most middleware handling (such as CORS headers) because suddenly an exception has occurred instead.
Secondly: Because you probably want to return something else than just information under a detail key. It won't be able to use the response_model mechanism that's built-in to FastAPI and allows you to tweak and validate the response model for each type of request declaratively (i.e. by configuring the view decorator).
Related
I am building a web application that works as Web API server for our mobile and Electron app. I am trying to properly design our error handling too.
I use Django, Django Rest Framework for RESTful API implementation.
For psycopg2 errors, I get the following:
"column "unifiedidd" of relation "basicinformation" does not
exist\nLINE 1: INSERT INTO profile.basicinformation (unifiedidd,
firstname,...\n ^\nQUERY:
INSERT INTO profile.basicinformation (unifiedidd, firstname,
middlename, familyname, sex, birthdate) VALUES
('8f38f402-ddee-11ea-bfee-ead0fcb69cd9'::uuid, 'Lily Francis Jane',
'Luo Yi', 'Chao Fan', 'Male', '1990-03-20')\nCONTEXT: PL/pgSQL
function inline_code_block line 5 at SQL statement\n"
In my view file, I am catching these errors as such:
def post(self, request, *args, **kwargs):
try:
return Response({"message": "Cool"},status=http_200_OK)
except ProgrammingError as e:
return Response({"message": str(e)},status=http_500_INTERNAL_SERVER_ERROR)
except IntegrityError as e:
return Response({"message": str(e)},status=http_500_INTERNAL_SERVER_ERROR)
except Exception as e:
return Response({"message": str(e)},status=http_500_INTERNAL_SERVER_ERROR)
First thing I wanna confirm is, because of the content of the error, I assume it is not a good idea to output the whole thing right? Since it shows the actual query. This is useful but maybe for error logging for developer use only.
So I assume I need to output a custom message. But given that there are tons of errors that may be encountered and I think it's impossible to create a custom message for each of these errors, I am thinking to output just a wildcard error message such as `Unexpected error has been encountered. Please contact developer team."
But also, this wildcard error message does not seem so informative for both the developers and the users as well.
I am not sure how to properly handle exceptions and response it to the API client as informative as possible.
I'm new to Flask and web development. I have a question about url parameters.
For example, I have an endpoint '/categories' which expect no url arguments. I experimented adding some random url parameter in curl like
curl localhost:5000/categories?page=1
It works like normal, I'm wondering if that is the expected behavior or should I handle this with some error or warning?
Also, if I expect an url parameter called 'id' and the request contains no url parameter or wrong url parameter. How should I handle this situation?
What status code should I abort in the above situations?
Thank you for any help.
You will need to inspect your query string (the values after ? in the URL) to see if the parameter exists and the value is valid. There are libraries to do this with a decorator, but you can do it manually as well. You will need to import the request object at the top of your module.
from flask import request
#app.route('/categories')
def categories():
id = request.args.get('id') # will return None if key does not exist
if id:
# id exists, validate value here
pass
else:
# no id, return error or something
pass
Related question:
How do you get a query string on Flask?
I wish to handle NoneType errors from the Google App Engine ndb Datastore.
Here is my code:
def post(self):
# get the email and password from the login form
global u_qry
email = self.request.get("email")
password = self.request.get("password")
try:
u_qry = user_db.User.get_by_email(email)
except BaseException, e:
self.response.out.write(e, u_qry)
else:
self.response.out.write("User Recognised")
self.response.out.write(u_qry)
When the user does not exist, the except clause is not catching any error.
Output:
User Recognised None
why is the except clause not catching this error? What exception can be used to catch this error?
I realise I can use if/else statements on this, but would like to learn how to use the try/except clause in GAE.
Thanks.
While you're not showing the way the User.get_by_email() function is implemented I suspect it is simply based on a query. And returning an empty result from a query is a perfectly valid situation - no existing datastore entity matches the query. It's not an exception.
If you intend to consider such case an exception you have to raise one yourself inside User.get_by_email() and in that case you'd be able to catch it in your post() function.
Alternatively you can directly check u_qry for a None value.
I have a thorny problem that I can't seem to get to grips with. I am
currently writing unit tests for a django custom auth-backend. On our
system we actually have two backends: one the built-in django backend
and the custom backend that sends out requests to a Java based API
that returns user info in the form of XML. Now, I am writing unit
tests so I don't want to be sending requests outside the system like
that, I'm not trying to test the Java API, so my question is how can I
get around this and mock the side-effects in the most robust way.
The function I am testing is something like this, where the url
settings value is just the base url for the Java server that
authenticates the username and password data and returns the xml, and the service value is
just some magic for building the url query, its unimportant for
us:
#staticmethod
def get_info_from_api_with_un_pw(username, password, service=12345):
url = settings.AUTHENTICATE_URL_VIA_PASSWORD
if AUTH_FIELD == "username":
params = {"nick": username, "password": password}
elif AUTH_FIELD == "email":
params = {"email": username, "password": password}
params["service"] = service
encoded_params = urlencode([(k, smart_str(v, "latin1")) for k, v in params.items()])
try:
# get the user's data from the api
xml = urlopen(url + encoded_params).read()
userinfo = dict((e.tag, smart_unicode(e.text, strings_only=True))
for e in ET.fromstring(xml).getchildren())
if "nil" in userinfo:
return userinfo
else:
return None
So, we get the xml, parse it into a dict and if the key nil is present
then we can return the dict and carry on happy and authenticated.
Clearly, one solution is just to find a way to somehow override or
monkeypatch the logic in the xml variable, I found this answer:
How can one mock/stub python module like urllib
I tried to implement something like that, but the details there are
very sketchy and I couldn't seem to get that working.
I also captured the xml response and put it in a local file in the
test folder with the intention of finding a way to use that as a mock
response that is passed into the url parameter of the test function,
something like this will override the url:
#override_settings(AUTHENTICATE_URL_VIA_PASSWORD=(os.path.join(os.path.dirname(__file__), "{0}".format("response.xml"))))
def test_get_user_info_username(self):
self.backend = RemoteAuthBackend()
self.backend.get_info_from_api_with_un_pw("user", "pass")
But that also needs to take account of the url building logic that the
function defines, (i.e. "url + encoded_params"). Again, I could rename
the response file to be the same as the concatenated url but this is becoming
less like a good unit-test for the function and more of a "cheat", the whole
thing is just getting more and more brittle all the time with these solutions, and its really just a fixture anyway, which is also something I want to avoid if
at all possible.
I also wondered if there might be a way to serve the xml on the django development server and then point the function at that? It seems like a saner solution, but much googling gave me no clues if such a thing would be possible or advisable and even then I don't think that would be a test to run outside of the development environment.
So, ideally, I need to be able to somehow mock a "server" to
take the place of the Java API in the function call, or somehow serve
up some xml payload that the function can open as its url, or
monkeypatch the function from the test itself, or...
Does the mock library have the appropriate tools to do such things?
http://www.voidspace.org.uk/python/mock
So, there are two points to this question 1) I would like to solve my
particular problem in a clean way, and more importantly 2) what are
the best practices for cleanly writing Django unit-tests when you are
dependent on data, cookies, etc. for user authentication from a remote
API that is outside of your domain?
The mock library should work if used properly. I prefer the minimock library and I wrote a small base unit testcase (minimocktest) that helps with this.
If you want to integrate this testcase with Django to test urllib you can do it as follows:
from minimocktest import MockTestCase
from django.test import TestCase
from django.test.client import Client
class DjangoTestCase(TestCase, MockTestCase):
'''
A TestCase class that combines minimocktest and django.test.TestCase
'''
def _pre_setup(self):
MockTestCase.setUp(self)
TestCase._pre_setup(self)
# optional: shortcut client handle for quick testing
self.client = Client()
def _post_teardown(self):
TestCase._post_teardown(self)
MockTestCase.tearDown(self)
Now you can use this testcase instead of using the Django test case directly:
class MySimpleTestCase(DjangoTestCase):
def setUp(self):
self.file = StringIO.StringIO('MiniMockTest')
self.file.close = self.Mock('file_close_function')
def test_urldump_dumpsContentProperly(self):
self.mock('urllib2.urlopen', returns=self.file)
self.assertEquals(urldump('http://pykler.github.com'), 'MiniMockTest')
self.assertSameTrace('\n'.join([
"Called urllib2.urlopen('http://pykler.github.com')",
"Called file_close_function()",
]))
urllib2.urlopen('anything')
self.mock('urllib2.urlopen', returns=self.file, tracker=None)
urllib2.urlopen('this is not tracked')
self.assertTrace("Called urllib2.urlopen('anything')")
self.assertTrace("Called urllib2.urlopen('this is mocked but not tracked')", includes=False)
self.assertSameTrace('\n'.join([
"Called urllib2.urlopen('http://pykler.github.com')",
"Called file_close_function()",
"Called urllib2.urlopen('anything')",
]))
Here's the basics of the solution that I ended up with for the record. I used the Mock library itself rather than Mockito in the end, but the idea is the same:
from mock import patch
#override_settings(AUTHENTICATE_LOGIN_FIELD="username")
#patch("mymodule.auth_backend.urlopen")
def test_get_user_info_username(self, urlopen_override):
response = "file://" + os.path.join(os.path.dirname(__file__), "{0}".format("response.xml"))
# mock patch replaces API call
urlopen_override.return_value = urlopen(response)
# call the patched object
userinfo = RemoteAuthBackend.get_info_from_api_with_un_pw("user", "pass")
assert_equal(type(userinfo), dict)
assert_equal(userinfo["nick"], "user")
assert_equal(userinfo["pass"], "pass")
How do I control the HTTP Status Code in the protoRPC response?
Let's say I have the following service:
class ApiService(remote.Service):
#remote.method(ApiRequestContextCreate, ApiResponseContextCreate)
def context_create(self, request):
cid = helpers.create_context(request.name)
return ApiResponseContextCreate(cid=cid)
Looks to me that the protoRPC API is lacking semantics: either the request can be fulfilled and returns a 200 or an exception is raised yielding to a 404. Of course of could craft an error response in the RPC method but that seems kludgy.
Update: I have found I can raise ApplicationError too for a 400.
The HTTP status code is not part of the specification for ProtoRPC because ProtoRPC is meant to support protocols besides HTTP. It therefore cannot have specific-to-HTTP return codes. Instead, errors are returns by raising ApplicationError, using the error_name field to specify application specific error conditions.