Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add reddit clone #10

Open
wants to merge 150 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
150 commits
Select commit Hold shift + click to select a range
67d5add
add more models
aryaniyaps Sep 21, 2021
d429da0
rename model.py to models.py
aryaniyaps Sep 21, 2021
5e48aff
update tech stack
aryaniyaps Sep 21, 2021
fc413ec
fix base model inheritance
aryaniyaps Sep 21, 2021
9b31170
update field comments
aryaniyaps Sep 21, 2021
8c6bd21
update __init__.py
aryaniyaps Sep 21, 2021
b4788f7
add example goal
aryaniyaps Sep 21, 2021
9ce38ab
add alembic skeleton
aryaniyaps Sep 21, 2021
294396a
refactor example structure
aryaniyaps Sep 25, 2021
ac8b8e2
update model comments
aryaniyaps Sep 25, 2021
458f223
update typing
aryaniyaps Sep 25, 2021
900d259
Update env.py
aryaniyaps Sep 25, 2021
fa12496
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 25, 2021
972acd4
Update alembic.ini
aryaniyaps Sep 25, 2021
45502a5
Update post.py
aryaniyaps Sep 25, 2021
b75378b
Update user.py
aryaniyaps Sep 25, 2021
d100613
Update user.py
aryaniyaps Sep 25, 2021
19d6dad
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 25, 2021
4e8a60e
Update user.py
aryaniyaps Sep 25, 2021
bc85d46
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 25, 2021
8b0bf79
Update user.py
aryaniyaps Sep 25, 2021
3204fbb
Create database.py
aryaniyaps Sep 26, 2021
61ae172
Update database.py
aryaniyaps Sep 26, 2021
64b1a9a
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 26, 2021
cc4fb35
Delete reddit-clone/reddit/db directory
aryaniyaps Sep 26, 2021
5dc1454
Update env.py
aryaniyaps Sep 26, 2021
4317bbe
Create settings.py
aryaniyaps Sep 26, 2021
8280d5a
Update database.py
aryaniyaps Sep 26, 2021
74dd913
Delete reddit-clone/reddit/core directory
aryaniyaps Sep 26, 2021
8ac9df7
refactor project structure
aryaniyaps Sep 30, 2021
cef2a1c
type hint relationships
aryaniyaps Sep 30, 2021
5dc7f90
add dummy schema (and update instructions)
aryaniyaps Sep 30, 2021
797f7c3
make migrations
aryaniyaps Sep 30, 2021
784ec42
remove .idea
aryaniyaps Sep 30, 2021
923e5ee
remove broken migrations
aryaniyaps Sep 30, 2021
c475d94
populate metadata
aryaniyaps Sep 30, 2021
a0934b8
add schema types
aryaniyaps Oct 5, 2021
717a30a
add user loaders
aryaniyaps Oct 5, 2021
82c1c99
update context
aryaniyaps Oct 5, 2021
c7e5e5d
update model: user
aryaniyaps Oct 6, 2021
fdf42ae
update type: node
aryaniyaps Oct 6, 2021
c1520b6
implement classmethod: get_node on node types
aryaniyaps Oct 6, 2021
2487b21
update nodes
aryaniyaps Oct 6, 2021
f4ec663
rename node resolver
aryaniyaps Oct 6, 2021
7be5c59
add field: node
aryaniyaps Oct 6, 2021
49c7c14
import strawberry as a whole module
aryaniyaps Oct 6, 2021
f9c4df0
update interface checking
aryaniyaps Oct 6, 2021
5379890
update typehints
aryaniyaps Oct 9, 2021
63e7064
add user mutations and queries
aryaniyaps Oct 9, 2021
ee6bbcf
replace strawberry.union with typing.Union
aryaniyaps Oct 9, 2021
d0ba9e0
delete mutations.py
aryaniyaps Oct 9, 2021
c09a2ad
mark input types correctly
aryaniyaps Oct 9, 2021
005353f
remove decorator-based field definitions
aryaniyaps Oct 9, 2021
234e1b9
update field descriptions
aryaniyaps Oct 9, 2021
0e75b36
update BaseQuery
aryaniyaps Oct 9, 2021
e6637fa
add a few email templates
aryaniyaps Oct 9, 2021
628ae0e
add skeleton for subreddit mutations and queries
aryaniyaps Oct 9, 2021
af11ed2
remove from_instance before we finalize data models
aryaniyaps Oct 9, 2021
743b156
add more mutations
aryaniyaps Oct 10, 2021
53e09fc
remove explicit field names
aryaniyaps Oct 10, 2021
076777f
setup email client
aryaniyaps Oct 10, 2021
8033676
update example env file
aryaniyaps Oct 10, 2021
3d15d8a
rename email helper
aryaniyaps Oct 10, 2021
afafbbd
update README.md
aryaniyaps Oct 10, 2021
fc47ef7
update setup instructions
aryaniyaps Oct 10, 2021
ce67dd3
fix model: comment
aryaniyaps Oct 10, 2021
c053899
update README.md
aryaniyaps Oct 10, 2021
da35bd9
use schematics for data validation
aryaniyaps Oct 10, 2021
560c8e6
add user service
aryaniyaps Oct 10, 2021
81f281b
add user services
aryaniyaps Oct 10, 2021
eb7bd5f
update user services
aryaniyaps Oct 10, 2021
9c221ba
update user services
aryaniyaps Oct 10, 2021
2d28665
add email template: change email
aryaniyaps Oct 10, 2021
3e58450
update user service: deactivate_user
aryaniyaps Oct 10, 2021
ba08a49
simplify schema design
aryaniyaps Oct 10, 2021
1f7b053
update deps: add jinja2
aryaniyaps Oct 10, 2021
6ea08f4
add templating helpers
aryaniyaps Oct 10, 2021
4f719f2
add file storage helpers
aryaniyaps Oct 11, 2021
e17eb28
update storage helper: generate-file-name
aryaniyaps Oct 11, 2021
141951d
switch to starlette
aryaniyaps Oct 11, 2021
3687f40
pass debug value
aryaniyaps Oct 11, 2021
ffe32b1
update graphql app
aryaniyaps Oct 11, 2021
3f16c64
create dir: utils
aryaniyaps Oct 11, 2021
bc58695
describe mail config values
aryaniyaps Oct 11, 2021
ec80bca
update README.md
aryaniyaps Oct 11, 2021
a2a6b8b
update README.md
aryaniyaps Oct 11, 2021
6e0dbc3
Update templates.py
aryaniyaps Oct 12, 2021
a7c2b0c
update strawberry (we need to access schema from resolver info)
aryaniyaps Oct 13, 2021
9776bd3
update user queries
aryaniyaps Oct 13, 2021
2f97af7
update user queries
aryaniyaps Oct 13, 2021
e2d796b
add connection types
aryaniyaps Oct 13, 2021
feb613e
update node type
aryaniyaps Oct 13, 2021
4fea150
document relay types
aryaniyaps Oct 13, 2021
4051849
document relay types
aryaniyaps Oct 13, 2021
f9ab261
simplify node type
aryaniyaps Oct 13, 2021
667dad5
update services
aryaniyaps Oct 14, 2021
58f2da0
update user services
aryaniyaps Oct 14, 2021
eeacb09
add more dataloaders
aryaniyaps Oct 14, 2021
699a09a
fix graphql asgi app
aryaniyaps Oct 14, 2021
1a33dc3
simplify base query
aryaniyaps Oct 14, 2021
9fe4063
update services
aryaniyaps Oct 14, 2021
2ca8249
flag abstract types
aryaniyaps Oct 14, 2021
19f5c3a
make pageinfo-cursor generic
aryaniyaps Oct 14, 2021
2d170ff
pass kwargs to type var
aryaniyaps Oct 14, 2021
ca92138
add skeletons for services
aryaniyaps Oct 14, 2021
d6c37d2
recreate migrations
aryaniyaps Oct 14, 2021
cc26b55
review migrations
aryaniyaps Oct 14, 2021
aea21ef
Update README.md
aryaniyaps Oct 14, 2021
1f0a1ce
add celery
aryaniyaps Oct 14, 2021
4fbe70a
update celery worker
aryaniyaps Oct 14, 2021
44798ec
update README.md
aryaniyaps Oct 14, 2021
c3ac1a7
update README.md
aryaniyaps Oct 14, 2021
93f4d65
add dockerfile
aryaniyaps Oct 14, 2021
1b8bcd1
prepare to use docker compose
aryaniyaps Oct 14, 2021
645026f
add docker-compose.yml
aryaniyaps Oct 15, 2021
1d2b56a
update Dockerfile to python 3.9
aryaniyaps Oct 15, 2021
7333d27
update docker file
aryaniyaps Oct 15, 2021
0c32ec8
update dockerfile
aryaniyaps Oct 15, 2021
c02786f
add .dockerignore
aryaniyaps Oct 15, 2021
4fc9965
create volume for postgres data
aryaniyaps Oct 15, 2021
fcfe7ca
make docker compose happy
aryaniyaps Oct 15, 2021
59ec70f
update Dockerfile
aryaniyaps Oct 15, 2021
77fc174
simplify setup instructions
aryaniyaps Oct 15, 2021
4178ea6
update docker compose config
aryaniyaps Oct 15, 2021
7f2bb23
update tasks.py
aryaniyaps Oct 15, 2021
92bb3aa
add PGadmin
aryaniyaps Oct 15, 2021
0528e62
update pgadmin config
aryaniyaps Oct 15, 2021
89d8f86
update Dockerfile
aryaniyaps Oct 15, 2021
cc6f6dc
expose correct docker port
aryaniyaps Oct 15, 2021
b09177f
clear the clutter
aryaniyaps Oct 15, 2021
9f1c97e
make builds slim
aryaniyaps Oct 15, 2021
2a1abd4
update docker-compose.yml
aryaniyaps Oct 15, 2021
26b521e
update docker-compose.yml
aryaniyaps Oct 16, 2021
fc1dd3b
update README.md
aryaniyaps Oct 16, 2021
9c9aab6
update celery deps
aryaniyaps Oct 16, 2021
823ce99
simplify docker config
aryaniyaps Oct 16, 2021
675650a
reduce duplication
aryaniyaps Oct 16, 2021
1e901e0
update docker-compose.yml
aryaniyaps Oct 16, 2021
dfb2f86
update database url
aryaniyaps Oct 16, 2021
56ab62c
update docker-compose.yml
aryaniyaps Oct 16, 2021
b98389e
update docker config
aryaniyaps Oct 16, 2021
b51cd54
prepare to add nginx
aryaniyaps Oct 16, 2021
904b07c
get nginx proxy working
aryaniyaps Oct 17, 2021
632f5a7
add more fields
aryaniyaps Oct 17, 2021
a4b971e
fix circular import issues
aryaniyaps Oct 17, 2021
57fae72
use helper: merge_types
aryaniyaps Oct 17, 2021
db85096
use helper: merge_types
aryaniyaps Oct 17, 2021
c6fb4b8
fix schema fields
aryaniyaps Oct 18, 2021
311b93d
use marshmallow for serialization
aryaniyaps Oct 19, 2021
f7c0d6d
update volumes
aryaniyaps Oct 19, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
Expand Down Expand Up @@ -127,3 +126,6 @@ dmypy.json

# Pyre type checker
.pyre/

# PyCharm
.idea
7 changes: 7 additions & 0 deletions reddit-clone/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.git
__pycache__
*.pyc
*.pyo
*.pyd
.Python
env
7 changes: 7 additions & 0 deletions reddit-clone/.flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[flake8]
max-line-length = 89
exclude=.venv,.git
ignore = W503
extend-ignore =
# See https://github.com/PyCQA/pycodestyle/issues/373
E203,
Empty file added reddit-clone/.projectroot
Empty file.
15 changes: 15 additions & 0 deletions reddit-clone/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
FROM python:3.9-slim
LABEL maintainer="Aryan Iyappan <[email protected]>"

ARG APP_HOME=/app/
WORKDIR ${APP_HOME}

# install poetry
RUN pip install poetry

# install dependencies
COPY ./poetry.lock ./pyproject.toml ${APP_HOME}
RUN poetry install --no-dev

# copy project files
COPY ./ ${APP_HOME}
36 changes: 36 additions & 0 deletions reddit-clone/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Reddit GraphQL API

This example shows you how to create a Reddit API clone using GraphQL.
The goal of this example is not to re-create the entire reddit API, but
to produce a simpler version that is easier to understand, and implements
most of the features that Strawberry gives us.

## Tech Stack used:

- [Strawberry GraphQL](https://github.com/strawberry-graphql/strawberry)
- [Starlette](https://github.com/encode/starlette) web framework
- [Uvicorn](https://github.com/encode/uvicorn) ASGI server
- [SQLAlchemy](https://github.com/sqlalchemy/sqlalchemy) core/ mapper (asyncio)
- [Alembic](https://github.com/sqlalchemy/alembic) migrations
- [PostgreSQL](https://github.com/postgres/postgres) database server
- [Marshmallow](https://github.com/marshmallow-code/marshmallow) data validation
- [Celery](https://github.com/celery/celery) tasks ([Redis](https://github.com/redis/redis) store, [RabbitMQ](https://github.com/rabbitmq/rabbitmq-server) broker)

## Features at a glance

- [ ] Implements the Relay spec
- [x] data modelling with relations
- [x] Error modelling within the schema
- [ ] Authorization with the permissions API
- [x] Batch loading with dataloaders
- [x] modular codebase

## How to use

You can use [Docker Compose](https://github.com/docker/compose) to run this example. Make sure you have it installed on your machine!

```text
docker compose up
```

You can now explore the GraphQL API here: http://localhost/graphql
100 changes: 100 additions & 0 deletions reddit-clone/alembic.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# A generic, single database configuration.

[alembic]
# path to migration scripts
script_location = migrations

# template used to generate migration files
# file_template = %%(rev)s_%%(slug)s

# sys.path path, will be prepended to sys.path if present.
# defaults to the current working directory.
prepend_sys_path = .

# timezone to use when rendering the date within the migration file
# as well as the filename.
# If specified, requires the python-dateutil library that can be
# installed by adding `alembic[tz]` to the pip requirements
# string value is passed to dateutil.tz.gettz()
# leave blank for localtime
# timezone =

# max length of characters to apply to the
# "slug" field
# truncate_slug_length = 40

# set to 'true' to run the environment during
# the 'revision' command, regardless of autogenerate
# revision_environment = false

# set to 'true' to allow .pyc and .pyo files without
# a source .py file to be detected as revisions in the
# versions/ directory
# sourceless = false

# version location specification; This defaults
# to migrations/versions. When using multiple version
# directories, initial revisions must be specified with --version-path.
# The path separator used here should be the separator specified by "version_path_separator"
# version_locations = %(here)s/bar:%(here)s/bat:migrations/versions

# version path separator; As mentioned above, this is the character used to split
# version_locations. Valid values are:
#
# version_path_separator = :
# version_path_separator = ;
# version_path_separator = space
version_path_separator = os # default: use os.pathsep

# the output encoding used when revision files
# are written from script.py.mako
# output_encoding = utf-8

sqlalchemy.url = driver://user:pass@localhost/dbname


[post_write_hooks]
# post_write_hooks defines scripts or Python functions that are run
# on newly generated revision scripts. See the documentation for further
# detail and examples

# format using "black" - use the console_scripts runner, against the "black" entrypoint
# hooks = black
# black.type = console_scripts
# black.entrypoint = black
# black.options = -l 79 REVISION_SCRIPT_FILENAME

# Logging configuration
[loggers]
keys = root,sqlalchemy,alembic

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = WARN
handlers = console
qualname =

[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine

[logger_alembic]
level = INFO
handlers =
qualname = alembic

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S
113 changes: 113 additions & 0 deletions reddit-clone/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
version: "3.9"
x-environment: &base-environment
DEBUG: "false"
CELERY_BROKER: amqp://reddit:reddit@rabbitmq:5672/
CELERY_BACKEND: redis://:reddit@localhost:6379/
DATABASE_URL: postgresql+asyncpg://reddit:reddit@postgres:5432/reddit/
MAIL_HOST: 127.0.0.1
MAIL_PORT: 25
MAIL_USERNAME:
MAIL_PASSWORD:
MAIL_SENDER:

services:
nginx:
image: nginx:1.21-alpine
container_name: reddit-nginx
restart: always
networks:
- reddit-proxy
ports:
- 80:80
volumes:
- ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf
depends_on:
- app

app:
build: "."
image: reddit-app
container_name: reddit-app
restart: always
command: poetry run uvicorn reddit:app --host=0.0.0.0 --port=8080
environment: *base-environment
networks:
- reddit-main
- reddit-proxy
volumes:
- .:/app
depends_on:
- postgres

celery:
image: reddit-app
container_name: reddit-celery
restart: always
command: poetry run celery -A reddit.tasks worker
environment: *base-environment
networks:
- reddit-main
volumes:
- .:/app
depends_on:
- rabbitmq
- redis
- app

postgres:
image: postgres:14-alpine
container_name: reddit-postgres
restart: always
environment:
POSTGRES_USER: reddit
POSTGRES_PASSWORD: reddit
POSTGRES_DB: reddit
networks:
- reddit-main
ports:
- 5432:5432
volumes:
- ./data/postgres:/var/lib/postgresql/data

redis:
image: redis:6.2-alpine
container_name: reddit-redis
restart: always
environment:
REDIS_PASSWORD: reddit
networks:
- reddit-main
ports:
- 6379:6379
volumes:
- ./data/redis:/data
healthcheck:
test: redis-cli ping
interval: 15s
retries: 5
timeout: 5s

rabbitmq:
image: rabbitmq:3.9-alpine
container_name: reddit-rabbitmq
restart: always
environment:
RABBITMQ_DEFAULT_USER: reddit
RABBITMQ_DEFAULT_PASS: reddit
networks:
- reddit-main
ports:
- 5672:5672
volumes:
- ./data/rabbitmq:/data
healthcheck:
test: rabbitmq-diagnostics -q ping
interval: 15s
retries: 5
timeout: 5s

networks:
reddit-main:
driver: bridge
reddit-proxy:
driver: bridge
1 change: 1 addition & 0 deletions reddit-clone/migrations/README
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Generic single-database configuration with an async dbapi.
96 changes: 96 additions & 0 deletions reddit-clone/migrations/env.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import asyncio
from logging.config import fileConfig

from sqlalchemy import engine_from_config
from sqlalchemy import pool
from sqlalchemy.ext.asyncio import AsyncEngine

from alembic import context

from reddit.database import Base
from reddit.settings import DATABASE_URI


# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config

config.set_main_option("sqlalchemy.url", DATABASE_URI)

# Interpret the config file for Python logging.
# This line sets up loggers basically.
fileConfig(config.config_file_name)

# populate Base.metadata
from reddit.users.models import User # noqa
from reddit.subreddits.models import Subreddit # noqa
from reddit.posts.models import Post # noqa
from reddit.comments.models import Comment # noqa

# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
target_metadata = Base.metadata

# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.


def run_migrations_offline():
"""Run migrations in 'offline' mode.

This configures the context with just a URL
and not an Engine, though an Engine is acceptable
here as well. By skipping the Engine creation
we don't even need a DBAPI to be available.

Calls to context.execute() here emit the given string to the
script output.

"""
url = config.get_main_option("sqlalchemy.url")
context.configure(
url=url,
target_metadata=target_metadata,
literal_binds=True,
dialect_opts={"paramstyle": "named"},
)

with context.begin_transaction():
context.run_migrations()


def do_run_migrations(connection):
context.configure(connection=connection, target_metadata=target_metadata)

with context.begin_transaction():
context.run_migrations()


async def run_migrations_online():
"""Run migrations in 'online' mode.

In this scenario we need to create an Engine
and associate a connection with the context.

"""
connectable = AsyncEngine(
engine_from_config(
config.get_section(config.config_ini_section),
prefix="sqlalchemy.",
poolclass=pool.NullPool,
future=True,
)
)

async with connectable.connect() as connection:
await connection.run_sync(do_run_migrations)


if context.is_offline_mode():
run_migrations_offline()
else:
asyncio.run(run_migrations_online())
Loading