You can use multiple services in Google App Engine and each service can be in its own language. This is usually done by having different url prefixes, so for example one url is:
myapp.com/js/*
myapp.com/python/*
However, I'm wondering if you can mix-and-match endpoints and just set them up with a dispatch file. Here is what I have so far to give an idea of what I'm trying to do:
default-multi/
app.yaml
dispatch.yaml
js/
js.yaml
package.json
server.js
py/
py.yaml
requirements.txt
main.py
And the files are:
js/js.yaml
runtime: nodejs14
service: js
js/package.json
{
"engines": {
"node": "14.x"
},
"dependencies": {
"express": "^4.17.1"
}
}
js/server.js
'use strict';
const express = require('express');
const app = express();
app.get('/js', (req, res) => {
res.status(200).send('Hello, world!').end();
});
app.listen(8080, () => {});
module.exports = app;
py/requirements.txt
Flask==2.1.3
py/py.yaml
runtime: python39
service: py
py/main.py
from flask import Flask, jsonify
app = Flask(__name__)
#app.route('/py')
def hello():
return jsonify(hello='world')
app.yaml
runtime: python39 # requires I add this ?
service: default
dispatch.yaml
dispatch:
- url: "*/py$"
service: py
- url: "*/js$"
service: js
And to dispatch:
$ gcloud app deploy app.yaml js/js.yaml py/py.yaml dispatch.yaml
Is there an actual way to accomplish what I'm trying to do above, or is it just not possible using GAE?
This is possible. Here is a working example I have now:
default_multi/
dispatch.yaml
dispatch:
- url: "*/js"
service: js
- url: "*/py"
service: default # 'py'
js/
js.yaml
runtime: nodejs14
service: js
package.json
{
"engines": {
"node": "14.x"
},
"dependencies": {
"express": "^4.17.1"
}
}
server.js
'use strict';
const express = require('express');
const app = express();
app.get('/js', (req, res) => {
res.status(200).send('Hello, world!').end();
});
app.listen(8080, () => {});
module.exports = app;
py/
py.yaml
# set this as 'default' yaml
runtime: python39
service: default
requirements.txt
Flask==2.1.3
main.py
from flask import Flask, jsonify
app = Flask(__name__)
#app.route('/py')
def hello():
return jsonify(hello='world')
And the command to run it:
$ gcloud app deploy py/py.yaml js/js.yaml dispatch.yaml
The main points here are that:
One server needs to be registered as the default service, even if the packages are split and equivalent in priority.
Only the dispatch.yaml goes at the top level. This acts as the service-router now.
Related
I've one Electron app in which I've used python flask a server with Angular JS for all HTML front end thing. In dev environment it's working fine as I expect. But, after creating a distributable by electron forge when I'm trying to open the .exe file it showing this Error spawn python ENOENT.
Distributable creating process by electron forge is going without any issue. But, just after getting the ".exe" file when I'm trying to open the app by clicking on ".exe" file I'm getting this error.
Error Screenshot -
My Electron app files
main.js
const { app, BrowserWindow } = require('electron');
const path = require('path');
const url = require('url');
const { spawn } = require('child_process')
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
},
});
win.loadFile('./dist/angular-flask-electron-app/index.html');
};
app.whenReady().then(() => {
const status = spawn("./flask_server/.venv/Scripts/python", ["./flask_server/main.py"])
status.stdout.on('data', (data) => {
console.log(`python process stdout: ${data}`);
});
status.stderr.on('data', (data) => {
console.error(`python process stderr: ${data}`);
});
createWindow();
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
Flask route file - main.py
import sys
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
#app.route("/")
def hello():
return "Hello World from Flask!"
if __name__ == "__main__":
app.run(host='127.0.0.1', port=5000)
Folder structure of electron app
I can guess like somehow the distributable can't able to package the python inside it. That's why, at the time of opening the file it can't able to make the connection with Python & failed to create the python environment to run the flask route file.
But don't know what to do exactly to rectify this. Need some help.
-----UPDATE-----
First I tried Electron Forge to get the distributable. But, when I start getting this error I thought maybe Electron forge is somehow not working properly. Then I tried Electron Builder to get the distributable.
I followed this article to do that - https://medium.com/jspoint/packaging-and-distributing-electron-applications-using-electron-builder-311fc55178d9
The out folder structure is like this now -
Screenshot for "dist" folder
working on a python flask app with a vue js front end. tested it my local mac book but when i try the same thing on a linux development machine, i get a ajax error. here is the set up ( directory structure below).
backend is flask app that i run with python app.py , then in the front end vue js, i have added a route and calling the backend api endpoint. not sure if there is anything different we have to do in RHEL linux.
myApp
server
app.py
requirements.txt
Client
node_modules
public
src
components
...
package.json
installed vue-cli , npm install -g #vue/cli
Vue create myapp
npm run serve
from flask import Flask
from flask_cors import CORS
# enable CORS
CORS(app, resources={r'/*': {'origins': '*'}})
app = Flask(__name__)
#app.route('/helo')
def index():
return "Hello from flask app"
if __name__ == "__main__":
app.run()
User.vue
<template>
<div>
<div class="hello">
...
</template>
<script>
import axios from "axios";
export default {
name: "Users",
data() {
return {
message: '',
},
};
},
methods: {
getUsers() {
const path = 'http://localhost:5000/hello';
axios.get(path)
.then((res) => {
this.message = msg;
})
.catch((error) => {
// eslint-disable-next-line
console.error(error);
});
}
},
created() {
this.getUsers();
}
}
</script>
I have docker-compose.yml to bring up two docker containers.
1.) front-end - reactjs - running on port 3000
2.) back-end - python (flask) - running on port 8083
The front-end is calling the python server for a POST method through the url "http://127.0.0.1:8083/api using axios, but now since these are running at two containers, how can I connect the front-end to the python server through that url?
This is my docker-compose.yml
version: "3.2"
services:
frontend:
build: ./frontend
environment:
CHOKIDAR_USEPOLLING: "true"
volumes:
- /app/node_modules
- ./frontend:/app
ports:
- 80:3000
depends_on:
- backend
backend:
build: ./backends/jananath
volumes:
- ./backends/jananath:/usr/src/app
environment:
FLASK_APP: /usr/src/app/server.py
FLASK_DEBUG: 1
FLASK_RUN_EXTRA_FILES: "/usr/src/app/banuka.txt"
ports:
- 5000:8083
And this is the server.py python server
from flask import Flask, render_template, request, url_for, redirect
import os
from os import path, walk
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
PORT = 8083
#app.route('/api', methods=['POST', 'GET'])
def upload_file():
file = request.files['file']
filename = file.filename
print(filename)
filepath = os.path.abspath(filename)
print(filepath)
response_ = {}
response_['filename'] = str(filename)
response_['filepath'] = str(filepath)
return response_
if __name__ == '__main__':
app.run(host='0.0.0.0', port=PORT, extra_files=extra_files)
And this is the axios calling a POST method from front-end to this server.py
const onFormSubmit = async (e) => {
e.preventDefault();
const formData = new FormData();
formData.append("file", file);
try {
const res = await axios.post("http://127.0.0.1:8083/api", formData, { // this url should change now?
headers: {
"Content-Type": "multipart/form-data",
"Access-Control-Allow-Credentials": "true",
"crossorigin": "true",
},
});
const {filename, filepath} = res.data;
setUploadedFile({filename, filepath});
} catch (error) {
console.log(error);
}
};
I think the problem here is the URL is now changed, but I don't know how to fix that. Can someone tell me how to fix this and what is the correct URL I should hit?
Thank you!
try backend:8083 in your react app, you will need to rebuild your react image.
I have a problem witch Angular and Flask inside Docker.
Angular linking to Flask app inside docker, but when I want to make http requests to API from Angular returns error.
Error image
My Angular service for make requests.
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders,Response } from '#angular/common/http';
import { Observable, of } from 'rxjs';
import { catchError, map, tap } from 'rxjs/operators';
import {User} from './user';
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};
#Injectable({providedIn: 'root'})
export class LoginService {
private loginUrl = "http://waiter_flask_1:5000/api/account/login";
constructor(
private http:HttpClient
) { }
loginUSer(): Observable<any> {
return this.http.post(this.loginUrl,{"username":"test","password":"test"},httpOptions).pipe(
map((response:Response)=>response)
);
}
}
My docker-compose.yml
version: '3.3'
services:
flask:
image: flask
ports:
- "5000:5000"
volumes:
- ./run.py:/app/run.py
- ./api:/app/api
links:
- database:waiter_database_1
angular:
image: angular
ports:
- "4200:4200"
volumes:
- ./docker-angular:/usr/src/app
links:
- flask:waiter_flask_1
How can I resolve this problem?
When you make the request from the Angular app, your browser is making the request, not the angular container. Therefore your host machine that you are running your browser from will try to resolve the http://waiter_flask_1:5000 host not the angular container, and since your host cannot resolve the name waiter_flask_1, the request will fail.
What you need to do is replace the url your angular app is using to make the HTTP request with a url that your host is able to resolve e.g:
http://host.ip.address:5000/api/account/login
where host.ip.address is the ip address for the host running the flask container. If, for example, you are running the flask container on the same host that you are accessing your browser, then your url can point to localhost, eg:
http://127.0.0.1:5000/api/account/login
I am using Nginx+uWSGI+Flask to build up a web service API.
I follow http://flask.pocoo.org/docs/0.10/deploying/uwsgi/ as below
In Nginx, I want Flask handle all request appapi, and others handle by nginx.
ex.
http://www.example.com/appapi/query?name=123 will be handled by flask
http://www.example.com/ will be handled by nginx.
I add below configuration to let flask handle.
location = /appapi { rewrite ^ /appapi /; }
location /appapi { try_files $uri #appapi ; }
location #appapi {
include uwsgi_params;
uwsgi_param SCRIPT_NAME /appapi;
uwsgi_modifier1 30;
uwsgi_pass 127.0.0.1:3301;
}
uWSGI has listen 3301 port, and will load flask app, In Flask app code. I have defined route for appapi
#app.route('/appapi/query', methods=['GET'])
def query():
print 'query()'
But I find query function is not called, and in log. it return 404, not found.
Thanks in advance!
You can do this:
#app.route('/query', methods=['GET'])
def query():
print 'query()'
Then in the Nginx config:
location /appapi/ {
include uwsgi_params;
uwsgi_pass 127.0.0.1:3301;
}