Skip to content
This repository has been archived by the owner on Sep 12, 2023. It is now read-only.

Commit

Permalink
docs: tidy up.
Browse files Browse the repository at this point in the history
  • Loading branch information
peterschutt committed Nov 7, 2022
1 parent b1cc226 commit e524edf
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 56 deletions.
35 changes: 18 additions & 17 deletions .env.example
Expand Up @@ -6,23 +6,27 @@ NAME=my-starlite-app

# API
API_CACHE_EXPIRATION=60
API_DB_SESSION_DEPENDENCY_KEY=db_session
API_DEFAULT_PAGINATION_LIMIT=100
API_DTO_INFO_KEY=dto
API_HEALTH_PATH=/health
API_DB_SESSION_DEPENDENCY_KEY=db_session

# Log
LOG_EXCLUDE_PATHS="\A(?!x)x"
LOG_HTTP_EVENT="HTTP"
LOG_LEVEL=20
LOG_OBFUSCATE_COOKIES='["session"]'
LOG_OBFUSCATE_HEADERS='["Authorization","X-API-KEY"]'
LOG_REQUEST_FIELDS='["path","method","content_type","headers","cookies","query","path_params","body"]'
LOG_RESPONSE_FIELDS='["status_code","cookies","headers","body"]'
LOG_WORKER_EVENT="Worker"

# OpenAPI
OPENAPI_CONTACT_EMAIL=some_human@email.com
OPENAPI_CONTACT_NAME="Some Human"
OPENAPI_TITLE="My Starlite App"
OPENAPI_VERSION=1.0.0

# Sentry
SENTRY_DSN=
SENTRY_TRACES_SAMPLE_RATE=0.0001

# Redis
REDIS_URL=redis://cache.local:6379/0

# Database
DB_ECHO=false
DB_ECHO_POOL=false
Expand All @@ -32,12 +36,9 @@ DB_POOL_SIZE=5
DB_POOL_TIMEOUT=30
DB_URL=postgresql+asyncpg://postgres:mysecretpassword@pg.db.local:5432/db

# Log
LOG_EXCLUDE_PATHS="\A(?!x)x"
LOG_OBFUSCATE_COOKIES=["session"]
LOG_OBFUSCATE_HEADERS=["Authorization", "X-API-KEY"]
LOG_REQUEST_FIELDS=["path","method","content_type","headers","cookies","query","path_params","body"]
LOG_RESPONSE_FIELDS=["status_code","cookies","headers","body",]
LOG_HTTP_EVENT="HTTP"
LOG_WORKER_EVENT="Worker"
LOG_LEVEL=20
# Redis
REDIS_URL=redis://cache.local:6379/0

# Sentry
SENTRY_DSN=
SENTRY_TRACES_SAMPLE_RATE=0.0001
16 changes: 15 additions & 1 deletion docs/config.md
@@ -1,6 +1,20 @@
# Configuring the application

Configuration is via environment. Here's an example `.env`:
Configuration is via environment.

## Minimal `.env`

```dotenv title="Minimal .env"
NAME=tmpl-starlite-saqlalchemy
DB_URL=postgresql+asyncpg://postgres:mysecretpassword@localhost:5432/postgres1
OPENAPI_CONTACT_EMAIL=peter.github@proton.me
OPENAPI_CONTACT_NAME="Peter Schutt"
OPENAPI_TITLE="Template starlite-saqlalchemy Application"
OPENAPI_VERSION=1.0.0
REDIS_URL=redis://localhost:6379/0
```

## Full `.env`

```dotenv title="Example .env"
--8<-- ".env.example"
Expand Down
36 changes: 16 additions & 20 deletions docs/dto.md
@@ -1,9 +1,5 @@
# DTOs

- pydantic models generated from SQLAlchemy declarative models.
- DTOs have a purpose, read or write.
- Model attributes can have a mode, read-only or private.

## What are DTOs?

DTO stands for "Data Transfer Object". They are the filter through which data is accepted into, and
Expand All @@ -25,14 +21,14 @@ found there - a credit to everyone who has contributed to that project over the

### Configuring generated DTOs

#### DTO Purpose
#### dto.Purpose

The `dto.Purpose` enum tells the factory if the purpose of the DTO is parse data submitted by the
The `dto.Purpose` enum tells the factory if the purpose of the DTO is to parse data submitted by the
client for updating or "writing" to a resource, or if it is to serialize data to be transmitted back
to, or "read" by the client.

For example, the DTO objects generated by the factory may differ due to the intended purpose of the
DTO:
The DTO objects generated by the factory may differ due to the intended purpose of the DTO. Here's
an example of setting the DTO purpose:

```python
from starlite_saqlalchemy import dto
Expand All @@ -44,28 +40,29 @@ ReadDTO = dto.factory("UserReadDTO", model=User, purpose=dto.Purpose.READ)
WriteDTO = dto.factory("UserWriteDTO", model=User, purpose=dto.Purpose.WRITE)
```

#### DTO Attrib
#### dto.Attrib

The `dto.Attrib` object is a container for configuration of how the generated DTO object should
reflect the SQLAlchemy model field.
The `dto.Attrib` object is a container for configuring how the generated DTO object should reflect
the SQLAlchemy model field.

Define this in the SQLAlchemy `info` parameter to `mapped_column()`, for example,
`mapped_column(info={"dto": dto.Attrib()})`.

The DTO Attrib object has two values that can be set:

- `dto.Attrib.mark`: a value of the enum [`dto.Mark`][DTO-mark].
- `dto.Attrib.pydantic_field`: return value of the pydantic `Field` function that will be used to
construct the pydantic model.
- `dto.Attrib.mark`: a value of the enum [`dto.Mark`](.. /reference/starlite_saqlalchemy/dto/#Mark).
- `dto.Attrib.pydantic_field`: return value of the pydantic
[`Field`](https://pydantic-docs.helpmanual.io/usage/schema/#field-customization) function that
will be used to construct the pydantic model field for the model attribute.

#### DTO Mark
#### dto.Mark

We use the `info` parameter to `mapped_column()` to guide `dto.factory()`.

The [dto.Mark](../reference/starlite_saqlalchemy/dto/#Mark) enumeration is used to indicate on the
SQLAlchemy ORM model, whether properties should always be private, or read-only.
whether properties on the SQLAlchemy model should always be private, or read-only.

Take this model, for example:
For example:

```python
from datetime import datetime
Expand All @@ -89,9 +86,8 @@ WriteDTO = dto.factory("UserWriteDTO", model=User, purpose=dto.Purpose.WRITE)
Both `ReadDTO` and `WriteDTO` are pydantic models that have a `name` attribute.

Neither `ReadDTO` or `WriteDTO` have a `password_hash` attribute - this is the side effect of
marking the column with `dto.Mark.PRIVATE`. Columns that are marked private will never be included
in any generated DTO model, meaning that in the context of the application, they are unable to be
read or modified by the client.
marking the column with `dto.Mark.SKIP`. Skipped columns are never included in any generated DTO
model, meaning that they are unable to be read or modified by the client.

`ReadDTO` has an `updated_at` field, while `WriteDTO` does not. This is the side effect of marking
the column with `dto.Mark.READ_ONLY` - these fields will only be included in DTOs generated for
Expand Down
15 changes: 6 additions & 9 deletions docs/index.md
Expand Up @@ -17,12 +17,10 @@ An API application pattern standing on the shoulders of:
--8<-- "examples/basic_example.py"
```

Check out the [Usage](config/) section to see everything that is enabled by the framework!
Check out the [Usage](config/) section to see all the features this configures on the application!

## Pattern

This is the pattern encouraged by this framework:

``` mermaid
sequenceDiagram
Client ->> Controller: Inbound request data
Expand All @@ -47,16 +45,15 @@ sequenceDiagram

## Motivation

A modern, production-ready API application has a lot of components. Starlite, the backbone of this
library, exposes a plethora of features and functionality that requires some amount of boilerplate
and configuration that must be carried from one implementation of an application to
the next.
A modern, production-ready API has a lot of components. Starlite, the backbone of this library,
exposes a plethora of features and functionality that requires some amount of boilerplate and
configuration that must be carried from one implementation of an application to the next.

`starlite-saqlalchemy` is an example of how Starlite's `on_app_init` hook can be utilized to build
application configuration libraries that support streamlining the application development process.

However, this library intends to be not only an example, but also an opinionated resource to support
the efficient, and consistent rollout of production ready API applications built on top of Starlite.
However, more than just an example, this library intends to be an opinionated resource to support
the efficient, and consistent rollout of production ready APIs built on top of Starlite.

Use this library if the stack and design decisions suit your taste. If there are improvements or
generalizations that could be made to the library to support your use case, we'd love to hear about
Expand Down
2 changes: 1 addition & 1 deletion docs/logging.md
Expand Up @@ -6,7 +6,7 @@ single log line per request or async worker invocation).

The pattern is built upon the excellent [`structlog`](https://github.com/hynek/structlog) library,
and is configured to be as efficient as possible while not blocking the event loop (it runs the
logging in a processor thread, off the event loop).
logging in a processor thread).

## Adding data to the log

Expand Down
16 changes: 8 additions & 8 deletions src/starlite_saqlalchemy/settings.py
Expand Up @@ -75,6 +75,10 @@ class Config:
# https://stackoverflow.com/a/1845097/6560549
EXCLUDE_PATHS: str = r"\A(?!x)x"
"""Regex to exclude paths from logging."""
HTTP_EVENT: str = "HTTP"
"""Log event name for logs from Starlite handlers."""
LEVEL: int = 20
"""Stdlib log levels. Only emit logs at this level, or higher."""
OBFUSCATE_COOKIES: set[str] = {"session"}
"""Request cookie keys to obfuscate."""
OBFUSCATE_HEADERS: set[str] = {"Authorization", "X-API-KEY"}
Expand Down Expand Up @@ -112,12 +116,8 @@ class Config:
"body",
]
"""Attributes of the [Response][starlite.response.Response] to be logged."""
HTTP_EVENT: str = "HTTP"
"""Log event name for logs from Starlite handlers."""
WORKER_EVENT: str = "Worker"
"""Log event name for logs from SAQ worker."""
LEVEL: int = 20
"""Stdlib log levels. Only emit logs at this level, or higher."""


# noinspection PyUnresolvedReferences
Expand All @@ -132,14 +132,14 @@ class Config:
env_prefix = "OPENAPI_"
case_sensitive = True

TITLE: str | None
"""Document title."""
VERSION: str
"""Document version."""
CONTACT_NAME: str
"""Name of contact on document."""
CONTACT_EMAIL: str
"""Email for contact on document."""
TITLE: str | None
"""Document title."""
VERSION: str
"""Document version."""


# noinspection PyUnresolvedReferences
Expand Down

0 comments on commit e524edf

Please sign in to comment.