Skip to content

Commit 11bdb29

Browse files
authored
starlette example (#1454)
### Description new example showing starlette with the base 'Python' framework preset ### Demo URL https://vercel-plus-starlette.vercel.app/ ### Type of Change - [x] New Example - [ ] Example updates (Bug fixes, new features, etc.) - [ ] Other (changes to the codebase, but not to examples) ### New Example Checklist - [ ] 🛫 `npm run new-example` was used to create the example - [ ] 📚 The template wasn't used but I carefuly read the [Adding a new example](https://github.com/vercel/examples#adding-a-new-example) steps and implemented them in the example - [ ] 📱 Is it responsive? Are mobile and tablets considered?
1 parent f0bb27b commit 11bdb29

7 files changed

Lines changed: 214 additions & 0 deletions

File tree

python/starlette/.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.vercel/
2+
.venv/
3+
venv/
4+
__pycache__/
5+
.Python
6+
.DS_Store
7+
.env*
8+
.vercel

python/starlette/README.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Starlette Starter
2+
3+
Deploy your [Starlette](https://www.starlette.io/) project to Vercel with zero configuration.
4+
5+
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?demo-description=Deploy%20Python%20Starlette%20applications%20with%20zero%20configuration.&demo-title=Starlette%20Boilerplate&demo-url=https%3A%2F%2Fvercel-plus-starlette.vercel.app%2F&from=templates&project-name=Starlette%20Boilerplate&repository-name=starlette-python-boilerplate&repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fexamples%2Ftree%2Fmain%2Fpython%2Fstarlette&skippable-integrations=1)
6+
7+
_Live Example: https://vercel-plus-starlette.vercel.app/_
8+
9+
Visit the [Starlette documentation](https://www.starlette.io/) to learn more.
10+
11+
## Getting Started
12+
13+
Install the required dependencies:
14+
15+
```bash
16+
python -m venv .venv
17+
source .venv/bin/activate
18+
pip install .
19+
```
20+
21+
Or, if using [uv](https://docs.astral.sh/uv/):
22+
23+
```bash
24+
uv sync
25+
```
26+
27+
## Running Locally
28+
29+
Start the development server on http://0.0.0.0:5001
30+
31+
```bash
32+
python main.py
33+
# using uv:
34+
uv run main.py
35+
```
36+
37+
When you make changes to your project, the server will automatically reload.
38+
39+
## Deploying to Vercel
40+
41+
Deploy your project to Vercel with the following command:
42+
43+
```bash
44+
npm install -g vercel
45+
vercel --prod
46+
```
47+
48+
Or `git push` to your repository with our [git integration](https://vercel.com/docs/deployments/git).
49+
50+
To view the source code for this template, [visit the example repository](https://github.com/vercel/vercel/tree/main/examples/starlette).

python/starlette/api/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .routes import api_routes
2+
3+
__all__ = ["api_routes"]

python/starlette/api/routes.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
from starlette.responses import JSONResponse
2+
from starlette.routing import Route
3+
4+
5+
async def get_sample_data(request):
6+
return JSONResponse(
7+
{
8+
"data": [
9+
{"id": 1, "name": "Sample Item 1", "value": 100},
10+
{"id": 2, "name": "Sample Item 2", "value": 200},
11+
{"id": 3, "name": "Sample Item 3", "value": 300},
12+
],
13+
"total": 3,
14+
"timestamp": "2024-01-01T00:00:00Z",
15+
}
16+
)
17+
18+
19+
async def get_item(request):
20+
item_id = int(request.path_params["item_id"])
21+
return JSONResponse(
22+
{
23+
"item": {
24+
"id": item_id,
25+
"name": f"Sample Item {item_id}",
26+
"value": item_id * 100,
27+
},
28+
"timestamp": "2024-01-01T00:00:00Z",
29+
}
30+
)
31+
32+
33+
api_routes = [
34+
Route("/data", get_sample_data),
35+
Route("/items/{item_id:int}", get_item),
36+
]

python/starlette/main.py

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
from starlette.applications import Starlette
2+
from starlette.responses import HTMLResponse
3+
from starlette.routing import Mount, Route
4+
from api import api_routes
5+
6+
7+
async def read_root(request):
8+
return HTMLResponse("""
9+
<!DOCTYPE html>
10+
<html lang="en">
11+
<head>
12+
<meta charset="UTF-8">
13+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
14+
<title>Vercel + Starlette</title>
15+
<link rel="icon" type="image/svg+xml" href="/favicon.ico">
16+
<style>
17+
* { margin: 0; padding: 0; box-sizing: border-box; }
18+
body {
19+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', sans-serif;
20+
background-color: #000000; color: #ffffff; line-height: 1.6; min-height: 100vh;
21+
display: flex; flex-direction: column;
22+
}
23+
header { border-bottom: 1px solid #333333; padding: 0; }
24+
nav { max-width: 1200px; margin: 0 auto; display: flex; align-items: center; padding: 1rem 2rem; gap: 2rem; }
25+
.logo { font-size: 1.25rem; font-weight: 600; color: #ffffff; text-decoration: none; }
26+
.nav-links { display: flex; gap: 1.5rem; margin-left: auto; }
27+
.nav-links a { text-decoration: none; color: #888888; padding: 0.5rem 1rem; border-radius: 6px; transition: all 0.2s ease; font-size: 0.875rem; font-weight: 500; }
28+
.nav-links a:hover { color: #ffffff; background-color: #111111; }
29+
main { flex: 1; max-width: 1200px; margin: 0 auto; padding: 4rem 2rem; display: flex; flex-direction: column; align-items: center; text-align: center; }
30+
.hero { margin-bottom: 3rem; }
31+
.hero-code { margin-top: 2rem; width: 100%; max-width: 900px; display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
32+
.hero-code pre { background-color: #0a0a0a; border: 1px solid #333333; border-radius: 8px; padding: 1.5rem; text-align: left; grid-column: 1 / -1; }
33+
h1 { font-size: 3rem; font-weight: 700; margin-bottom: 1rem; background: linear-gradient(to right, #ffffff, #888888); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; }
34+
.subtitle { font-size: 1.25rem; color: #888888; margin-bottom: 2rem; max-width: 600px; }
35+
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 1.5rem; width: 100%; max-width: 900px; }
36+
.card { background-color: #111111; border: 1px solid #333333; border-radius: 8px; padding: 1.5rem; transition: all 0.2s ease; text-align: left; }
37+
.card:hover { border-color: #555555; transform: translateY(-2px); }
38+
.card h3 { font-size: 1.125rem; font-weight: 600; margin-bottom: 0.5rem; color: #ffffff; }
39+
.card p { color: #888888; font-size: 0.875rem; margin-bottom: 1rem; }
40+
.card a { display: inline-flex; align-items: center; color: #ffffff; text-decoration: none; font-size: 0.875rem; font-weight: 500; padding: 0.5rem 1rem; background-color: #222222; border-radius: 6px; border: 1px solid #333333; transition: all 0.2s ease; }
41+
.card a:hover { background-color: #333333; border-color: #555555; }
42+
.status-badge { display: inline-flex; align-items: center; gap: 0.5rem; background-color: #0070f3; color: #ffffff; padding: 0.25rem 0.75rem; border-radius: 20px; font-size: 0.75rem; font-weight: 500; margin-bottom: 2rem; }
43+
.status-dot { width: 6px; height: 6px; background-color: #00ff88; border-radius: 50%; }
44+
pre { background-color: #0a0a0a; border: 1px solid #333333; border-radius: 6px; padding: 1rem; overflow-x: auto; margin: 0; }
45+
code { font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace; font-size: 0.85rem; line-height: 1.5; color: #ffffff; }
46+
.keyword { color: #ff79c6; }
47+
.string { color: #f1fa8c; }
48+
.function { color: #50fa7b; }
49+
.class { color: #8be9fd; }
50+
.module { color: #8be9fd; }
51+
.variable { color: #f8f8f2; }
52+
.decorator { color: #ffb86c; }
53+
@media (max-width: 768px) {
54+
nav { padding: 1rem; flex-direction: column; gap: 1rem; }
55+
.nav-links { margin-left: 0; }
56+
main { padding: 2rem 1rem; }
57+
h1 { font-size: 2rem; }
58+
.hero-code { grid-template-columns: 1fr; }
59+
.cards { grid-template-columns: 1fr; }
60+
}
61+
</style>
62+
</head>
63+
<body>
64+
<header>
65+
<nav>
66+
<a href="/" class="logo">Vercel + Starlette</a>
67+
<div class="nav-links">
68+
<a href="/api/data">API</a>
69+
</div>
70+
</nav>
71+
</header>
72+
<main>
73+
<div class="hero">
74+
<h1>Vercel + Starlette</h1>
75+
<div class="hero-code">
76+
<pre><code><span class="keyword">from</span> <span class="module">starlette.applications</span> <span class="keyword">import</span> <span class="class">Starlette</span>
77+
<span class="keyword">from</span> <span class="module">starlette.responses</span> <span class="keyword">import</span> <span class="class">JSONResponse</span>
78+
<span class="keyword">from</span> <span class="module">starlette.routing</span> <span class="keyword">import</span> <span class="class">Route</span>
79+
80+
<span class="keyword">async def</span> <span class="function">homepage</span>(<span class="variable">request</span>):
81+
<span class="keyword">return</span> <span class="class">JSONResponse</span>({<span class="string">"Python"</span>: <span class="string">"on Vercel"</span>})
82+
83+
<span class="variable">app</span> = <span class="class">Starlette</span>(<span class="variable">routes</span>=[<span class="class">Route</span>(<span class="string">"/"</span>, <span class="variable">homepage</span>)])</code></pre>
84+
</div>
85+
</div>
86+
87+
<div class="cards">
88+
<div class="card">
89+
<h3>Sample Data</h3>
90+
<p>Access sample JSON data through our REST API. Perfect for testing and development purposes.</p>
91+
<a href="/api/data">Get Data →</a>
92+
</div>
93+
</div>
94+
</main>
95+
</body>
96+
</html>
97+
""")
98+
99+
100+
app = Starlette(
101+
routes=[
102+
Route("/", read_root),
103+
Mount("/api", routes=api_routes),
104+
]
105+
)
106+
107+
108+
if __name__ == "__main__":
109+
import uvicorn
110+
uvicorn.run(app, host="0.0.0.0", port=5001)
6.61 KB
Binary file not shown.

python/starlette/pyproject.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[project]
2+
name = "vercel-starlette-starter"
3+
version = "0.1.0"
4+
requires-python = ">=3.12"
5+
dependencies = [
6+
"starlette>=0.40"
7+
]

0 commit comments

Comments
 (0)