Mixing static and dynamic endpoints in app.yaml file - google-app-engine

I'm trying to describe endpoints in my App Engine app and am having difficulty for directory structures that mix static and dynamic content. But my yaml rules are conflicting with one another. Before I change my directory structure, does anyone have a recommendation?
The goal is to create a directory that contains both documentation (static html files) and implementations.
/api
- /v1
- getitdone.py
- doc.html
- index.html
What I think I should be doing with my application yaml...
- url: /api/v1/getitdone
script: api/v1/getitdone.py
- url: /api/
static_files: api/index.html
upload: api/index.html
- url: /api
static_dir: api
But this causes the dynamic endpoints to fail. I'm assuming the static_dir reference is breaking it. How can I do this without describing every script and static file reference (I have many more than are listed here)?

The cause of this is that you're marking /api/ as a static directory, so your scripts are getting uploaded as static files, which makes them inaccessible to the App Engine runtime.
The easiest solution would be to put your dynamic code and your static resources in different parts of your app's directory heirarchy, and use app.yaml to map them into the desired URL structure.

Related

React app giving 404 error when deployed to GCP

I have deployed my react app to GCP's App engine. It successfully deploys and the landing page is accessible. However none of the routes work. All the routes are giving '404' error.
I am pretty sure its the app.yaml configuration that has issue. Help please!
app.yaml
runtime: nodejs10
handlers:
- url: /
static_files: build/index.html
upload: build/index.html
- url: /
static_dir: build
The issue is that you are using both static_files and static_dir to your / url.
You need to either use static_files or static_dir.
From the description of your question it looks like you want to use static_dir to match everything that is inside the directory after the url: /.
As stated in the documentation:
static_dir: The path to the directory containing the static files, from the application root directory. Everything after the end of the matched url pattern is appended to static_dir to form the full path to the requested file.
static_files: A static file pattern handler associates a URL pattern with paths to static files uploaded with the application. The URL pattern regular expression can define regular expression groupings to be used in the construction of the file path. You can use this instead of static_dir to map to specific files in a directory structure without mapping the entire directory.

Defining a static directory into app.yaml make app crash

I have a weird issue on GAE standard (running node), more precisely with my app.yaml below.
runtime: nodejs8
# Environment variables
env_variables:
GOOGLE_CLOUD_PROJECT: '...'
# Static directories and files
handlers:
- url: /static
static_dir: public
Without the handlers part, everything works like a charm: my app is deployed and works. Note that the size is 4.8 MB (version 1-0-43).
However, with the handlers part, my app doesn't work anymore: 4xx error and an app size of 324 KB (version 1-0-43).
The sole purpose of the handlers part is to define a directory to serve static assets (CSS, JS, images...).
Any clue? Thanks.
When you add your static_dir handler definition the entire content of your public subdirectory is no longer (by default) uploaded together with your app code (most likely explaining the app size difference). Instead it's uploaded to a different location to be served directly by the GAE infra, see How to serve static files in AppEngine Standard and nodejs
It sounds that your app may need some of those files as well. In such case the easiest solution would be to add the application_readable flag to the static definition, causing that directory to be uploaded both in the static content location and together with your app code, see GAE: file_get_contents() and static files.
To speedup your deployments could also try to separate the static content in 2: one portion not needed by your app code, deployed without application_readable (thus not also uploaded with your app code, deployed faster) and one with the flag. If it's not too much trouble.
Could you try changing static_dir from 'public' to 'static'. Because the url and static_dir are usually located at the same place. Please try it and let me know. Cheers!
# Static directories and files
handlers:
- url: /static
static_dir: static

Google App Engine URL Routing with App.Yaml for Static resource and Script

I am busy migrating a app into the GAE. I used to utilize timthumb.php to resize images on demand from within a static img folder. From the same folder I used to serve static images aswel.
eg: example.com/img/image_name.jpg
example.com/img/timbthumb.php?src=example.com/img/image_name.jpg&w=50&h=50
etc.
I am not using timbthump.php anymore, I have re-written it to serve images via CloudStorageTools.php api, and I do not want to go through all code to rewrite the image paths.
Now, on my local environment the google app engine is serving both versions of images, static and dynamic via timbthumb.php.
On the live environment GAE only serves static or dynamic, I cannot build URL handlers to serve both.
The timbthumb.php images are throwing a 404 error with both handlers.
My app.yaml
application: my-app
version: 1
runtime: php55
api_version: 1
threadsafe: yes
handlers:
- url: /favicon\.ico
static_files: favicon.ico
upload: favicon\.ico
- url: /css
static_dir: dir/css
#timbthumb.php images
- url: /img/(.+\.php)$
script: dir/img/timbthumb.php
#static images
- url: /img
static_dir: dir/img
#all other php files
- url: /.*
script: dir/index.php
My Question, how can I make GAE route static images via example.com/img/ and the timthumb.php script located at example.com/img/timbthumb.php in my app.yaml?
Thanks
According to the documentation you can't serve a script from a static directory:
A static directory handler makes it easy to serve the entire contents
of a directory as static files. Each file is served using the MIME
type that corresponds with its filename extension unless overridden by
the directory's mime_type setting. All of the files in the given
directory are uploaded as static files, and none of them can be run
as scripts.
The fact that it appears to be running in the development server is just another reflection of the fact that the development server is just an approximation of GAE, but not really GAE.
If your image paths naming allows it you could use static_files routing rules instead of a static_dir one:
A static file pattern handler associates a URL pattern with paths to
static files uploaded with the application. The URL pattern regular
expression can define regular expression groupings to be used in the
construction of the file path. You can use this instead of
static_dir to map to specific files in a directory structure without
mapping the entire directory.

Google App Engine - default MIME type

Long story short:
I'm building a static web application which seems to work fine locally when served with the Node http-server, but when deployed to Google App Engine, has issues. I've traced the problem to the content-type header: when serving locally, some of my files (from an Emscripten library) are served with application/octet-stream; charset=utf-8 which works. When served from App Engine, they're served with simply application/octet-stream, which does not work. I've been able to verify this by adding a mime_type: application/octet-stream; charset=utf-8 line to one of my app.yaml handlers, but there are dozens or hundreds of files intermingled with different MIME types. I don't want to mark them all as octet-stream if I don't have to.
So is there a way in app.yaml to simply specify a default mimetype besides application/octet-stream? If not, I'll have to get much more creative with my handler matchers.
You can't set a default global mime type, but you can (as you mention) get creative. This is a good example of an app.yaml file for a static website, it's not unusual to define cases for each different file type, in order to have fine control over placement/mime.
In your case, you might wish to extend on the following idea:
- url: /(.*\.(svg|svgz))
mime_type: images/svg+xml
static_files: static/\1
upload: static/(.*\.(svg|svgz))
Using this pattern you can match multiple file types with the same mime type. Might be the quickest (& dirtiest?) path to solve your problem.
Here's another app.yaml example for further reference.

GAE: How to upload files to be accessed by the application?

Update: I found the problem. My static rule for HTML files still matched the templates even though they were in a subdirectory. After changing the rule to not match them anymore, the files could be accessed by the application.
I'm creating a Google AppEngine application. I'm using the Go language but I'm not sure that's relevant. I want to use a template with a separate template file. So the application must read the template file. Locally this works but after uploading the app to GAE, I get "no such file or directory" when calling template.ParseFiles().
So I'm thinking that somehow I must indicate that the template files are application files so that they get uploaded in the right way. I thought maybe my template files were uploaded as static files because of this in my app.yaml
- url: /(.*\.html)
static_files: \1
upload: .*\.html
So I moved them to their own directory. But that didn't make a difference. I tried adding an upload directive for my script rule in app.yaml like this:
- url: /.*
script: _go_app
upload: templates/.*
But that didn't seem to be allowed. So can anyone tell me how do I access the template files (or any data files) from my GAE application?
Thanks!
All files in your project directory are automatically uploaded.
If your app needs to access them (this is your case as you are working with templates) you can't mark them as static. This is why the first solution fails.
The second attempt, does not work either as upload is not a member of an url description.
In your case, just deploy your app and the files will be automatically uploaded and available to your app (you may need to get the basepath of your project to construct the full path to the template).
The files are automatically uploaded, assuming they're not in a static_dir or static_files directory. See the Skipping Files section in the App Engine documentation. App Engine treats such directories and files as static resources, and static resources are served separately from the application.
Static resources are not normally accessible from application code. If you must put your templates in the same directory as your other static resources, you can use the application_readable setting to make such resources accessible to your app as well.
But as you note, you can put your templates in a place within your app that isn't mapped to a static resource path; that's probably the right thing to do.
Check the different options for the app.yaml at [1]. You can check the static_dir and static_files options. I’m sharing a sample that is able to download static files. These files are in the static folder adn test folder. I share my app.yaml:
runtime: python27
api_version: 1
threadsafe: yes
handlers:
- url: .*
script: main.app
- url: /test
static_dir: test
application_readable: true
- url: /(.*\.(gif|png|jpg))$
static_files: static/\1
upload: static/.*\.(gif|png|jpg)$
application_readable: true
And the main.py:
…
import webapp2
...
class Download(webapp2.RequestHandler):
def get(self):
imageName = self.request.get('img-name')
self.response.headers['Content-Disposition'] = str('attachment; filename=' + imageName)
f = None
try:
f = open('static/' + imageName, 'r')
self.response.out.write(f.read())
except:
self.response.out.write('Jon Wayne')
class Test(webapp2.RequestHandler):
def get(self):
imageName = self.request.get('tst-name')
self.response.headers['Content-Disposition'] = str('attachment; filename=' + imageName)
f = None
try:
f = open('test/' + imageName, 'r')
self.response.out.write(f.read())
except:
self.response.out.write('Jon Test')
app = webapp2.WSGIApplication([
('/download', Download),
('/tst', Test)
], debug=True)
I have two images: fib2.png and fib1.jpeg
Then in the Test folder I have two files fib2.tst and fib1.tst.
Web is the domain name.
https://web.com/download?img-name=fib2.png
https://web.com/download?img-name=fib1.jpeg
https://web.com/tst?tst-name=fib2.tst
https://web.com/tst?tst-name=fib1.tst
Hope this helps!
[1] https://cloud.google.com/appengine/docs/standard/go/config/appref#handlers_element

Resources