The CherryPy web server can supposedly be deployed in the Google App Engine.
Who has done it, and what was the experience like?
What special effort was required (configuration, etc.)?
Would you recommend it to others?
The article is a good example but its slightly out of date now as the patch is no longer required, the latest version of Cherrypy should run without it, I've gotten the sample below running in the development environment.
I've included cherrypy inside a zip file as the google app engine has a limit of one thousand files per application, it also makes it easier to deploy.
I'm also using the cherrypy dispatch handler to route the request.
import sys
sys.path.insert(0, 'cherrypy.zip')
import cherrypy
import wsgiref.handlers
class Root:
exposed = True
def GET(self):
return "give a basic description of the service"
d = cherrypy.dispatch.MethodDispatcher()
conf = {'/':
{
'request.dispatch': d
}
}
app = cherrypy.tree.mount(Root(), "/",conf)
wsgiref.handlers.CGIHandler().run(app)
So far I've not come across any particular issues but I have read some people have had issues with sessions.
See boodebr.org article (missing, but here on the Wayback machine) It works for me.
If you are looking for an example, look for the condition that accepts ServerMode.GAE in ServerInterface.auto in this example.
There is a good article on how to do this over here now here. I haven't actually tried this yet, I stuck with django on App Engine, but it seems to be a solid example.
Related
Firstly, I just wanted to say that this is my first web application project. I've spent the past few days trying to find answers on how to essentially put the frontend and backend together. I have a lot of questions, but the main one I want answered is on how to return my frontend 'final product' from a backend endpoint.
This is what I understand (please correct me if I'm wrong):
The frontend code is run by the client (browser).
When the client interacts with the webpage, the frontend makes API calls to the backend to retrieve/modify data, as necessary.
The backend and frontend is often developed separately, and could be hosted on separate servers.
It is, however, possible (and maybe simpler) to host it on a single domain/server. I am hoping to do this, in order to avoid a whole set of issues with CORS.
Then comes the following problem:
When I want to test out my front end and see how it's coming along, I just run npm run start. I then go to the given url (usually http://localhost:8080/) and I have access to the frontend that I've developed. And when I want to deploy it, I run npm run build, which gives me a dist folder (bundled together and minified).
If I want to run and test my backend locally, as I am using FastAPI, I simply run uvicorn main:app --reload.
How to put the two together? More specifically, in my backend code, how do I return the product of my frontend work (i.e., the dist folder?). I've tried the following (simplified):
#app.get("/", response_class=HTMLResponse)
def root():
return open("../frontend/dist/index.html", "r").read()
but, of course, this only gives me the static html without the React components.
I realize this post may be loaded with incorrect assumptions and poor practices (in which case, my apologies! and I would appreciate any corrections/suggestions.) However, if the following questions could be answered, I would greatly appreciate it. These are questions I have that will hopefully help me test my whole web application locally on my computer.
How do I return the product of my frontend work for the GET request at the domain root endpoint?
If there is a page A, page B, and page C for my web app, each with url www.example.com/A, www.example.com/B, and www.example.com/C do I have to create three separate React frontend projects? I.e., equivalent of having three dist folders? What is the standard way this is handled?
These are good questions and it is certainly possible. I will tell you what I do, with the caveat that there may be a better way...
I'm using Vue instead of React, but its build process also sends static html, js and css to a dist/ directory, so the process should be about the same.
First you can copy the dist/index.html file you mention into your FastAPI templates/ directory. You will use your FastAPI route to serve that file as a Template.
Then copy your js and css into a static/ directory and make sure FastAPI knows about both static and templates.
from fastapi import FastAPI, Request
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
templates = Jinja2Templates(directory="templates")
#app.get("/")
async def serve_spa(request: Request):
return templates.TemplateResponse("index.html", {"request": request})
You may need to set something in React in order for your build to know that the js and css will live in a dir called static. For Vue, there is the assetsDir option within vue.config.js
For your question about handling different paths, like example.com/a and example.com/b, it depends how you want to handle those requests. Are you wanting your single react app to handle all of those routes?
If that is the case, you may want to see also: How to capture arbitrary paths at one route in FastAPI?
One option is to copy the serve_spa() route above and handle your routes, like /a, /b, etc.
Or use a catch-all route:
#app.route("/{full_path:path}")
async def catch_all(request: Request, full_path: str):
print("full_path: "+full_path)
return templates.TemplateResponse("index.html", {"request": request})
The "traditional" approach to running a web application is to have a server that serves your web application (i.e. your React app). Usually you'll hear about nginx being used as the web server being used for modern day single page applications. When you run npm run start you start up a local server on your machine and it makes your app available at http://localhost:8080 (the port and hostname are of course configurable).
When it comes to your API, it should be it's own server available at a different endpoint/url, and then your web app will make API calls to that endpoint/url in order to fetch data.
The way you're describing things, it sounds like you're trying to use FastAPI to server render your web app, but I'm not sure how feasible that is, especially considering there is an entire framework solely dedicated to server rendering react applications.
I've also struggled with this and here's an approach that worked for me
import logging
from fastapi import FastAPI
from starlette.responses import RedirectResponse
from starlette.staticfiles import StaticFiles
app = FastAPI()
#app.get("/")
async def index():
return RedirectResponse(url="/index.html")
app.mount("/", StaticFiles(directory="backend/ui/"), name="ui")
Note: Please observe that app.mount is called after registering the / route. From my experience if the mount is called before the registration then it will simply not redirect to index.html
Note: I use react-scripts to generate the app.
Dear hainabaraka
Your question resembles this one: How do I serve a React-built front-end on a FastAPI backend?. In that one, I contributed an answer, but I'd like to also refer you to Mike Chaliy's answer, which updates mine.
In any case, here are two thoughts on that solution (that I should really update) and the answers you get here:
the nginx approach: this removes responsibility from your code, meaning that it also removes control from you. DevOps love this kind of "you do your thing and let me worry about that" approach, but let's just say that this is a good solution... not for your case. You want to serve from your API.
By the way, "it should be it's own server" has no apostrophe!
the Jinja2 approach: I'm not sure this would work, and even if it did, it would be introdsucing a lot of CPU waste. Jinja2 is an excellent tool for Python based backend tremplate rendering. I used it extensively to generate HTML medical reports to be then PDF-rendered but in this case it always sounds like a "Yes, it works, but...". Rule of thumb for "but"-sentences: everything to the left of the "but" is irrelevant.
the FastAPI RTFM approach: I am a HUGE fan of FastAPI and I'm (extremely slowly) trasnslating its documentation to European Portuguese, but the examples there are very very limited. Referring you to the FastAPI docs is assuming you're an idiot that never thought of that.
other approaches: I saw a bungh of these that, while well intentioned, did not really work because they were either produced by that kinf of people here in SO that don't really test their answer before answering, or by pure back-end devs that have no clue how a React (or a SPA) app works. Some can even serve a home page but then routing kills it.
The solution I present works and has been working for me for years now, both with Vue and React SPAs. The caveat is that you either serve your app from a special endpoint (I suggest /my-spa, which is quite lame), or, if you want the app to come from /, you have to do the
app.mount('/', SPAStaticFiles(directory='folder', html=True), name='whatever')
after all other endpoints, and you cannot obviously have other endpoints conflicting with either / or any React route within it. This perhaps adds to why APIs are recommended to hang from an /api endpoints, and possibly versioned, like /api/v1/.... Please let me know if this works for you.
For that, there an excellent resource in Zalando RESTful API and Event Guidelines.
I want to produce a Google Apps document based on a (Google doc) template stored on the users Google Drive and some XML data held by a servlet running on Google App Engine.
Preferably I want to run as much as possible on the GAE. Is it possible to run Apps Service APIs on GAE or download/manipulate Google doc on GAE? I have not been able to find anything suitable
One alternative is obviously to implement the merge functionality using an Apps Script transferring the XML as parameters and initiate the script through http from GAE, but it just seem somewhat awkward in comparison.
EDIT:
Specifically I am looking for the replaceText script functionality, as shown in the Apps script snippet below, to be implemented in GAE. Remaining code is supported through Drive/Mail API, I guess..
// Get document template, copy it as a new temp doc, and save the Doc’s id
var copyId = DocsList.getFileById(providedTemplateId)
.makeCopy('My-title')
.getId();
var copyDoc = DocumentApp.openById(copyId);
var copyBody = copyDoc.getActiveSection();
// Replace place holder keys,
copyBody.replaceText("CustomerAddressee", fullName);
var todaysDate = Utilities.formatDate(new Date(), "GMT+2", "dd/MM-yyyy");
copyBody.replaceText("DateToday", todaysDate);
// Save and close the temporary document
copyDoc.saveAndClose();
// Convert temporary document to PDF by using the getAs blob conversion
var pdf = DocsList.getFileById(copyId).getAs("application/pdf");
// Attach PDF and send the email
MailApp.sendEmail({
to: email_address,
subject: "Proposal",
htmlBody: "Hi,<br><br>Here is my file :)<br>Enjoy!<br><br>Regards Tony",
attachments: pdf});
As you already found out, apps script is currently the only one that can access an api to modify google docs. All other ways cannot do it unless you export to another format (like pdf or .doc) then use libraries that can modify those, then reupload the new file asking to convert to a google doc native format, which in some cases would loose some format/comments/named ranges and other google doc features. So like you said, if you must use the google docs api you must call apps script (as a content service). Also note that the sample apps script code you show is old and uses the deptecated docsList so you need to port it to the Drive api.
Apps script pretty much piggy backs on top of the standard published Google APIs. Increasingly the behaviours are becoming more familiar.
Obviously apps script is js based and gae not. All the APIs apart from those related to script running are available in the standard gae client runtimes.
No code to check here so I'm afraid generic answer is all I have.
I see now it can be solved by using the Google Drive API to export (download) the Google Apps Doc file as PDF (or other formats) to GAE, and do simple replace-text editing using e.g. the iText library
Ok, i found this link https://code.google.com/p/gwt-platform/wiki/CrawlerSupport#Using_gwtp-crawler-service that explain how you can make your GWTP app crawlable.
I got some GWTP experience, but i know nothing about AppEngine.
Google said its "crawlservice.appspot.com" can parse any Ajax page. Now I have a page "http://mydomain.com#!article" that has an artice that was pulled from Database. Say that page has the text "this is my article". Now I open this link:
crawlservice.appspot.com/?key=123456&url=http://mydomain.com#!article, then i can see all javascript but I couldn't find the text "this is my article".
Why?
Now let check with a real life example
open this link https://groups.google.com/forum/#!topic/google-web-toolkit/Syi04ArKl4k & you will see the text "If i open that url in IE"
Now you open http://crawlservice.appspot.com/?key=123456&url=https://groups.google.com/forum/#!topic/google-web-toolkit/Syi04ArKl4k you can see all javascript but there is no text "If i open that url in IE",
Why is it?
SO if i use http://crawlservice.appspot.com/?key=123456&url=mydomain#!article then Can google crawler be able to see the text in mydomain#!article?
also why the key=123456, it means everyone can use this service? do we have our own key? does google limit the number of calls to their service?
Could you explain all these things?
Extra Info:
Christopher suggested me to use this example
https://github.com/ArcBees/GWTP-Samples/tree/master/gwtp-samples/gwtp-sample-crawler-service
However, I ran into other problem. My app is a pure GWTP, it doesn't have appengine-web.xml in WEB-INF. I have no idea what is appengine or GAE mean or what is Maven.
DO i need to register AppEngine?
My Appp may have a lot of traffic. Also I am using Godaddy VPS. I don't want to register App Engine since I have to pay for Google for extra traffic.
Everything in my GWTP App is ok right now except Crawler Function.
So if I don't use Google App Engine, then how can i build Crawler Function for GWTP?
I tried to use HTMLUnit for my app, but HTMLUnit doesn't work for GWTP (See details in here Why HTMLUnit always shows the HostPage no matter what url I type in (Crawlable GWT APP)? )
I believe you are not allowed to crawl Google Groups. Probably they are actively trying to prevent this, so you do not see the expected content.
There's a couple points I wish to elaborate on:
The Google Code documentation is no longer maintained. You should look on Github instead: https://github.com/ArcBees/GWTP/wiki/Crawler-Support
You shouldn't use http://crawlservice.appspot.com. This isn't a Google service, it's out of date and we may decide to delete it down the road. This only serves as a public example. You should create your own application on App Engine (https://appengine.google.com/)
There is a sample here (https://github.com/ArcBees/GWTP-Samples/tree/master/gwtp-samples/gwtp-sample-crawler-service) using GWTP's Crawler Service. You can basically copy-paste it. Just make sure you update the <application> tag in appengine-web.xml to the name of your application and use your own service key in CrawlerModule.
Finally, if your client uses GWTP and you followed the documentation, it will work. If you want to try it manually, you must encode the Query Parameters.
For example http://crawlservice.appspot.com/?key=123456&url=http://www.arcbees.com#!service will not work because the hash (everything including and after #) is not sent to the server.
On the other hand http://crawlservice.appspot.com/?key=123456&url=http%3A%2F%2Fwww.arcbees.com%2F%23!service will work.
Can anybody show a working example of how to get pretty urls on a GWT project over AppEngine.
I know that you will suggest to look at UrlRewriteFilter. I have been burning it for 3 days and get no succedd.
Please, could help?
Maybe what you're looking for: Pretty URLs in Google App Engine
This will work, and it's really easy:
def main():
application = webapp.WSGIApplication([('/', MainHandler), ('/(.*)', PostHandler)], debug=True)
class PostHandler(webapp.RequestHandler):
def get(self, slug):
As explained in the article on Pretty Urls with Google App Engine
I followed that link till urlrewrite filter, wich is what i am using at the moment.
I get to transform domain/?user=43434&mensage=89898 to domain/user43434-mensage89898 which is quite good for me.
But i can not transform it to domain/43434/8989.
When i try to do this i always get a fail consisting on my services cannot find an *.wgt.rpc file.
In other words, I am not able to run the next example when i use GWT:
http://zenoconsulting.wikidot.com/blog:16
You can do it on the client side with the History class if you're willing to have a # at the beginning of your URLs. In my app teachers can access their grades at http://activegrade.com/#calculus/grades, for example. The History object receives "calculus/grades" and you can parse it from there.
GWT 2.1 introduces the concept of Places - you could look into that as well.
Now I use my own Java FTP program to ftp objects from my PC to my ISP's website server.
I want to use Google App Engine's servlet to get Paypal IPN messages, then store the messages into my own objects and ftp the objects to my ISP's website server, is this doable ? I heard Google App Engine doesn't support FTP.
I don't expect Google to do it for me, but can I use my own Java FTP program in the web app that I upload onto the App Engine to do it ?
Frank
No, you can't open any socket connection except by using URL Fetch
service on HTTP/HTTPS to these port ranges:
80-90, 440-450, 1024-65535.
As of April 9 this year (SDK 1.7.7) this isn't a problem any longer. Outbound sockets (e.g. FTP) are generally available to all billing-enabled apps.
Socket API Overview (Java): https://developers.google.com/appengine/docs/java/sockets/
UPDATE: Our code below may no longer work. This FTP code worked for us before but we see a comment now below that says FTP is no longer supported on App Engine. See the link below. If you try this code and it works or doesn't work for you for straight FTP (TLS is NOT supported BTW) - please comment.
Yes. FTP now works on Google App Engine. (The accepted answer is outdated and no longer true.)
Here is tested and working code on GAE.
#!/usr/bin/env python
from google.appengine.ext import webapp
from ftplib import FTP
class HwHandler(webapp.RequestHandler):
def get(self):
self.response.out.write('FTP Starting...<br>')
ftp = FTP('ftp_site.com')
ftp.login('login', 'password')
ftp.retrlines('LIST') # list directory contents
self.response.out.write('FTP opened')
ftp.quit()
app = webapp.WSGIApplication([
('/', HwHandler)
], debug=True)
Of note, FTP TLS does not appear to work currently. (Trying to do "from ftplib import FTP_TLS" fails.)
You can use the Apache Commons FTP client (org.apache.commons.net.ftp.FTPClient) if you put it into passive mode. Just do the following:
FTPClient client = new FTPClient();
client.connect(FTP_HOST);
client.enterLocalPassiveMode();
Then it won't call ServerSocketFactory, and life should be good!