Dolium
Dolium

Reputation: 23

404 error when deploying a flask app in Vercel

I'm encountering issues when trying to use my Flask app deployed in Vercel. It is a small program that returns a badge containing the number of stars a GitHub repo has.

main.py (located in "dynamicBadges")

import requests
from flask import Flask, Response

app = Flask(__name__, template_folder='dynamicBadges/templateFiles', static_folder='dynamicBadges/staticFiles')

# VARIANT 1 ----------------------------------------------------------------
variant_1 = ['#B02E26', '#974800', '#8E7500', '3F6900', '#4B6700', '#00696A', '#4B53B9', '#006493', '#8A33B8', '#9E2A99', '#99405E', '#1B1B1B']
on_variant_1 = '#FFF'

# VARIANT 2 ----------------------------------------------------------------
variant_2 = ['#FFB4AA', '#FFB689', '#E9C327', '#92DA35', '#AFD364', '#4CDADB', '#BEC2FF', '#8DCDFF', '#E8B3FF', '#FFABF1', '#FFB1C5', '#C6C6C6']
on_variant_2 = ['#690004', '#512400', '#3B2F00', '#1F3700', '#253600', '#003737', '#181F89', '#00344F', '#500075', '#5C005A', '#5E1130', '#303030']

# VARIANT 3 ----------------------------------------------------------------
variant_3 = ['#FFDAD5', '#FFDBC7', '#FFE177', '#ACF850', '#CAF07D', '#6FF6F7', '#E0E0FF', '#CAE6FF', '#F6D9FF', '#FFD7F4', '#FFD9E1', '#E2E2E2']
on_variant_3 = ['#410001', '#311300', '#231B00', '#102000', '#141F00', '#002020', '#00036B', '#001E30', '#310049', '#380037', '#3F001B', '#1B1B1B']

@app.route('/badge/stars/<style>/<variant>/<username>/<repo>')
def github_stars_badge(style, variant, username, repo):
    url = f'https://api.github.com/repos/{username}/{repo}'
    headers = {'Accept': 'application/vnd.github.v3+json'}
    r = requests.get(url, headers=headers)
    if r.ok:
        index = int(style) - 1

        if variant == '1':
            background = variant_1[index]
            foreground = on_variant_1
        if variant == '2':
            background = variant_2[index]
            foreground = on_variant_2[index]
        if variant == '3':
            background = variant_3[index]
            foreground = on_variant_3[index]

        data = r.json()
        stars = data['stargazers_count']

        if len(str(stars)) == 1:
            width = 20 + 68
        elif len(str(stars)) == 2:
            width = 2 * 16 + 68
        elif len(str(stars)) == 3:
            width = 3 * 14 + 68
        elif len(str(stars)) == 4:
            width = 4 * 13 + 68
        else:
            width = len(str(stars)) * 13 + 68
        
        svg = f'<svg xmlns="http://www.w3.org/2000/svg" width="{width}" height="30" fill="{background}" rx="15"><path d="M40 0h4v20h-4z" fill="#4c1"/><rect rx="15" width="{width}" height="30" fill="{background}"/><text x="11" y="22" fill="{foreground}" font-size="20" font-family="Product Sans">Stars : {stars}</text></svg>'
        return Response(svg, mimetype='image/svg+xml')
    else:
        return 'Error', r.status_code

vercel.json (located in the project root)

{
    "version": 2,
    "builds": [
    {
        "src": "dynamicBadges",
        "use": "@vercel/python",
        "config": {
        "maxLambdaSize": "15mb"
        }
    }
    ],
    "routes": [
    {
        "src": "/badge/stars/(.*)/(.*)/(.*)/(.*)",
        "dest": "dynamicBadges/main.py"
    }
    ]
}

requirements.txt (idem)

Flask==2.3.2

Error

error

What I should get

Something like this : expecting

(but in this case with the number of stars the VsCode repo on GitHub has)

Thanks.

Upvotes: 2

Views: 704

Answers (2)

arshovon
arshovon

Reputation: 13661

Use Github Api in Flask App and Deploy in Vercel

As you are using requests package, this should be added to requirements.txt. Also the vercel.json should have correct source and destination paths of the routes.

Directory structure:

.
├── api
│   └── index.py
├── README.md
├── requirements.txt
└── vercel.json

Updated requirements.txt:

blinker==1.6.2
certifi==2023.5.7
charset-normalizer==3.1.0
click==8.1.3
Flask==2.3.2
idna==3.4
itsdangerous==2.1.2
Jinja2==3.1.2
MarkupSafe==2.1.3
requests==2.31.0
urllib3==2.0.3
Werkzeug==2.3.6

Updated vercel.json:

{
  "rewrites": [
    { "source": "/(.*)", "destination": "/api/index" }
  ]
}

/api/index.py:

import requests
from flask import Flask, Response

app = Flask(__name__, template_folder='dynamicBadges/templateFiles', static_folder='dynamicBadges/staticFiles')

# VARIANT 1 ----------------------------------------------------------------
variant_1 = ['#B02E26', '#974800', '#8E7500', '3F6900', '#4B6700', '#00696A', '#4B53B9', '#006493', '#8A33B8',
             '#9E2A99', '#99405E', '#1B1B1B']
on_variant_1 = '#FFF'

# VARIANT 2 ----------------------------------------------------------------
variant_2 = ['#FFB4AA', '#FFB689', '#E9C327', '#92DA35', '#AFD364', '#4CDADB', '#BEC2FF', '#8DCDFF', '#E8B3FF',
             '#FFABF1', '#FFB1C5', '#C6C6C6']
on_variant_2 = ['#690004', '#512400', '#3B2F00', '#1F3700', '#253600', '#003737', '#181F89', '#00344F', '#500075',
                '#5C005A', '#5E1130', '#303030']

# VARIANT 3 ----------------------------------------------------------------
variant_3 = ['#FFDAD5', '#FFDBC7', '#FFE177', '#ACF850', '#CAF07D', '#6FF6F7', '#E0E0FF', '#CAE6FF', '#F6D9FF',
             '#FFD7F4', '#FFD9E1', '#E2E2E2']
on_variant_3 = ['#410001', '#311300', '#231B00', '#102000', '#141F00', '#002020', '#00036B', '#001E30', '#310049',
                '#380037', '#3F001B', '#1B1B1B']


@app.route('/')
def home():
    return 'You can go to <a href="/badge/stars/2/2/arsho/Hackerrank_Python_Domain_Solutions">/badge/stars/2/2/arsho/Hackerrank_Python_Domain_Solutions</a> to see the stars for arsho/Hackerrank_Python_Domain_Solutions repository'


@app.route('/badge/stars/<style>/<variant>/<username>/<repo>')
def github_stars_badge(style, variant, username, repo):
    url = f'https://api.github.com/repos/{username}/{repo}'
    headers = {'Accept': 'application/vnd.github.v3+json'}
    r = requests.get(url, headers=headers)
    if r.ok:
        index = int(style) - 1

        if variant == '1':
            background = variant_1[index]
            foreground = on_variant_1
        if variant == '2':
            background = variant_2[index]
            foreground = on_variant_2[index]
        if variant == '3':
            background = variant_3[index]
            foreground = on_variant_3[index]

        data = r.json()
        stars = data['stargazers_count']

        if len(str(stars)) == 1:
            width = 20 + 68
        elif len(str(stars)) == 2:
            width = 2 * 16 + 68
        elif len(str(stars)) == 3:
            width = 3 * 14 + 68
        elif len(str(stars)) == 4:
            width = 4 * 13 + 68
        else:
            width = len(str(stars)) * 13 + 68

        svg = f'<svg xmlns="http://www.w3.org/2000/svg" width="{width}" height="30" fill="{background}" rx="15"><path d="M40 0h4v20h-4z" fill="#4c1"/><rect rx="15" width="{width}" height="30" fill="{background}"/><text x="11" y="22" fill="{foreground}" font-size="20" font-family="Product Sans">Stars : {stars}</text></svg>'
        return Response(svg, mimetype='image/svg+xml')
    else:
        return 'Error', r.status_code

Screenshot:

demo

Upvotes: 0

SaptakD625
SaptakD625

Reputation: 159

Directory Structure of dynamicBadges:

.
├── main.py
├── requirements.txt
└── vercel.json

The first fix is with the requirements.txt. requests is not part of the Python Standard Library and hence must be included. The requirements.txt should look like:

blinker==1.6.2
certifi==2023.5.7
charset-normalizer==3.1.0
click==8.1.3
colorama==0.4.6
Flask==2.3.2
idna==3.4
importlib-metadata==6.7.0
itsdangerous==2.1.2
Jinja2==3.1.2
MarkupSafe==2.1.3
requests==2.31.0
urllib3==2.0.3
Werkzeug==2.3.6
zipp==3.15.0

The second fix is with the vercel.json configuration. Use the following configuration:

{
"version": 2,
"builds": [
    {
        "src": "main.py",
        "use": "@vercel/python"
    }
],
"routes": [
    {
        "src": "(.*)",
        "dest": "main.py"
    }
]}

Link to Sample Deployment: https://badges-vercel.vercel.app/badge/stars/1/1/microsoft/vscode

Screenshot of Solution: enter image description here

Upvotes: 1

Related Questions