Hey everyone,
I will talk about some experiments I did with FastAPI and deploying on Zeit.co.
Context: For one side-project, I needed a simple way to retrieve the information from a specific Android application (eg. io.shodan.app
) on the Google Store and a download link from APKPure (if any).
I thought that this would have been a great playground to get my hands on FastAPI, a very promising framework that I never had time to play with.
Alright, so let’s go straight in the code!
In order to serve my FastAPI application, we are going to use uvicorn.
Based on the FastAPI introduction, you basically just need to install the fastapi
and uvicorn
dependencies:
pip install fastapi uvicorn
The (bootstraping) Python code is as… simple as that:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
In order to try your app, one simple command will do the work:
$ uvicorn main:app --reload
The last parameter --reload
will automatically reload the app as soon as you will perform some changes on the source code. Pretty handy especially when you’re prototyping.
Couple of minutes later, I had proof of concept ready to get deployed on zeit.co.
The final source code is :
from fastapi import FastAPI, HTTPException
import play_scraper
import datetime
from bs4 import BeautifulSoup
import requests
import optparse
import sys
app = FastAPI()
@app.get("/app/{app_id}")
def retrieve_info(app_id: str):
return {
"google_play" : google_play(app_id),
"apkpure": apkpure_get_last_version(app_id),
"app_id": app_id,
"timestamp": datetime.datetime.now(),
}
# return HTTPException(404, {"message": "app_id {} not found".format(app_id)})
def google_play(app_id: str):
try:
return play_scraper.details(app_id)
except:
return { "message": "Can't find information on Playstore for {}".format(app_id) }
def apkpure_get_last_version(app_id: str):
versions = apkpure_get_versions(app_id)
if 'message' in versions:
return versions
latest_version = versions[0]
for version in versions[1:]:
if version['update_date'] > latest_version['update_date']:
latest_version = version
return latest_version
def apkpure_get_versions(app_id: str):
url = 'https://apkpure.com/en/{}/versions'.format(app_id)
req = requests.get(url)
soup = BeautifulSoup(req.content, 'html.parser')
try:
result = []
container = soup.findAll('ul', attrs={'class': 'ver-wrap'})[0]
app_versions = container.findAll('li')
for app in app_versions:
try:
tmp_download = app.find('a', attrs={'class': 'down'})['href'].split('?')[0]
download_link = "https://apkpure.com{}".format(tmp_download)
except:
download_link = "We didn't manage to get it."
version = app.find('span', attrs={'class': 'ver-item-n'}).text
size = app.find('span', attrs={'class': 'ver-item-s'}).text
developer = app.find('p').text
update_date = app.find('p', attrs={'class': 'update-on'}).text
result.append({
'version': version,
'size': size,
'developer': developer,
'update_date': update_date,
'download_link': download_link
})
return result
except Exception as err:
return { "message": "Can't find the latest version on APKPure for {}".format(app_id) }
Make sure to create a requirements.txt
file in the root directory. I added those dependencies :
play-scraper
fastapi
uvicorn
bs4
And finally, but most importantly part for the deployment phase, I created a now.json
file in the root folder.
The content of the file is as follow:
{
"version": 2,
"public": false,
"builds": [{ "src": "main.py", "use": "@now/python" }],
"routes": [
{ "src": "/", "dest": "main.py" },
{ "src": "/app/(.*)", "dest": "main.py" }
]
}
Finally, you are ready to deploy and launch the final command!
$ now .
And.. the app is deployed. You can give it a shot at: https://android-version-checker.now.sh/app/io.shodan.app
And if you prefer to check it out with cURL:
$ curl https://android-version-checker.now.sh/app/io.shodan.app --silent | jq .