All, I'm trying to raise a custom error using Flask-Restful, following the docs. For testing purposes, I've defined and registered the errors dictionary exactly link in the docs: api = flask_restful.Api(app, errors=errors).
However, when I want to raise the custom error using (e.g.) abort(409) within the resource module, firebug reports:
{
"message": "Conflict",
"status": 409
}
This seems like the standard 409 error, nothing custom; from the docs, I would expect the custom error message- "A user with that username already exists."
I think I'm missing something regarding the raising of the error itself. Should I use the dictionary key in any way? Reviewing the Flask-Restful source code didn't help, though I tried.
To define a message for a standard HTTP status code with Flask-RESTful, you must redefine one of the HTTP exceptions provided by Werkzeug, on which Flask is based.
Following your question, here is an example to override the Conflict exception:
errors = {
'Conflict': {
'message': "A user with that username already exists.",
'status': 409,
},
}
app = Flask(__name__)
api = flask_restful.Api(app, errors=errors)
Hence, every time you will call abort(409), this will return a representation in the right mediatype, and with the defined message.
However, by using this method, in any place you will abort with a 409 status code, this will return a message about a user with a username that already exists. This is unlikely what you want when you call abort(409) in a view that deals with other resources than users.
So, I advise you to simply use the abort method of Flask-RESTful as follows, every time you want to provide a custom message:
from flask.ext.restful import abort
abort(409, description="A user with that username already exists.")
Generally speaking, extending Flask-RESTful by defining custom error messages is useful when you raise custom exceptions (with raise(), not abort()) which are not in the HTTP exceptions provided by Werkzeug.
Related
I am trying to integrate stripe with my django project, so I try to create a PaymentIntent and if a network communication with stripe failed I will try to do like this:
try:
intent = stripe.PaymentIntent.create(
amount=100,
currency='usd'
)
return JsonResponse({
'clientSecret': intent['client_secret']
})
except stripe.error.CardError as e:
pass
except stripe.error.RateLimitError as e:
pass
except stripe.error.InvalidRequestError as e:
pass
except stripe.error.AuthenticationError as e:
pass
except stripe.error.APIConnectionError as e:
try:
intent_cancel = stripe.PaymentIntent.cancel(
intent['id']
)
except Exception as e:
# (If an exception is raised this means that the PaymentIntent was not created, I am right ?)
# I redirect the user to the payment page and inform him
# that a network problem has occurred and ask him to repeat his request
pass
except stripe.error.StripeError as e:
pass
except Exception as e:
pass
My questions are:
1 Is my way of handling the exception right ?
2 Can I apply this logic to the other exception ?
3 In the documentation they say that we should use an idempotency_key to retry the failed requests, how can I implement this ? and what about if I retry the failed request and it fails again, what should I do ?
You have 2 Stripe API requests in the same try block. This means if one succeeds but the other fails due to a connection error you'll treat both as failed. A better flow would be to only have one API operation per try/catch block.
You also have a request to cancel a hardcoded PaymentIntent after your code returns a JSON object. Since the return isn't conditional this is likely dead code.
The cancel logic in the case of a connection error doesn't make sense here. You should only hit this path if the connection failed and the intent wasn't created, so trying to cancel the non-existent PaymentIntent will likely result in yet another error. Instead you should introduce retry logic here. Luckily stripe-python has this built in specifically for network errors: https://github.com/stripe/stripe-python#configuring-automatic-retries
Once all retries have failed, you should probably log that somewhere and inform your user that a problem occurred and that they should try again later.
As for idempotency keys, the Stripe docs have a primer on that here: https://stripe.com/docs/api/idempotent_requests?lang=python
Somehow, using django 1.7 with the default email backend, I get an error: 111 Connection Refused. This is triggered as an exception, even when the fail_silently parameter is True.
The line goes like this:
return send_mail(subject=u"Bienvenido a Mi CNT!",
message=render_to_string('micnt/mail.welcome.txt', context),
from_email=settings.DEFAULT_FROM_EMAIL,
recipient_list=[email_address],
fail_silently=True,
html_message=render_to_string('micnt/mail.welcome.html', context))
I know how to fix the excepcion (I forgot to configure certain parameters). However, there will be cases where, perhaps, the exception will be due to other reasons (e.g. I correctly specified the mail parameters, but the server got down).
Why is fail_silently not working? What is the "scope" of fail_silently? (i.e. which errors does it cover, and which errors does it let pass to the invoker?).
I would like to correctly cover the exceptions without having to:
try:
return send_mail(...)
except Exception as e:
# I want to understand what exception types will be triggered here.
pass
fail_silently will only catch SMTPException's when send_mail attempts to connect to email server (executes get_connection).
I like to take issues like this as an opportunity to look into the django source code, which contains all the answers:
https://github.com/django/django/blob/master/django/core/mail/backends/smtp.py#L69
I'm trying to access a Google Drive using gdata-Python-client package. I can get access to an account by providing authentication details (user name, password) and open a client to manipulate spreadsheets.
import gdata.spreadsheet.service
client=gdata.spreadsheet.service.SpreadsheetsService()
client.email=some_username
client.password=some_pwd
Now I want to check whether the login process was successful and I write the following piece of code.
try:
client.ProgrammaticLogin()
return True
except:
return False
This code throws an exception if the login fails.
Are there other ways we can achieve this without catching this exception? (Eg. checking within an if clause using a return value of a method)
As far as I know ProgrammaticLogin() method itself does not return any value (i.e. type(ProgrammaticLogin()) returns 'NoneType')
If try-except is the only way to check this what is the name of the exact Exception thrown at this instant?
Thanks
According to this link multiple types of exceptions are thrown based on the error type
http://gdata-python-client.googlecode.com/hg/pydocs/gdata.service.html
(This is the first time I've done this actually.)
<mx:HTTPService id="post_update" method="POST" result="{Dumper.info('bye')}"/>
The result handler above is just for debugging purposes, but its never hit, even though what I'm uploading via POST...
post_update.url = getPath(parentDocument.url)+"update";
post_update.send(new_sel);
...is received and handled successfully by my Django view:
def wc_post(request) :
request.session['wc'] = request.POST
return http.HttpResponse("<ok/>", mimetype="text/xml")
As far as what I'm sending back from Django, I'm following the guidelines here:
Sending Images From Flex to a Server
I just don't want it to generate an error on the Flex side considering Django is actually receiving and processing the data. Any help appreciated. Can't remember the text of the error in Flex at the moment.
UPDATE: new_sel (what I'm posting from Flex) is just a Flex Object, with various text fields.
UPDATE: various error messages from event.message (in fault handler):
faultCode = "Server.Error.Request"
faultString = "HTTP request error"; DSStatusCode = 500; errorID = 2032; type = "ioError"
This is more grasping at straws than answers, but do I have to send a particular type of header back from Django- the default sent by Django includes a 200 success status code, and the response I was sending of "<ok/>" with mime type of "text/xml" was following the example exactly that I provided from that other source.
And also the url I'm sending the POST to is localhost:8000/wr_view1/wr_webcube/update, and I previously successfully did a GET to localhost:8000/wr_view1/wr_webcube/webcube.xml, and despite the .xml extension in the case of GET, it was still being handled by Django (and without errors in Flex). In the case of this POST, once again, the data is actually succesfully sent and handled by Django, but Flex is returning Error 2032, which I found out can mean numerous different things including cross domain issues, but don't see how that's the case here.
Just had to return HttpResponse("ok") Didn't like it being sent as xml for some reason. So much ado about nothing I guess.
I have a bug in my 404 setup. I know that because, when I try to reach some page which doesn't exist, I get my server error template. But that templates is useless because it doesn't give me any debug info. In order to get django's debug page, I need to set DEBUG=True in settings file. But if I do that, bug doesn't appear because django doesn't try to access my buggy 404 setup. So what do you guys think? This is in my root urls file:
handler404 = 'portal.blog.views.handlenotfound' And this is in portal.blog.views.handlenotfound:
def handlenotfound(request):
global common_data
datas = {
'tags' : Tag.objects.all(),
'date_list' : Post.objects.filter(yayinlandi=True).dates("pub_date","year")
}
data.update(common_data)
return render_to_response("404.html",datas)
Edit:
I guess I also need to return a HttpResponseNotFound right?
If I had to debug this kind of errors, I would either
temporarily turn the handler into a simple view served by a custom url, so that django's internal mechanisms don't get into the way, or
(temporarily) wrap the handler code in a try..except block to log any error you may have missed
Anyway, are you sure your handler doesn't get called if DEBUG=true?
data.update(common_data) should be datas.update(common_data).
(Incidentally, data is already plural: the singular is datum.)