AppEngine dispatch.yaml for SPA and client-side routing - google-app-engine

I have a Go server where I have an API and a static client build folder with a SPA (Single Page Application). Since the SPA should have client-side routing, I must make sure that all paths map to the frontend. For example, http://myapp.com/djaksfjal should not show a 404 in the browser, it should always route to the routes in my SPA.
Now I also want to have a backend API, so all requests to /api should go to the Go backend.
Question: how do I set this up with AppEngine? I tried with two app.yaml files and one dispatch.yaml file but can't get it to work.
client-app.yaml
runtime: go
api_version: go1
service: default
handlers:
- url: /
static_files: build/index.html
upload: build/index.html
- url: /*
static_dir: build
server-app.yaml
runtime: go
api_version: go1
service: test-backend
handlers:
- url: /api/*
script: _go_app
dispatch.yaml
dispatch:
- url: "*/api/*"
service: test-backend
hello.go
package main
import (
"fmt"
"net/http"
"google.golang.org/appengine"
)
func main() {
http.HandleFunc("/api/hello", handle)
appengine.Main()
}
func handle(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, world!")
}
Then running dev_appserver.py server-app.yaml client-app.yaml dispatch.yaml and going to localhost:8080 where the dispatch server is. However, this doesn't work. The client-side routing takes over everything, ignoring the /api/hello route.
Tested: localhost:8080/api/hello. Expecting: api route reply. Got: static client reply
If I change the client-app.yaml to not use a * then the /api/hello route works, but of course the client-side routing does not work because I need all routes to go to the client so that it can handle the routing itself (except for the /api routes).

The rules order in the dispatch.yaml file matters - the first pattern match wins. So you want the */api one first.
Also - if none of the rules pattern matches the request will be routers to the default service, no need to add a rule for that.
I also see that you mentioned an /api/hello request path - for that to work you may need to expand the */api pattern into */api/*
So I'd use this dispatch.yaml file:
dispatch:
- url: "*/api/*"
service: test-backend
You also need to expand the /api pattern in the server-app.yaml file, otherwise /api/hello will give a 404:
handlers:
- url: /api/*
script: _go_app
Side note: you shouldn't (need to) go to localhost:8080 - that'll just send you to the default service. Instead note the individual ports that the development server listens to for each module/service, displayed when the server starts.

Related

URL Map is not working with backend service on Load Balancer Google Cloud

I am setting up URL Maps on our Backend Services with Load Balancer. The issue is that my URL Maps are not working for some reason. When I tried to browse domain.com/path, it shows
The requested URL /bpd was not found on this server.
I do believe I did the correct way, but seems that its still not working.
Please see screenshot below:
[![image][1]][1]
/* - working
/path1 and /path2 - not working, shows error - was not found on this server
app.yaml file:
runtime: python27
api_version: 1
threadsafe: true
service:
handlers:
- url: /
static_files:
upload:
secure: always
redirect_http_response_code: 301
- url: /(.*)
static_files: www/\1
upload: www/(.*)
I also set-up Serverless network endpoint group and connected with Google App Engine for the Backend Services.
Thank you all for your help.
Thanks to your comment, I though I found the mistake. In fact, when you define a URL map in a load balancer, the query path in entry of the load balancer is, by default, forwarded as-is to the backend.
Let's take your case
you have this URL map: <URL>/address/*. Your URL path is /address/*
The backend is <myAddressAppEngine.appspot.com>. It received the request on this path <myAddressAppEngine.appspot.com>/address/*
And it doesn't work because in reality you expect <myAddressAppEngine.appspot.com>/*.
To solve that, you can use advanced mode in the URL map
Start by setting the default backends for any URL and any path
Then add a new path rule and configure it like this, with a path rewrite to /

Angular frontend with django rest backend on google cloud app engine error 502 Bad Gateway

I have deployed my angular front end with Django Rest Framework backend on Google App Engine. When I make a request to the backend from the frontend I get an error 502 Bad Gateway any help on identifying the problem will be really appreciated. I have tried several online recommendations are not working for me.
This is my front end app.yaml
runtime: nodejs12
handlers:
- url: /
static_files: smis/index.html
upload: smis/index.html
secure: always
- url: /
static_dir: smis
secure: always
This is my backend app.yaml file
runtime: python38
service: backend
handlers:
- url: /static
static_dir: /static/
secure: always
- url: /.*
script: auto
secure: always
This is my dispatch.yaml file
#routing rules
dispatch:
#api
- url: "*/api/*"
service: backend
The leading wildcard in your url routing is invalid. Try this:
#routing rules
dispatch:
#api
- url: "/api/*"
service: backend
Then, any url that begins with /api/... will go to the python backend
I found out I had not set main.py file. App engine handles request in the main.py file which should be in the root directory. The contents of main.py file can be derived from wsgi.py file. This is the content I place in the main.py file and it worked for me:
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'smis.settings')
application = get_wsgi_application()
app = application
```

Mapping a custom domain route to an application in App Engine

I have a custom domain with a route that I'd like to map to my React application (create-react-app production build being served on App engine). When I map the custom domain, none of my static files are found however. I've tried updating the handlers for the app but I'm getting the same error (404 on loading css, js, manifest). My dispatch.yaml is
dispatch:
- url: "example.service.org/test"
service: my-service
Accessing example.service.org/test correctly populates the page title but none of the assets load. How do I update my handlers to serve the files correctly?
If this is working in your appspot.com domain means that your static routes works fine.
I think that the issue is caused because your service doesn't know how to address this path
/test/static
I think that are multiple solutions to this issue:
1.- Map the domain with the service without /test
dispatch:
- url: "example.service.org"
service: my-service
with this workaround if you need a test url you can add an test subdomain in order to have 2 services one in prod and another in dev/test for example
dispatch:
- url: "example.service.org"
service: my-service
- url: "test.example.service.org"
service: test-my-service
2.- define in your app.yaml this handlers
handlers:
- url: /static
static_dir: static/
- url: /test/static
static_dir: static/

Google App Engine routing with dispatch.yaml

I try to deploy a web app on my sandbox GCP project where there is already an app deployed. So I'm trying to play with the path to have the two web apps deployed at the same time.
My dispatch looks like this
dispatch:
- url: "*/wc/api/.*"
service: wc-api
- url: "*/wc/.*"
service: wc-front
- url: "*/.*"
service: default
When I do so, all my calls to mysandbox.appspot.com/wc/ gets redirected to my default service and I don't understand why (I can see the calls in the logs of the default service).
If this helps, here is the app.yaml of my wc-front service.
runtime: python27
api_version: 1
threadsafe: yes
service: wc-front
default_expiration: "10m"
handlers:
- url: /wc/.*
script: app.APP
login: required
secure: always
Do you see any error in this ?
(Calling directly wc-front-dot-mysandbox.appspot.com/wc/ returns the typical App Engine 404 error)
Thanks
It appears the problem was coming from the .* notation. This should only be used for the very general */.* rule.
My new - working - dispatch
dispatch:
- url: "*/wc/api/*"
service: wc-api
- url: "*/wc/*"
service: wc-front
- url: "*/.*"
service: default
Yes, indeed, you need to configure your dispatch.yaml file, for App Engine to route your application based on the URL that you set there. It seems that your service: default it's getting all URLs and redirecting them to the service set there.
Considering that, I would recommend you to take a look at the official documentation about configuring the dispatch.yaml file - you can get some better ideas on how to configure it - and this other post from the Community, where another user has a similar use case as yours, that I believe should help you.
dispatch.yaml Configuration File
How to use GAE's dispatch.yaml with multiple development environments?
Let me know if the information helped you!

Mapping subdomain to a service in Google App Engine project

I have a Google App Engine project with following yaml file
handlers:
- url: /web/.*
script: web_server.app
- url: /api/.*
script: rest_server.app
How do I make sure subdomain, of a domain I own, be served by rest_server.app script.
Example: If I own example.com
I want example.com to be served by web_server.app, and api.example.com to be served by rest_server.app
Is it possible to do that using Google App Engine.
Example:
handlers:
- url: example.com/.*
script: web_server.app
- url: api.example.com/.*
script: rest_server.app
Request routing in the app.yaml can not be used to route based on the URL's domain name, see the url table row in the Handlers element doc section.
Because of that you can't really have a single module/service serving your app while simultaneously stripping the filepath portion of the URL you're currently used in your handlers' url configs for routing requests to one script or the other.
You can obtain what you desire by splitting your app into 2 separate services/modules, each handling one script. One of the modules has to be the default module, I'd make the web one the default.
A dispatch.yaml file would be used to route requests to their respective modules based on the URL hostname.
The web.yaml file would contain:
module: default
handlers:
- url: /.*
script: web_server.app
The rest.yaml file would contain:
module: rest
handlers:
- url: /.*
script: rest_server.app
In the dispatch.yaml file you only need routes for the non-default module(s), requests matching no routes are by default routed to the defaut module:
- url: "api.example.com/*"
module: rest
You can find a more complete example here: https://stackoverflow.com/a/34111170/4495081
You'd then map both your example.com naked domain and api.example.com subdomain to your app. Follow the Adding a custom domain for your application procedure, paying extra attention to the sections which are slightly different when configuring a naked domain vs a subdomain. See also https://stackoverflow.com/a/36317462/4495081
There is one problem, tho - dispatch.yaml routing based on hostnames doesn't work with the local development server, the requests destined for the rest module would actually go to the default module.
A simpler workaround would be to direct the rest module clients to the actual localhost:PORT URL where the local devserver's rest module listens (displayed in the terminal at dev server startup), instead.
This might not be possible in all cases or for all apps. For example it's an issue if the app makes cross-module requests with auto-generated URLs.
In such cases, to work around it you can temporarily insert a small path portion in the rest.yaml URL, only during testing on the local dev server the rest module (you'd need matching changes on the client side and/or the cross-module URL generation logic):
module: rest
handlers:
- url: /api/.*
script: rest_server.app
And then you can add a dispatch.yaml rule that is not host-based and would also with the local dev server. This can be left in there permanently, it doesn't hurt if/when deployed in production when the temporary rest.yaml change is reversed:
- url: "api.example.com/*"
module: rest
- url: "*/api/*"
module: rest

Resources