Gae webapp2 routing problems. match the uris wrong - google-app-engine

I'm having difficulties with the gae webapp2 routing sistem.
In my routes.py I have the following:
_route = [
RedirectRoute('/', 'home.HomeHandler', name='home', strict_slash=True),
RedirectRoute('/users/<usercode>', 'users.UserSingleHandler', name='user-page', strict_slash=True),
RedirectRoute('/users/comments/new/', 'users.UserNewCommentHandler', name='new-comment', strict_slash=True)
]
The problem I have is that when doing a ajax call to '/users/comments/new' the handler that receives the call is UserSingleHandler and not the one I need (UserNewCommentHandler).
When inspecting the code, I found that de usercode param in UserSingleHandler gets '/comments/new/'... weird!!
¿What I'm doing wrong?

Route like '/users/' will catch all requests on '/users/*', so you can fix your problem by changing the order of routes:
_route = [
RedirectRoute('/', 'home.HomeHandler', name='home', strict_slash=True),
RedirectRoute('/users/comments/new/', 'users.UserNewCommentHandler', name='new-comment', strict_slash=True)
RedirectRoute('/users/<usercode>', 'users.UserSingleHandler', name='user-page', strict_slash=True),
]

Related

PrettyPrint feature does not work in Apache Camel

I have been trying to leverage the PrettyPrint feature to display the result of my API that is using Apache Camel. Here is the context. I have this route in my code
// Route Definition for processing Health check request
from("direct:processHealthCheckRequest")
.routeId("health")
.setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200))
.setBody(constant(healthCheckResponse));
When I'm using Postman to test my API, the display is in pretty mode even though it is not set to true, like so
{
"status": "UP"
}
Now when I'm using the following code to set the PrettyPrint to false, I'm still getting the same result. It looks like the PrettyPrint feature is not working as it is supposed to
// Route Definition for processing Health check request
from("direct:processHealthCheckRequest")
.routeId("health")
.setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200))
.setBody(constant(healthCheckResponse))
.unmarshal()
.json(JsonLibrary.Jackson, HealthCheckResponse.class, false);
I'm expecting the result to be displayed on one line like here without changing the type from JSON to string.
{"status": "UP"}
Could someone please advice on this?
I've bumped into the same issue always when manually setting the HTTP_RESPONSE_CODE header. I don't know why it technically happens - without it the HTTP response always returns proper JSON for me.
Setting CONTENT_TYPE header to application/json has solved it:
.setHeader(Exchange.CONTENT_TYPE, constant("application/json"))
The solution that finally worked was to set the following in my application.properties file.
camel.rest.data-format-property.prettyPrint=false
or not to provide that property at all.
Try this:
<removeHeaders id="removeHeaders_http*" pattern="CamelHttp*"/>
<setHeader headerName="Content-type" id="content_setHeader">
<constant>application/x-www-form-urlencoded</constant>
</setHeader>
Same with Java DSL:
.removeHeaders("CamelHttp*")
.setHeader("Content-type", constant("application/x-www-form-urlencoded"))

AppEngine python's send_email not working anymore

My appengine app has a cron job that calls a url endpoint whose handler uses mail.send_mail from google.appengine.api. This has been working fine for several months so far.
Today, the email never arrived. I wrote some test code to invoke send_mail, but the email does not get sent. I have adhered to the necesarry requirements like sending from a email address of the form anything#appname.appspotmail.com.
The function is not throwing any exception either. The appengine logs note that the url is invoked, but there is no error or exception.
What might be the problem? Thanks.
Editing to add some code as suggested. Note that to actually test this code one'd need an AppEngine App. In that case you'd need to change myApp etc. in the code below to the actual app name that is used.
Looking forward to any help/insights.
from google.appengine.api import mail
class TestEmailHandler(webapp2.RequestHandler):
def get(self):
mySender = "mySender <mySender#myApp.appspotmail.com>"
myTo = "myToAddress#example.com"
mySubject = "Test Subject"
myBody = "Test Body Text"
myHtml = "<html><body>Test body</body></html>"
try:
mail.send_mail(sender=mySender,
to=myTo,
subject=mySubject,
body=myBody,
html=myHtml)
self.response.headers['Content-Type'] = 'text/plain'
self.response.write("Sent email. Body: " + myBody)
except:
self.response.write("Exception. " + sys.exc_info()[0])
application = webapp2.WSGIApplication([
('/', MainPage),
('/test_email', TestEmailHandler)
], debug=True)
My app.yaml looks like this:
application: myApp
version: 2
runtime: python27
api_version: 1
threadsafe: true
handlers:
- url: /.*
script: myApp.application
inbound_services:
- mail
I think the problem's now fixed. I associated my credit card by enabling billing and now an email got sent when I tested it. Who would've thought...

How do you escape a . (full stop) or / so it doesn't change URL's meaning?

I have a Web API 2.0 service which defines a particular route:
/api/someEntityGroup/{entityName}
I'm calling this enpoint using Angular $resource service.
The problem is when user wants to provide an entity name with characters that have a specific meaning in URL:
404 Not found - . (full stop), /, +
400 Bad request - ?, :, &, %, *, <, >
And these are the ones I've encountered. There may be others that may be problematic as well and I'm not even aware of them (yet).
If I use window.escape() function these still don't work, but I mainly get 404 back (the only exception being * which still returns 400 Bad request).
My code
Angular resource creation:
.factory("entityResource", ["$resource", function() {
return $resource("/api/entities/:id", null, {
search: {
method: "GET",
url: "/api/entities/:name",
isArray: true
}
});
}]);
How I call it in my code:
entityResource.search({ query: scope.name }, function(data) {
...
});
My Api controller action:
[RoutePrefix("/api/entities")]
public class EntitiesController: ApiController
{
[Route("{searchQuery}")]
public IEnumerable<Interest> Get(string searchQuery)
{
return this.interestService.Search(searchQuery);
}
...
}
I can shed some light on your 404 Not found issue when using ., /, + characters.
The issue isn't with Angular but rather with Web API and the way it resolves routes. Urls that Web API interprets as being managed resources (e.g. static content, pages etc.) it will try to resolve independently.
Set the following in your web.config to disable this behavior and force WebAPI to run all requests through your modules:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
</system.webServer>
Just a warning - If your Web API is hosted together with something like MVC or a static website, the above is not recommended as it will force all managed resources (pages, MVC routes, content[css,js,images]) through your API modules and there will be a performance impact. However, if all the API is doing is serving resource routes I would recommend enabling the above.

flask: error_handler for blueprints

Can error_handler be set for a blueprint?
#blueprint.errorhandler(404)
def page_not_found(error):
return 'This page does not exist', 404
edit:
https://github.com/mitsuhiko/flask/blob/18413ed1bf08261acf6d40f8ba65a98ae586bb29/flask/blueprints.py
you can specify an app wide and a blueprint local error_handler
You can use Blueprint.app_errorhandler method like this:
bp = Blueprint('errors', __name__)
#bp.app_errorhandler(404)
def handle_404(err):
return render_template('404.html'), 404
#bp.app_errorhandler(500)
def handle_500(err):
return render_template('500.html'), 500
errorhandler is a method inherited from Flask, not Blueprint.
If you are using Blueprint, the equivalent is app_errorhandler.
The documentation suggests the following approach:
def app_errorhandler(self, code):
"""Like :meth:`Flask.errorhandler` but for a blueprint. This
handler is used for all requests, even if outside of the blueprint.
"""
Therefore, this should work:
from flask import Blueprint, render_template
USER = Blueprint('user', __name__)
#USER.app_errorhandler(404)
def page_not_found(e):
""" Return error 404 """
return render_template('404.html'), 404
On the other hand, while the approach below did not raise any error for me, it didn't work:
from flask import Blueprint, render_template
USER = Blueprint('user', __name__)
#USER.errorhandler(404)
def page_not_found(e):
""" Return error 404 """
return render_template('404.html'), 404
add error handling at application level using the request proxy object:
from flask import request,jsonify
#app.errorhandler(404)
#app.errorhandler(405)
def _handle_api_error(ex):
if request.path.startswith('/api/'):
return jsonify(ex)
else:
return ex
flask Documentation
I too couldn't get the top rated answer to work, but here's a workaround.
You can use a catch-all at the end of your Blueprint, not sure how robust/recommended it is, but it does work. You could also add different error messages for different methods too.
#blueprint.route('/<path:path>')
def page_not_found(path):
return "Custom failure message"
Surprised others didn't mention miguelgrinberg's excellent tutorial.
https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-vii-error-handling
I found the sentry framework for error handling (links below). Seems overly complex. not sure of the threshold where it becomes useful.
https://flask.palletsprojects.com/en/1.1.x/errorhandling/
https://docs.sentry.io/platforms/python/guides/flask/
I combined previous excellent answers with the official docs from Flask, section 'Returning API Errors as JSON', in order to provide a more general approach.
Here is a working PoC that you can copy and paste on your registered blueprint API route handler (e.g. app/api/routes.py):
#blueprint.app_errorhandler(HTTPException)
def handle_exception(e):
"""Return JSON instead of HTML for HTTP errors."""
# start with the correct headers and status code from the error
response = e.get_response()
# replace the body with JSON
response.data = json.dumps({
"code": e.code,
"name": e.name,
"description": e.description,
})
response.content_type = "application/json"
return response
Flask doesnt support blueprint level error handlers for 404 and 500 errors. A BluePrint is a leaky abstraction. Its better to use a new WSGI App for this, if you need separate error handlers, this makes more sense.
Also i would recommend not to use flask, it uses globals all over the places, which makes your code difficult to manage if it grows bigger.

What's the best practice to use named Route in AppEngine?

In the app.yaml file, I have put 2 lines to specify the url mapping:
url: /blog/.*
script: blog.app
url: /
script: home.app
the problem is I can't use the "uri_for" function to generate a url for blog module in home.py, case there's no Route added in home moudle:
here is the code in home module:
app = webapp2.WSGIApplication([
webapp2.Route(r'/', handler=HomeHandler, name='home')
], debug = SITE_CONFIG['is_debug'], config=SITE_CONFIG)
and code in blog.py:
app = webapp2.WSGIApplication([
webapp2.Route(r'/blog/<blog_id:\d+>', handler=BlogHandler, name="blog")
], debug = SITE_CONFIG['is_debug'], config=SITE_CONFIG)
so, if I have code like this: {{ uri_for('blog', blog_id=blabla) }} in home.html, it can't work.
You should consolidate those routes into one app.
app = webapp2.WSGIApplication([
webapp2.Route(r'/', handler=HomeHandler, name='home'),
webapp2.Route(r'/blog/<blog_id:\d+>', handler=BlogHandler, name="blog")
], debug = SITE_CONFIG['is_debug'], config=SITE_CONFIG)
and actually those are only the view blog post routes.
If you wanted to do a full CRUD app, you might need to add some more.
app = webapp2.WSGIApplication([
webapp2.Route(r'/admin/blog', handler='admin.AdminBlogHandler:list, name="admin.blog.list"),
webapp2.Route(r'/admin/blog/new', handler='admin.AdminBlogHandler:new', name='admin.blog.edit'),
webapp2.Route(r'/admin/blog/<id:[^/]+>/edit', handler='admin.AdminBlogHandler:edit', name='admin.blog.edit'),
webapp2.Route(r'/admin/blog/<id:[^/]+>', handler='admin.AdminBlogHandler:view', name='admin.blog.view')
], debug = SITE_CONFIG['is_debug'], config=SITE_CONFIG)
Note for these examples:
1) you prefix a name to load the handlers from a different file (admin.AdminBlogHandler will look in 'admin.py' for 'class AdminBlogHandler'
2) you specify the method to run after the handler name, after the colon.
3) in each method I am creating functionality for get and post, so there are not discrete RESTful URLs for edit and update.

Resources