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.
Related
I am newbie to service worker concept so forgive me if I am overlooking something from documentation. I have an angular application already running in production and I am trying to introduce service worker using sw-precache.
To start with I am trying to precache all images/fonts and couple of js files and see if it works, so my precache config is like this -
{
"cacheId": "static-cache",
"importScripts": [
"sw-toolbox.js"
],
"stripPrefix": "dist/",
"verbose": true,
"staticFileGlobs": [
"dist/img/**.*",
"dist/javascripts/require.js",
"dist/stylesheets/**.*",
"dist/webfonts/**.{ttf, eot, woff}",
"sw-toolbox.js",
"service-worker.js"
]
}
Now I can see service worker registered and installed properly and cache storage shows all the urls with _sw-precache hashes.
But when I load the application and see in network tab all static content are still served from memory/disk, not from service worker and I am unable to debug why is it so. Am I missing something here -
UPDATE:
More information: I had wrong configurations since I have dynamic url and server side rendered html. Server side it's test.jsp which is giving me initial shell.
For now I have removed all other static files from cache and kept only show.css
So update config now is -
{
"importScripts": [
"sw-toolbox.js"
],
"stripPrefix": "dist/",
"verbose": true,
"staticFileGlobs": [
"dist/stylesheets/show.css"
],
"dynamicUrlToDependencies": {
"/developers": ["dist/stylesheets/show.css"]
},
"navigateFallback": "/developers"
}
Web root folder is named differently and it is -
- dashboard
-- img
-- javascripts
-- service-worker.js
-- sw-toolbox.js
- test.jsp
And I see /developers url as an entry in storage cache, but still it's not served from service worker for next refresh. I have tried all my energy to fix this, but I desperately need some clue here, what's missing in here. TIA.
Let me know if need more info.
It seems that whitespaces in your file extension list are not allowed. Your definition for webfonts should be:
"dist/webfonts/**.{ttf,eot,woff}",
I cloned the sw-precache repo and added a unit test where I compared two generated files with two diffrent staticFileGlobs, one with whitespace and one without.
it('should handle multiple file extensions', function(done) {
var config = {
logger: NOOP,
staticFileGlobs: [
'test/data/one/*.{txt,rmd}'
],
stripPrefix: 'test'
};
var configPrime = {
logger: NOOP,
staticFileGlobs: [
'test/data/one/*.{txt, rmd}'
],
};
generate(config, function(error, responseString) {
assert.ifError(error);
generate(configPrime, function(error, responseStringPrime) {
assert.ifError(error);
console.log('responseStringPrime',responseString);
assert.strictEqual(responseString, responseStringPrime);
done();
});
});
});
and it failed. The second config didn't include the .rmd file:
-var precacheConfig = [["/data/one/a.rmd","0cc175b9c0f1b6a831c399e269772661"],["/data/one/a.txt","933222b19ff3e7ea5f65517ea1f7d57e"],["/data/one/c.txt","fa1f726044eed39debea9998ab700388"]];
versus
+var precacheConfig = [["test/data/one/a.txt","933222b19ff3e7ea5f65517ea1f7d57e"],["test/data/one/c.txt","fa1f726044eed39debea9998ab700388"]];
consider the following scenario:
My express server dynamically generates HTML for the "/" route of my single page application.
I would like to re-serve this same generated HTML as the service worker navigateFallback when the user is offline.
I'm using https://www.npmjs.com/package/sw-precache-webpack-plugin in my webpack configuration.
If I generate an index.html via html-webpack-plugin, say, and set index.html as my navigateFallback file, that generated file gets served correctly by the service worker.
However, I can see no way to cause the on-the-fly rendered index html (what the live server returns for the "/" path) to be cached and used as the offline html.
Use dynamicUrlToDependencies option of Service Worker Precache to cache your route url and its dependencies. Then set navigateFallback to '/' and navigateFallbackWhitelist to a regex matching your sublinks logic.
Take this configuration : (Add const glob = require('glob') atop of your webpack config)
new SWPrecacheWebpackPlugin({
cacheId: 'my-project',
filename: 'offline.js',
maximumFileSizeToCacheInBytes: 4194304,
dynamicUrlToDependencies: {
'/': [
...glob.sync(`[name].js`),
...glob.sync(`[name].css`)
]
},
navigateFallback: '/',
navigateFallbackWhitelist: [/^\/page\//],
staticFileGlobsIgnorePatterns: [/\.map$/],
minify: false, //set to "true" when going on production
runtimeCaching: [{
urlPattern: /^http:\/\/localhost:2000\/api/,
// Use network first and cache as a fallback
handler: 'networkFirst'
}],
})
That use case should be supported. I have an example of something similar using the underlying sw-precache library, and I believe the syntax should be equivalent when using the Webpack wrapper.
In this case, /shell is the URL used for dynamically generated content from the server, constituting the App Shell, but it sounds like your use case is similar, with / instead of /shell.
{
// Define the dependencies for the server-rendered /shell URL,
// so that it's kept up to date.
dynamicUrlToDependencies: {
'/shell': [
...glob.sync(`${BUILD_DIR}/rev/js/**/*.js`),
...glob.sync(`${BUILD_DIR}/rev/styles/all*.css`),
`${SRC_DIR}/views/index.handlebars`
]
},
// Brute force server worker routing:
// Tell the service worker to use /shell for all navigations.
// E.g. A request for /guides/12345 will be fulfilled with /shell
navigateFallback: '/shell',
// Other config goes here...
}
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),
]
I try to understand the different between:
The class ChatsRequestHandler generate a template with the name chats.html
template = self.generate('chats.html', template_values)
In the application view its is named getchats:
application = webapp.WSGIApplication(
[('/', MainRequestHandler),
('/getchats', ChatsRequestHandler)],
The same occurs to me at edit_user.html v.s ('/edituser', EditUserProfileHandler)
How is it that the application knows that the getchats is connected to the chats.html aldo they have not the same name? I would expect that it should be the same name chats.html and ('/chats', ChatsRequestHandler).
The flow of your request goes something like this.
App Engine looks up your app.yaml file. It should contain an entry that says /getchats should be handled by application in somefile.py.
It then goes to this "application view" and matches it to a Webapp Route. In this case, that route is ('/getchats', ChatsRequestHandler).
Then it calls get or post on ChatRequestHandler, passing it the request and response objects.
The output of that is sent back to the user's browser.
You are free to implement ChatRequestHandler as you'd like. In this case you're doing so by reading in a template named chats.html, populating it with some values, and then outputting it.
So the application knows that getchats is connected to ChatRequestHandler. The name of chats.html is pretty arbitrary - the ChatReqeustHandler has to know it, but that is all. You could rename it.
Thanks for helping me:
The example a came up with comes from codenvy.com as a examples app.
1 App Engine looks up your app.yaml file. It should contain an entry that says /getchats should be handled by application in somefile.py.
Here is the app.yaml file of this application
application: 3kus-apps
version: 1
runtime: python
api_version: 1
handlers:
- url: /css
static_dir: css
- url: /js
static_dir: js
- url: /.*
script: devchat.py
So as you can see it contain's no entry that says /getchats should be handled by application in somefile.py.
What i found there is a util.js file witch has a function updateChat(). function updateChat() {downloadUrl(getRandomUrl("/getchats"), "GET", null, onChatsReturned);}.
However, I would like to know - under (1) how this should be handled by a somefile.py.
This works fine :
secrets = 'client_secrets-gae.json'
decorator = OAuth2DecoratorFromClientSecrets(os.path.join(os.path.dirname(__file__), secrets),
scope='https://www.googleapis.com/auth/drive')
....
webapp2.Route('/oauth2callback', handler=decorator.callback_handler() ),
But how can I lazy load the callback using webapp2. I have to refer to the decorator instance :
webapp2.Route(r'/products', handler='handlers.ProductsHandler', name='products-list', handler_method='list_products')
Update and solved
This line decorator.callback_handler() creates a request handler object.
decorator_callback_handler = decorator.callback_handler()
....
webapp2.Route('/oauth2callback', handler='my_package.my_mod.decorator_callback_handler'),
And ofcourse I use different modules for handling the decorator and the webapp2 routes to benefit from the lazy load.
This line decorator.callback_handler() returns a webapp.RequestHandler that handles the redirect back from the server during the OAuth 2.0 dance.
From : callback_handler docstring in oath2client.appengine
So the solution is :
use_api.py :
secrets = 'client_secrets-gae.json'
decorator = OAuth2DecoratorFromClientSecrets(os.path.join(os.path.dirname(__file__), secrets),
scope='https://www.googleapis.com/auth/drive')
decorator_callback_handler = decorator.callback_handler()
And lazy load this handler in main.py :
app = webapp2.WSGIApplication([
.... # other routes
webapp2.Route('/oauth2callback', handler='package.use_api.decorator_callback_handler'),
], debug=True)