Skip to content

Simple but powerful and async blog system RESTful API which has 2FA with JWT and comments of n level replies.

License

Notifications You must be signed in to change notification settings

mahdihaghverdi/simplerestblog

Repository files navigation

Table of Contents

Introduction

SimpleRESTBlog is a fast, fully async and reliable blog system RESTful API built with Python and FastAPI framework. It uses the open source PostgreSQL database for storage.

Note: This project is under development and is not fully ready! see the Roadmap section.

Features

  • Fully async and non-blocking.
  • Uses FastAPI framework for API development
  • Uses PostgreSQL as data store for users, drafts, posts and comments.
  • Fully layered and decoupled code.
  • Extensible architecture for adding new API endpoints and services.
  • Descriptive and well-documented code.
  • OAuth2 (with hashed passwords and JWT tokens) based user authentication.
  • TOTP for two-factor authentication using authenticator apps like Google Authenticator.
  • Uses Poetry for dependency management.
  • Automated code formatting and linting with pre-commit and ruff.
  • Pagination support for listing comments.
  • Fully type annotated code for better IDE support and code quality.

Project Structure, Implementation details and Best Practices

Structure

Structure of simplerestblog package containing main files and folders of the application is consistent and straightforward and just by looking at module names it gives you an idea of what's inside it!

simplerestblog
├── alembic                 # Migration utility
├── src                     # Primary app
│   ├── core                # config, ACL, DB, depends, schemas, security, ...
│   ├── repository          # Data layer: Repository and ORM stuff
│   ├── service             # Service layer: the business logic
│   ├── web                 # API layer: routes
│   ├── app.py              # Main FastAPI app
│   ├── __init__.py
│   └── __main__.py         # Runs the uvicorn server
├── tests                   # App tests
├── alembic.ini             # Migration settings
└── pyproject.toml

Implementation details

Database Design

At the core of almost any business, a good database design helps the reliability and data normalization and avoid wasting disk usage.

The database design and considerations of SRB is discussed below.

Tables:

users
+------------------+----------+------+---------+-----------+------+-----+----+
| username: UNIQUE | password | role | created | totp_hash | name | ... | id | <------------+
+------------------+----------+------+---------+-----------+------+-----+----+              |
                                                                          ^^                |
                                                                          ||-----------+    |
                                                                          |            |    |
drafts                                                                    |            |    |
+----+-------+------+---------+------------+--------------+---------+--------------+   |    |
| id | title | body | updated | draft_hash | is_published | created | username: FK |   |    |
+----+-------+------+---------+------------+--------------+---------+--------------+   |    |
  ^                                                                                    |    |
  |----------------------------+              +----------------------------------------+    |
                               |              |                                             |
posts                          |              |                                             |
+------+---------------+--------------+--------------+----+                                 |
| slug | published: DT | draft_id: FK | username: FK | id | <-+                             |
+------+---------------+--------------+--------------+----+   |                             |
                                                       ^      |                             |
                         +-----------------------------|      |                             |
                         |                                    |                             |
association_table        |                                    |                             |
+----+------------+-------------+                             |                             |
| id | tag_id: FK | post_id: FK |                             |                             |
+----+------------+-------------+                             |                             |
                |                                             |                             |
                |                                             |                             |
tags            |                                             |                             |
+----+-----+    |                                             |                             |
| id | tag | <--+                                             |                             |
+----+-----+                                                  |                             |
                                                              |                             |
comments                                                      |                             |
+----+---------+-------------+---------------+---------+-------------+---------------+--------------+
| id | comment | path: LTree | commented: DT | updated | post_id: FK | parent_id: FK | username: FK |
+----+---------+-------------+---------------+---------+-------------+---------------+--------------+
  ^                                                                         |
  |-------------------------------------------------------------------------+

As you can see, data is normalized. Some design considerations of the database design:

  1. Each post's details are stored in the drafts table. This is good because if someone wants to unpublish and edit the post, the is_published columns of the drafts table will be false and there is no need to delete post details and reinsert them into database (if they were stored in posts table separately)
  2. Retrieving the comments is done by using the PostgreSQL feature LTree (which is a very fast, builtin type for hierarchical tree-like data)

Data Layer

The data layer of the application has repositories for different database tables.

  • In each method of the repositories queries are generated using SQLAlchemy query builder functions and methods, to have full control over the generated query and more important database hits.

Authentication

  • SRB uses access and refresh JWT tokens to implement authentication.

    Signing up is a simple username, password flow.

  • 2FA:

    SRB has builtin support for TOTP two-factor authentication using qr-code and authenticator apps like: Google Authenticator

Authorization

Most routes of SRB are protected (i.e. you have to be logged in and provide your access token) However SRB implements different layer of permissions for routes which in short is the ACL. SRB handle the ACL and route access permission with JWT tokens.

For example if I am the superuser or admin of SRB I can delete any user comments with the route that user uses to remove his/her comment. Also, if a users attempts to delete some other user's comment, it is now allowed.

Architecture

SRB is designed as a layered system. There are three layers: Data layer, Service layer and API layer which are fully decoupled. and upper layers are not aware of the details in the lower layers which is achieved with dependency injection.

Requirements

Manual installation:

  • Python 3.10 or higher.
  • Poetry for dependency management.
  • Up and running PostgreSQL instance.
  • Up and running Redis instance.

Setup

1. Clone the repository

git clone https://github.com/mahdihaghverdi/simplerestblog.git

2. Install dependencies

You need to configure Poetry to place the virtual environment in the project directory. To do so, run the following command:

poetry config --local virtualenvs.in-project true

Then, install dependencies:

poetry install

3. Configure environment variables

You can see the table of all environment variables below. Those marked with * are required and MUST be set before running the application. Rest of them are optional and have default values.

Note: To set any of these environment variables below, you MUST prefix them with SRB_ and then set them in your shell or in a .env file placed at the root directory. For example, to set DEBUG environment variable, you can do the following:

export SRB_DEBUG=True

Also note that ALL environment variables are CASE SENSITIVE.

FastAPI Application

Name Description Default Type
API_VERSION API version prefix v1 string
DEBUG Debug mode for development False boolean

PostgreSQL

Name Description Default Type
PG_URL Postgres connection URL postgresql+asyncpg://postgres:[email protected]:5432 string

Redis

Name Description Default Type
REDIS_CACHE_URL Redis instance connection URL redis://@0.0.0.0:6379 string

Authentication

Name Description Default Type
ACCESS_TOKEN_EXPIRE_MINUTES Access token expiration time in minutes 120 (2 hours) integer
REFRESH_TOKEN_EXPIRE_MINUTES Refresh token expiration time in minutes 2880 (2 days) integer
SECRET_KEY* Secret key for signing JWT tokens 64 random characters generated by openssl rand -hex 64 command. string
TFA_EXPIRE_MINUTES TOTP expiration time 15 string

4. Run the application

An up & running PostgreSQL and Redis instance are required.

python -m src

If the SRB_DEBUG environment variable is set to True, the application will be run in debug mode and will be reloaded automatically on code changes.

Now your application is available at http://localhost:8000/.

Documentation and Usage

After running the application, you can access the OpenAPI (Swagger) documentation at /api/v1/docs endpoint.

Stack

Frameworks and technologies used in Shortify

Roadmap

  • Implement a route to unpublish a post
  • Implement a route to delete a post
  • Use Redis for page caching
  • Introduce likes in SRB
  • Implement following and follower machnism
  • Introduce notifications in SRB
    • notif for adding comments and replies
    • notif for likes
    • follow or unfollow

License

This project is licensed under the terms of the GPL-3.0 license.

— ⚡ —

About

Simple but powerful and async blog system RESTful API which has 2FA with JWT and comments of n level replies.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Languages