Skip to content

Commit 202302a

Browse files
committed
initial commit
0 parents  commit 202302a

12 files changed

+1624
-0
lines changed

.dockerignore

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Python
2+
__pycache__
3+
*.pyc
4+
.mypy_cache
5+
.coverage
6+
htmlcov
7+
.venv
8+
.env
9+
.env.*

.env.docker

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
REDIS_URL="redis://redis:6379"
2+

.env.example

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
PORT=8000
2+
REDIS_URL="redis://localhost:6379"
3+

.gitignore

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Python
2+
__pycache__
3+
*.pyc
4+
.mypy_cache
5+
.ruff_cache
6+
.coverage
7+
htmlcov
8+
.venv
9+
.env
10+
.env.*
11+
!.env.docker
12+
!.env.example

Dockerfile

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
FROM python:3.12-slim
2+
ENV PYTHONUNBUFFERED=1
3+
WORKDIR /app/
4+
5+
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
6+
7+
# Place executables in the environment at the front of the path
8+
# Ref: https://docs.astral.sh/uv/guides/integration/docker/#using-the-environment
9+
ENV PATH="/app/.venv/bin:$PATH"
10+
11+
# Compile bytecode
12+
# Ref: https://docs.astral.sh/uv/guides/integration/docker/#compiling-bytecode
13+
ENV UV_COMPILE_BYTECODE=1
14+
15+
# uv Cache
16+
# Ref: https://docs.astral.sh/uv/guides/integration/docker/#caching
17+
ENV UV_LINK_MODE=copy
18+
19+
# Install dependencies
20+
# Ref: https://docs.astral.sh/uv/guides/integration/docker/#intermediate-layers
21+
RUN --mount=type=cache,target=/root/.cache/uv \
22+
--mount=type=bind,source=uv.lock,target=uv.lock \
23+
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
24+
uv sync --frozen --no-install-project
25+
26+
ENV PYTHONPATH=/app
27+
28+
COPY ./pyproject.toml ./uv.lock /app/
29+
COPY ./app /app/app
30+
31+
# Sync the project
32+
# Ref: https://docs.astral.sh/uv/guides/integration/docker/#intermediate-layers
33+
RUN --mount=type=cache,target=/root/.cache/uv \
34+
uv sync
35+
36+
ENV PORT 8080
37+
38+
EXPOSE ${PORT}
39+
40+
CMD ["sh", "-c", "fastapi run --port ${PORT} app/main.py"]
41+

Makefile

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
install:
2+
@uv sync
3+
4+
dev: install
5+
@fastapi dev app/main.py
6+
7+
serve: install
8+
@fastapi run app/main.py
9+
10+
docker:
11+
@docker compose up -d
12+
13+
format: install
14+
@ruff check app --fix
15+
@ruff format app
16+
17+
lint: install
18+
@mypy app
19+
@ruff check app
20+
@ruff format app --check
21+
22+
clean:
23+
@rm -rf .venv/ .mypy_cache/ .ruff_cache/

README.md

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
This is a [Redis](https://redis.io/) starter template for Go:
2+
3+
- [Redis Cloud](https://redis.io/try-free/)
4+
- [Echo](https://echo.labstack.com/)
5+
6+
## Getting started
7+
8+
Copy and edit the `.env` file:
9+
10+
```bash
11+
cp .env.example .env
12+
```
13+
14+
Your `.env` file should contain the connection string you copied from Redis Cloud.
15+
16+
Your `.env.docker` file will look similar to `.env`, but should use the appropriate docker internal URLs. Here is
17+
an example:
18+
19+
```bash
20+
REDIS_URL="redis://redis:6379"
21+
```
22+
23+
Next, spin up docker containers:
24+
25+
```bash
26+
make docker
27+
```
28+
29+
You should have a server running on `http://localhost:<port>` where the port is set in your `.env` file (default is 8000). You can test the following routes:
30+
31+
1. `GET /api/todos` - Gets all todos
32+
2. `GET /api/todos/:id` - Gets a todo by ID
33+
3. `GET /api/todos?[name=<name>]&[status=<status>]` - Search for todos by name and/or status
34+
4. `POST /api/todos` - Create a todo with `{ "name": "Sample todo" }`
35+
5. `PATCH /api/todos/:id` - Update todo by ID with `{ "status": "todo|in progress|complete" }`
36+
6. `DELETE /api/todos/:id` - Delete a todo by ID
37+
38+
## Running tests
39+
40+
## Running locally outside docker
41+
42+
To run the development server outside of docker:
43+
44+
```bash
45+
make dev
46+
```
47+
48+
## Other Scripts
49+
50+
Run a production server outside of docker:
51+
52+
```bash
53+
make serve
54+
```
55+
56+
Formatting code:
57+
58+
```bash
59+
make format
60+
```
61+
62+
Linting:
63+
64+
```bash
65+
make lint
66+
```
67+
68+
## Connecting to Redis Cloud
69+
70+
If you don't yet have a database setup in Redis Cloud [get started here for free](https://redis.io/try-free/).
71+
72+
To connect to a Redis Cloud database, log into the console and find the following:
73+
74+
1. The `public endpoint` (looks like `redis-#####.c###.us-east-1-#.ec2.redns.redis-cloud.com:#####`)
75+
1. Your `username` (`default` is the default username, otherwise find the one you setup)
76+
1. Your `password` (either setup through Data Access Control, or available in the `Security` section of the database
77+
page.
78+
79+
Combine the above values into a connection string and put it in your `.env` and `.env.docker` accordingly. It should
80+
look something like the following:
81+
82+
```bash
83+
REDIS_URL="redis://default:<password>@redis-#####.c###.us-west-2-#.ec2.redns.redis-cloud.com:#####"
84+
```
85+
86+
Run the [tests](#running-tests) to verify that you are connected properly.
87+
88+
## Learn more
89+
90+
To learn more about Redis, take a look at the following resources:
91+
92+
- [Redis Documentation](https://redis.io/docs/latest/) - learn about Redis products, features, and commands.
93+
- [Learn Redis](https://redis.io/learn/) - read tutorials, quick starts, and how-to guides for Redis.
94+
- [Redis Demo Center](https://redis.io/demo-center/) - watch short, technical videos about Redis products and features.
95+

app/__init__.py

Whitespace-only changes.

app/main.py

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from typing import Union
2+
3+
from fastapi import FastAPI
4+
5+
app = FastAPI()
6+
7+
8+
@app.get("/")
9+
def read_root():
10+
return {"Hello": "World"}
11+
12+
13+
@app.get("/items/{item_id}")
14+
def read_item(item_id: int, q: Union[str, None] = None):
15+
return {"item_id": item_id, "q": q}

compose.yml

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: redis-starter-python
2+
services:
3+
redis:
4+
container_name: redis
5+
image: "redis:8.0-M02"
6+
ports:
7+
- 6379:6379
8+
deploy:
9+
replicas: 1
10+
restart_policy:
11+
condition: on-failure
12+
volumes:
13+
- redis-data:/data
14+
15+
server:
16+
container_name: server
17+
build: .
18+
ports:
19+
- "${PORT-8080}:${PORT-8080}"
20+
environment:
21+
PORT: ${PORT-8080}
22+
env_file:
23+
- .env
24+
- .env.docker
25+
restart: always
26+
depends_on:
27+
- redis
28+
29+
volumes:
30+
redis-data:
31+

pyproject.toml

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
[project]
2+
name = "redis-starter-python"
3+
version = "0.1.0"
4+
description = "A starter project for working with Redis and Python"
5+
authors = [
6+
{ name = "Will Johnston", email = "[email protected]" }
7+
]
8+
maintainers = [
9+
{ name = "Will Johnston", email = "[email protected]" }
10+
]
11+
readme = "README.md"
12+
license = "MIT"
13+
requires-python = ">=3.8"
14+
keywords = ["python", "fastapi", "redis", "starter", "redis-py"]
15+
classifiers = [
16+
"Development Status :: 4 - Beta",
17+
"Intended Audience :: Developers",
18+
"Programming Language :: Python"
19+
]
20+
dependencies = ["fastapi[standard] (>=0.115.6,<0.116.0)"]
21+
22+
[project.urls]
23+
Repository = "https://github.com/redis-developer/redis-starter-python.git"
24+
"Bug Tracker" = "https://github.com/redis-developer/redis-starter-python/issues"
25+
26+
[project.optional-dependencies]
27+
dev = [
28+
"mypy<2.0.0,>=1.8.0",
29+
"ruff<1.0.0,>=0.2.2",
30+
]
31+
32+
[tool.mypy]
33+
strict = true
34+
35+
[tool.ruff]
36+
target-version = "py38"
37+
38+
[tool.ruff.lint]
39+
select = [
40+
"E", # pycodestyle errors
41+
"W", # pycodestyle warnings
42+
"F", # pyflakes
43+
"I", # isort
44+
"B", # flake8-bugbear
45+
"C4", # flake8-comprehensions
46+
"UP", # pyupgrade
47+
"ARG001", # unused arguments in functions
48+
]
49+
ignore = [
50+
"E501", # line too long, handled by black
51+
"B008", # do not perform function calls in argument defaults
52+
"W191", # indentation contains tabs
53+
"B904", # Allow raising exceptions without from e, for HTTPException
54+
]
55+
56+
[tool.ruff.lint.pyupgrade]
57+
# Preserve types, even if a file imports `from __future__ import annotations`.
58+
keep-runtime-typing = true
59+

0 commit comments

Comments
 (0)