Skip to content

Commit

Permalink
Fix the docs in several places
Browse files Browse the repository at this point in the history
  • Loading branch information
elliotwaite committed Dec 15, 2023
1 parent 42e426e commit 6b7fa71
Show file tree
Hide file tree
Showing 36 changed files with 392 additions and 384 deletions.
6 changes: 3 additions & 3 deletions docs/about.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# About BlackSheep

BlackSheep is a web framework for Python asyncio designed to facilitate the
implementation of stateless APIs and general purpose web applications. It is
implementation of stateless APIs and general-purpose web applications. It is
inspired by [Flask](https://flask.palletsprojects.com/en/1.1.x/) and [ASP.NET
Core](https://docs.microsoft.com/en-us/aspnet/core/introduction-to-aspnet-core?view=aspnetcore-5.0);
it recreates several features from both these web frameworks. The concept of
automatic binding of request parameters by request handler's signature and
automatic binding of request parameters by the request handler's signature and
dependency injection of required services (as it happens in ASP.NET Core) is
what makes BlackSheep unique today, in the context of Python web frameworks.

The project, as several other web frameworks for Python, is the fruit of the
The project, like several other web frameworks for Python, is the fruit of the
creative ferment around Yury Selivanov’s work, and the article [uvloop: Blazing
fast Python
networking](https://magic.io/blog/uvloop-blazing-fast-python-networking/) from
Expand Down
10 changes: 5 additions & 5 deletions docs/anti-request-forgery.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@ Cross-site request forgery, also known as XSRF or CSRF, is a kind of attack that
exploits situations in which browsers automatically include credentials in web
requests.

Example of such situations are:
Examples of such situations are:

- Cookies are automatically included in web requests, so if an application uses
cookie-based authentication, credentials are sent automatically
- After a user signs in with Basic or Digest authentication, the browser
automatically sends the credentials until the session ends

If a web application uses cookie based authentication or other features that
If a web application uses cookie-based authentication or other features that
cause credentials to be automatically included in web requests, it requires
anti-forgery measures.

BlackSheep implements built-in support for anti request forgery validation, this
BlackSheep implements built-in support for anti-request-forgery validation, this
page describes how to use the built-in solution.

!!! tip
Expand Down Expand Up @@ -115,7 +115,7 @@ forbid iframes.
the objective of the tag is to obtain an input element containing an
anti-forgery token, not to achieve Cross-Site Request Forgery!

An example of rendered view looks like the following:
An example of a rendered view looks like the following:

```html
<!DOCTYPE html>
Expand All @@ -138,7 +138,7 @@ Validation is applied by default to all `DELETE PATCH POST PUT` web requests.
Requests using other methods are not validated as they are not supposed to
change the state and should execute read-only operations.

!!! danger "Important note about tokens generation"
!!! danger "Important note about token generation"
Tokens are signed using symmetric encryption. For your production
environments, configure application secrets using environment variables
as described in [data protection](../dataprotection/).
Expand Down
55 changes: 28 additions & 27 deletions docs/application.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# The Application class
The `Application` class in BlackSheep is responsible of handling the
application life cicle (start, working state, stop), routing, web requests,
exceptions. This page describes details of the `Application` class:
The `Application` class in BlackSheep is responsible for handling the
application life cycle (start, working state, stop), routing, web requests,
and exceptions. This page describes the details of the `Application` class:

- [X] How to handle errors.
- [X] Application events and life cycle.

## Handling errors

BlackSheep catches any unhandled exception that happens during the execution of
request handlers, producing a `HTTP 500 Internal Server Error` response. To see
BlackSheep catches any unhandled exception that happen during the execution of
request handlers, producing an `HTTP 500 Internal Server Error` response. To see
this in practice, start an application like the following:

```python
Expand All @@ -26,7 +26,7 @@ def crash_test():
And observe how a request to its root produces a response with HTTP status 500,
and the text "Internal server error".

Exception details are hidden to the client by default: it would be a security
Exception details are hidden from the client by default: it would be a security
issue if the web application returned error details to the client. However,
while developing and occasionally while investigating issues, it is useful to
be able to obtain error details directly from the web requests that are
Expand All @@ -41,7 +41,7 @@ trace, serving a page like the following:

![Internal server error page](./img/internal-server-error-page.png)

Consider using environmental variables to handle this kind of settings that
Consider using environmental variables to handle these kinds of settings that
can vary across environments. For example:

```python
Expand All @@ -63,11 +63,11 @@ def crash_test():

### Configuring exceptions handlers

The BlackSheep `Application` object has a `exceptions_handlers` dictionary that
defines how errors should be handled. When an exception happens while handling
a web request and reaches the application, the application checks if there is a
matching handler for that kind of exception. An exception handler is defined as
a function with the following signature:
The BlackSheep `Application` object has an `exceptions_handlers` dictionary
that defines how errors should be handled. When an exception happens while
handling a web request and reaches the application, the application checks if
there is a matching handler for that kind of exception. An exception handler is
defined as a function with the following signature:

```python
from blacksheep import Request, Response, text
Expand Down Expand Up @@ -95,14 +95,14 @@ app.exceptions_handlers[CustomException] = exception_handler

@get('/')
async def home(request):
# of course, the exception can be risen at any point
# of course, the exception can be raised at any point
# for example in the business logic layer
raise CustomException()

```

Exceptions inheriting from `HTTPException` can be mapped to handlers by their
type or by their status code, using `int` keys; while user defined exceptions
type or by their status code, using `int` keys; while user-defined exceptions
are mapped to handlers by their type.

When an exception handler is registered for a type of exception, all subclasses
Expand Down Expand Up @@ -139,7 +139,7 @@ from blacksheep.messages import Request

class MyApp(Application):
async def handle_internal_server_error(self, request: Request, exc: Exception):
# TODO: handle this like you wish!
# TODO: handle this as you wish!
return json({"message": "Oh, no!"}, 500)
```

Expand All @@ -149,19 +149,19 @@ class MyApp(Application):

A BlackSheep application exposes three events: **on_start**, **after_start**,
**on_stop**. These events can be used to configure callbacks and services that
depend on application lifecycle. The application class also offers a useful
depend on the application lifecycle. The application class also offers a useful
method to configure objects that need to be initialized when the application
starts, and disposed when the application stops: **lifespan**.
starts, and disposed of when the application stops: **lifespan**.

### Using the lifespan decorator

The `Application.lifespan` method can be used to register objects bound to the
application life cycle. Common examples of such objects are HTTP clients and
database clients, since they use connection pools that can be initialized
and must be disposed when the application stops.
and must be disposed of when the application stops.

The following example illustrates how to use the `@app.lifespan` decorator to
create an HTTP `ClientSession` that will be disposed when the application
create an HTTP `ClientSession` that will be disposed of when the application
stops. Note how the instance of `ClientSession` is also bound to application
services, so that it can be injected into request handlers that need it.

Expand All @@ -183,7 +183,7 @@ async def register_http_client():
app.services.register(ClientSession, instance=client)
yield

print("HTTP client disposed")
print("HTTP client disposed of")


@router.get("/")
Expand All @@ -203,7 +203,8 @@ if __name__ == "__main__":
before the `yield` statement executes when the application starts, and what
is defined after the `yield` statement executes when the application stops.

The following example illustrates how a `redis-py` [connection can be disposed](https://redis.readthedocs.io/en/stable/examples/asyncio_examples.html)
The following example illustrates how a `redis-py` [connection can be disposed
of](https://redis.readthedocs.io/en/stable/examples/asyncio_examples.html)
using the same method:

```python
Expand All @@ -214,7 +215,7 @@ import redis.asyncio as redis
@app.lifespan
async def configure_redis():
"""
Configure an async Redis client, and dispose its connections when the
Configure an async Redis client, and dispose of its connections when the
application stops.
See:
https://redis.readthedocs.io/en/stable/examples/asyncio_examples.html
Expand All @@ -239,8 +240,8 @@ async def configure_redis():
### on_start

This event should be used to configure things such as new request handlers,
and service registered in `app.services`, such as database connection pools,
HTTP client sessions.
and services registered in `app.services`, such as database connection pools,
and HTTP client sessions.

### after_start

Expand All @@ -254,7 +255,7 @@ API specification file at this point.

This event should be used to fire callbacks that need to happen when the application
is stopped. For example, disposing of services that require disposal, such as
database connection pools, HTTP client sessions using connection pools.
database connection pools, and HTTP client sessions using connection pools.

### Application life cycle

Expand All @@ -281,8 +282,8 @@ are fired, and the state of the application when they are executed.


@app.on_start
async def before_start(application: Application) -> None:
print("Before start")
async def on_start(application: Application) -> None:
print("On start")


@app.after_start
Expand Down
8 changes: 4 additions & 4 deletions docs/authentication.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Authentication in BlackSheep
The words _authentication strategy_ in the context of a web application refer
The words "authentication strategy" in the context of a web application refer
to the ability to identify the user who is using the application. BlackSheep
implements a built-in authentication strategy for request handlers. This page
describes:
Expand Down Expand Up @@ -167,7 +167,7 @@ inside **[guardpost](https://github.com/Neoteroi/guardpost)** library.
## Writing a custom authentication handler

The example below shows how to configure a custom authentication handler that
obtains user's identity for each web request.
obtains the user's identity for each web request.

```python
from blacksheep import Application, Request, auth, get, json
Expand Down Expand Up @@ -269,9 +269,9 @@ Gets the output: `{"name":"Jan Kowalski"}`.

_The application has been started on port 44555 (e.g. `uvicorn server:app --port=44555`)._

## Reading user's context
## Reading a user's context

The example below shows how user's identity can be read from the web request:
The example below shows how a user's identity can be read from the web request:

=== "Using binders (recommended)"

Expand Down
20 changes: 10 additions & 10 deletions docs/authorization.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,11 @@ or more requirements to be satisfied in order for authorization to succeed.
The next example explains how to configure an authorization policy that checks
for user's roles from claims.

## Defining an authorization policy that checks user's claims
## Defining an authorization policy that checks a user's claims

The example below shows how to configure an authorization handler that
validates user's claims (looking for a "role" claim that might be coming from a
JWT).
validates a user's claims (looking for a "role" claim that might be coming from
a JWT).

```python
from blacksheep.server.authorization import Policy
Expand Down Expand Up @@ -200,9 +200,9 @@ async def only_for_administrators():
## Using the default policy

The method `app.use_authorization()`, when used without arguments, returns an
instance of `AuthorizationStrategy` from `guardpost` library. This object can
be configured to use a default policy, for example to require an authenticated
user by default for all request handlers.
instance of `AuthorizationStrategy` from the `guardpost` library. This object
can be configured to use a default policy, for example to require an
authenticated user by default for all request handlers.

```python
authorization = app.use_authorization()
Expand Down Expand Up @@ -232,10 +232,10 @@ async def for_anybody(user: Optional[User]):
## Specifying authentication schemes for request handlers

In some scenarios it is necessary to specify multiple authentication schemes
for web applications: for example the same application might handle authentication
obtained through `GitHub` OAuth app and `Azure Active Directory (AAD)`.
In such scenarios, it might be necessary to restrict access to some endpoints
by authentication method, too.
for web applications: for example, the same application might handle
authentication obtained through the `GitHub` OAuth app and `Azure Active
Directory (AAD)`. In such scenarios, it might be necessary to restrict access
to some endpoints by authentication method, too.

To do so:

Expand Down
10 changes: 5 additions & 5 deletions docs/background-tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ This page describes how to start background tasks in request handlers, and how
to configure background tasks that run periodically during the application's
lifetime.

## How to handle a request in background
## How to handle a request in the background

The following example shows how to handle a web request in background, which
is the use case for the [HTTP 202 Accepted](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/202)
The following example shows how to handle a web request in the background,
which is the use case for the [HTTP 202 Accepted](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/202)
response status code.

```python
Expand Down Expand Up @@ -35,7 +35,7 @@ def home() -> Response:

## How to configure background tasks

The following example shows how to configure a background tasks, including
The following example shows how to configure a background task, including
the activation of a service resolved by the DI container, running periodically
once every second:

Expand Down Expand Up @@ -64,7 +64,7 @@ class Foo:

async def task_example(app: Application) -> None:
# example background task, running once every second,
# this example also shows how to activate a service using the CI container
# this example also shows how to activate a service using the DI container
while True:
print(get_current_timestamp())

Expand Down
Loading

0 comments on commit 6b7fa71

Please sign in to comment.