Using tipfy, how does one express a catch-all route in urls.py if more specific routes do not match?
Tipfy uses Werkzeug-like routing, so there's this (in urls.py):
def get_rules(app):
rules = [
Rule('/<any>', endpoint='any', handler='apps.main.handlers.MainHandler'),
Rule('/', endpoint='main', handler='apps.main.handlers.MainHandler'),
]
This will match most random entry points into the application (app.example.com/foo, app.example.com/%20 etc) but does not cover the app.example.com/foo/bar case which results in a 404.
Alternatively, is there a graceful way to handle 404 in Tipfy that I'm missing?
I think you want:
Rule('/<path:any>', endpoint='any', handler='apps.main.handlers.MainHandler')
The path matcher also matches slashes.
Maybe you could write custom middle ware:
class CustomErrorPageMiddleware(object):
def handle_exception(self, e):
return Response("custom error page")
To enable it add somewhere to tipfy config:
config['tipfy'] = {
'middleware': [
'apps.utils.CustomErrorPageMiddleware',
]
}
It gives you quite a flexibility - you could for example send mail somewhere to inform that there was a problem. This will intercept all exceptions in your application
Related
Is it possible to define a route that will be redirected to if Django could not find a match in the defined URLs?
For example, let's say I have:
urlpatterns = [
path('ajaxlogin', views.ajax_login, name='ajaxlogin'),
path('ajaxprofile', views.ajax_profile, name='ajaxprofile'),
]
Can I define a "dynamic" URL of a specific view that will be redirected to if the path doesn't exist? Suppose I enter the URLs /ajaxsignup and /ajaxdelete, which are not defined, but have them redirected to a URL of a certain view?
In other words:
urlpatterns = [
path('ajaxlogin', views.ajax_login, name='ajaxlogin'),
path('ajaxprofile', views.ajax_profile, name='ajaxprofile'),
path('every-other-url', views.another_view, name='path-everything-else'),
]
I know there's Django's error handlers, but are there any other ways to achieve this? I have my frontend based separately on a React application, so I'd very much appreciate a "dynamic" URL rather than using Django's default 404 responses.
I suspect that if path couldn't do it, I could use the old url with regex -- but I still have no clue.
Thanks in advance.
Just add a wildcard re_path at the end of your urlpatterns:
from django.http import HttpResponse
from django.urls import re_path
def http_response(request):
return HttpResponse('<h1>Hello HttpResponse</h1>')
urlpatterns = [
path('ajaxlogin', views.ajax_login, name='ajaxlogin'),
path('ajaxprofile', views.ajax_profile, name='ajaxprofile'),
path('every-other-url', views.another_view, name='path-everything-else'),
re_path(r'.*', http_response), # only if the above routes don't trigger a match
]
It processes routes in order, so if it doesn't find a route before it hits the wildcard, it will return that one.
I have a route that looks like this:
from(URL_A)
.from(URL_B)
.to(URL_C)
.process(...)
// logging
.to(URL_D)
This route works perfectly in Camel 2.X.X but not in 3.7.X
The error message I get:
Only one input is allowed per route. Cannot accept input: From[direct:ABCD]
I checked the migration guide, but I cannot get how to migrate this sort of route.
Do you have any idea how to tackle it further?
I think you can use direct component: https://camel.apache.org/components/3.4.x/direct-component.html
For example:
from(URL_A)
.to(direct:collector)
from(URL_B)
.to(direct:collector)
from(direct:collector)
.to(URL_C)
.process(...)
// logging
.to(URL_D)
#Stepan Shcherbakov suggested a solution, below will be an enhancement of it:
String [] sources = {URL_A, URL_B}
for (String source : sources) {
from(source)
.to(direct:collector)
}
from(direct:collector)
.to(URL_C)
.process(...)
// logging
.to(URL_D)
Using Next.js , I currently have an app with a single entry point in the form of /pages/[...slug]/index.ts
It contains a getServerSideProps function which analyses the slug and decide upon a redirection
In some cases a redirection is needed, but it will always be towards a page that can be statically rendered. Example: redirect /fr/uid towards /fr/blog/uid which can be static.
In other cases the slug already is the url of a page that can be static.
How can I mix this dynamic element with a static generation of all pages?
Thanks a lot for your help!
If I understood you problem correctly, you cannot use getServerSideProps if you are going to export a static site.
You have two solutions:
Configure your redirection rules in your web hosting solution (i.e. Amazon S3/CloudFront).
Create client-side redirects (when _app.tsx mounts you can check if router.asPath matches any of the redirection you would like to have configured.
Please remember that the first solution is more correct (as 301 redirects from the browser) for SEO purposes.
EDIT: #juliomalves rightly pointed out OP is looking at two different things: redirection, and hybrid builds.
However, question should be clarified a bit more to really be able to solve his problem.
Because you will need to host a web-server for SSR, you can leverage Next.js 9.5 built-in redirection system to have permanent server-side redirects.
When it comes to SSR vs SSG, Next.js allows you to adopt a hybrid approach, by giving you the possibility of choosing with Data Fetching strategy to adopt.
In case you are using AWS CloudFront, then you can redirect with CloudFront Functions.
CloudFront Functions is ideal for lightweight, short-running functions for use cases like the following:
URL redirects or rewrites – You can redirect viewers to other pages based on information in the request, or rewrite all requests from one path to another.
Here is what we are using to redirect clients (e.g. Native App, Google search index, etc.) to new location when NextJS page was moved or removed.
// NOTE: Choose "viewer request" for event trigger when you associate this function with CloudFront distribution.
function makeRedirectResponse(location) {
var response = {
statusCode: 301,
statusDescription: 'Moved Permanently',
headers: {
'location': { value: location }
}
};
return response;
}
function handler(event) {
var mappings = [
{ from: "/products/decode/app.html", to: '/products/decode.html' },
{ from: "/products/decode/privacy/2021_01_25.html", to: '/products/decode/privacy.html' }
];
var request = event.request;
var uri = request.uri;
for (var i = 0; i < mappings.length; i++) {
var mapping = mappings[i]
if (mapping.from === uri) {
return makeRedirectResponse(mapping.to)
}
}
return request;
}
So I have the routes defined for my app inside main.py, something like:
app = webapp2.WSGIApplication([
webapp2.Route('/', handler=HomePage, name="home")
])
Inside the cron job I can't seem to access the routes of the app, for example this doesn't work:
self.uri_for('home')
I found somewhere online a snippet that fixes it, but it's ugly to use:
cls.app.router.add(r)
Where r would be an array of routes.
Is there a way to have acces to the app's routes inside an app engine cron job?
Your example is incorrect, it seems to be a cross between simple routes and extended routes.
To be able to use self.uri_for('home') you need to use named routes, i.e. extended routes:
app = webapp2.WSGIApplication([
webapp2.Route(r'/', handler=HomePage, name='home'),
])
With that in place self.uri_for('home') should work, assuming self is a webapp2.RequestHandler instance.
The workaround just looks ugly, but that is pretty much what uri_for does under the hood as well:
def uri_for(self, _name, *args, **kwargs):
"""Returns a URI for a named :class:`Route`.
.. seealso:: :meth:`Router.build`.
"""
return self.app.router.build(self.request, _name, args, kwargs)
I am learning the webapp2 framework with its powerful Route mechanism.
My application is supposed to accept URIs like these:
/poll/abc-123
/poll/abc-123/
/poll/abc-123/vote/ # post new vote
/poll/abc-123/vote/456 # view/update a vote
Polls may optionally be organized into categories, so all the above should work also like this:
/mycategory/poll/abc-123
/mycategory/poll/abc-123/
/mycategory/poll/abc-123/vote/
/mycategory/poll/abc-123/vote/456
My incorrect configuration:
app = webapp2.WSGIApplication([
webapp2.Route('/<category>/poll/<poll_id><:/?>', PollHandler),
webapp2.Route('/<category>/poll/<poll_id>/vote/<vote_id>', VoteHandler),
], debug=True)
Question: How could I fix my configuration?
If possible it should be optimized for GAE CPU-time/hosting fee. For example, it may be faster if I add two lines for each entry: one line with category and another one without category...
webapp2 has a mechanism to reuse common prefixes, but in this case they vary, so you can't avoid duplicating those routes, as in:
app = webapp2.WSGIApplication([
webapp2.Route('/poll/<poll_id><:/?>', PollHandler),
webapp2.Route('/poll/<poll_id>/vote/<vote_id>', VoteHandler),
webapp2.Route('/<category>/poll/<poll_id><:/?>', PollHandler),
webapp2.Route('/<category>/poll/<poll_id>/vote/<vote_id>', VoteHandler),
], debug=True)
You should not worry about adding many routes. They are really cheap to build and match. Unless you have tens of thousands, reducing the number of routes won't matter.
A small note: the first route accepts an optional end slash. You could instead use the RedirectRoute to accept only one and redirect if the other is accessed, using the option strict_slash=True. This is not well documented but has been around for a while. See the explanation in the docstring.
I am going to add my solution to this as a complimentary answer on top of #moraes.
So other people having problems like below can get a more complete answer.
Trailing Slash Problem
Optional Parameter Problem
In addition, I figured out how to route both /entity/create and /entity/edit/{id} in one regex.
Below are my routes that supports the following url patterns.
/
/myentities
/myentities/
/myentities/create
/myentities/create/
/myentities/edit/{entity_id}
SITE_URLS = [
webapp2.Route(r'/', handler=HomePageHandler, name='route-home'),
webapp2.Route(r'/myentities/<:(create/?)|edit/><entity_id:(\d*)>',
handler=MyEntityHandler,
name='route-entity-create-or-edit'),
webapp2.SimpleRoute(r'/myentities/?',
handler=MyEntityListHandler,
name='route-entity-list'),
]
app = webapp2.WSGIApplication(SITE_URLS, debug=True)
Below is my BaseHandler that all my handlers inherit from.
class BaseHandler(webapp2.RequestHandler):
#webapp2.cached_property
def jinja2(self):
# Sets the defaulte templates folder to the './app/templates' instead of 'templates'
jinja2.default_config['template_path'] = s.path.join(
os.path.dirname(__file__),
'app',
'templates'
)
# Returns a Jinja2 renderer cached in the app registry.
return jinja2.get_jinja2(app=self.app)
def render_response(self, _template, **context):
# Renders a template and writes the result to the response.
rv = self.jinja2.render_template(_template, **context)
self.response.write(rv)
Below is my MyEntityHandler python class with the get() method signature for the Google App Engine Datastore API.
class MyEntityHandler(BaseHandler):
def get(self, entity_id, **kwargs):
if entity_id:
entity = MyEntity.get_by_id(int(entity_id))
template_values = {
'field1': entity.field1,
'field2': entity.field2
}
else:
template_values = {
'field1': '',
'field2': ''
}
self.render_response('my_entity_create_edit_view_.html', **template_values)
def post(self, entity_id, **kwargs):
# Code to save to datastore. I am lazy to write this code.
self.redirect('/myentities')