Compare commits
20 Commits
7067c77714
...
docker
| Author | SHA1 | Date | |
|---|---|---|---|
| 42f8df2589 | |||
|
|
90f5451ff8 | ||
|
|
2e229ceadd | ||
|
|
32615bf615 | ||
|
|
7de5efab3f | ||
|
|
6fbd717868 | ||
|
|
6be588aa58 | ||
|
|
01a3efd424 | ||
|
|
38943392c2 | ||
|
|
78f6dcb356 | ||
|
|
ad45fd4ee2 | ||
|
|
a2aed1117f | ||
|
|
6cf2b3c3ef | ||
|
|
a5812354c2 | ||
|
|
aa3957945c | ||
|
|
729e73bae8 | ||
| d91d177fa9 | |||
| fa455aaa33 | |||
| b8e9dc2ae7 | |||
| 2ee6a1aba3 |
274
Docs/Libs/Docker/01-Setup.md
Normal file
274
Docs/Libs/Docker/01-Setup.md
Normal file
@@ -0,0 +1,274 @@
|
|||||||
|
# Docker SDK for Python – Setup and First Steps
|
||||||
|
|
||||||
|
This document introduces the **Docker SDK for Python (`docker` library)** and explains how to connect to the Docker Engine, inspect its status, and authenticate with a registry. The goal is not just to show code, but to clearly explain **what each part does, why it exists, and when you would use it**.
|
||||||
|
|
||||||
|
This guide assumes you already understand basic Docker concepts (images, containers, daemon) and are approaching this from a DevOps perspective.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Installing the Docker SDK for Python
|
||||||
|
|
||||||
|
Before Python can communicate with Docker, we need to install the official SDK.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install docker
|
||||||
|
```
|
||||||
|
|
||||||
|
### What this does
|
||||||
|
|
||||||
|
* Installs the **docker** Python package (often called *docker-py*).
|
||||||
|
* This package acts as a **client wrapper** around Docker’s REST API.
|
||||||
|
* All interactions ultimately talk to the Docker daemon (`dockerd`) over a socket or TCP connection.
|
||||||
|
|
||||||
|
Important note:
|
||||||
|
|
||||||
|
* Installing the library alone is not enough.
|
||||||
|
* Docker **must already be installed and running** on the system.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Connecting to Docker Using Environment Configuration
|
||||||
|
|
||||||
|
The simplest and most common way to create a Docker client is by using environment-based configuration.
|
||||||
|
|
||||||
|
```python
|
||||||
|
import docker
|
||||||
|
|
||||||
|
client = docker.from_env()
|
||||||
|
version = client.version()
|
||||||
|
ping_docker = client.ping()
|
||||||
|
|
||||||
|
print(version, ping_docker)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step-by-step explanation
|
||||||
|
|
||||||
|
#### `import docker`
|
||||||
|
|
||||||
|
* Imports the Docker SDK.
|
||||||
|
* This module exposes high-level objects for interacting with Docker resources.
|
||||||
|
|
||||||
|
#### `docker.from_env()`
|
||||||
|
|
||||||
|
* Automatically creates a `DockerClient` instance.
|
||||||
|
* Reads Docker connection details from environment variables such as:
|
||||||
|
|
||||||
|
* `DOCKER_HOST`
|
||||||
|
* `DOCKER_TLS_VERIFY`
|
||||||
|
* `DOCKER_CERT_PATH`
|
||||||
|
* On Linux, this usually resolves to:
|
||||||
|
|
||||||
|
* `unix:///var/run/docker.sock`
|
||||||
|
|
||||||
|
This is why `from_env()` is preferred:
|
||||||
|
|
||||||
|
* Works across Linux, macOS, Windows, and CI systems
|
||||||
|
* Requires no hardcoded connection strings
|
||||||
|
|
||||||
|
#### `client.version()`
|
||||||
|
|
||||||
|
* Calls the Docker Engine `/version` API endpoint.
|
||||||
|
* Returns detailed metadata such as:
|
||||||
|
|
||||||
|
* Docker Engine version
|
||||||
|
* API version
|
||||||
|
* Go version
|
||||||
|
* OS and architecture
|
||||||
|
|
||||||
|
This is commonly used for:
|
||||||
|
|
||||||
|
* Debugging
|
||||||
|
* Compatibility checks
|
||||||
|
* Logging runtime environment details
|
||||||
|
|
||||||
|
#### `client.ping()`
|
||||||
|
|
||||||
|
* Sends a lightweight request to the Docker daemon.
|
||||||
|
* Returns `True` if Docker is reachable and responsive.
|
||||||
|
|
||||||
|
This is a **health check**, often used in:
|
||||||
|
|
||||||
|
* Startup validation
|
||||||
|
* Monitoring scripts
|
||||||
|
* CI/CD pipelines
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. What Does “from_env” Actually Mean?
|
||||||
|
|
||||||
|
Using `from_env()` tells the SDK:
|
||||||
|
|
||||||
|
> “Figure out how to connect to Docker using the same configuration the Docker CLI uses.”
|
||||||
|
|
||||||
|
Behind the scenes, it:
|
||||||
|
|
||||||
|
* Detects whether Docker is local or remote
|
||||||
|
* Determines socket vs TCP
|
||||||
|
* Applies TLS settings if required
|
||||||
|
|
||||||
|
### When should you use it?
|
||||||
|
|
||||||
|
* Local development
|
||||||
|
* Kubernetes nodes
|
||||||
|
* CI runners
|
||||||
|
* Most production automation
|
||||||
|
|
||||||
|
### When not to use it?
|
||||||
|
|
||||||
|
* When you need explicit control over connection parameters
|
||||||
|
* When connecting to a **remote Docker daemon** with custom networking
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Creating a Docker Client Explicitly
|
||||||
|
|
||||||
|
Instead of relying on environment detection, you can create a client manually.
|
||||||
|
|
||||||
|
```python
|
||||||
|
import docker
|
||||||
|
|
||||||
|
client = docker.DockerClient(base_url='unix://var/run/docker.sock')
|
||||||
|
version = client.version()
|
||||||
|
ping_docker = client.ping()
|
||||||
|
|
||||||
|
print(version, ping_docker)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Explanation
|
||||||
|
|
||||||
|
#### `docker.DockerClient(...)`
|
||||||
|
|
||||||
|
* Directly instantiates a Docker client object.
|
||||||
|
* Requires you to specify how to reach the Docker daemon.
|
||||||
|
|
||||||
|
#### `base_url='unix://var/run/docker.sock'`
|
||||||
|
|
||||||
|
* Points to the Unix socket used by Docker on Linux systems.
|
||||||
|
* This socket is owned by root and the `docker` group.
|
||||||
|
|
||||||
|
Important implications:
|
||||||
|
|
||||||
|
* Your Python process must have permission to access the socket
|
||||||
|
* Usually means running as root or a user in the `docker` group
|
||||||
|
|
||||||
|
### When this approach is useful
|
||||||
|
|
||||||
|
* Controlled environments
|
||||||
|
* Educational examples
|
||||||
|
* Explicit infrastructure scripts
|
||||||
|
|
||||||
|
### Why it is less common
|
||||||
|
|
||||||
|
* Not portable across OSes
|
||||||
|
* Hardcodes infrastructure assumptions
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Inspecting Docker and Authenticating
|
||||||
|
|
||||||
|
Once connected, the client can retrieve detailed system information and authenticate with registries.
|
||||||
|
|
||||||
|
```python
|
||||||
|
import docker
|
||||||
|
|
||||||
|
client = docker.DockerClient(base_url='unix://var/run/docker.sock')
|
||||||
|
version = client.version()
|
||||||
|
ping_docker = client.ping()
|
||||||
|
information = client.info()
|
||||||
|
|
||||||
|
client.login(
|
||||||
|
username='user',
|
||||||
|
password='password',
|
||||||
|
registry='registry_link'
|
||||||
|
)
|
||||||
|
|
||||||
|
print(information, ping_docker)
|
||||||
|
```
|
||||||
|
|
||||||
|
### `client.info()`
|
||||||
|
|
||||||
|
* Calls the Docker `/info` endpoint.
|
||||||
|
* Returns a comprehensive snapshot of the Docker host, including:
|
||||||
|
|
||||||
|
* Number of containers (running/stopped)
|
||||||
|
* Number of images
|
||||||
|
* Storage driver
|
||||||
|
* Cgroup and kernel features
|
||||||
|
* Security options (AppArmor, seccomp)
|
||||||
|
|
||||||
|
This is extremely valuable for:
|
||||||
|
|
||||||
|
* Capacity planning
|
||||||
|
* Debugging runtime issues
|
||||||
|
* Auditing host configuration
|
||||||
|
|
||||||
|
### `client.login(...)`
|
||||||
|
|
||||||
|
* Authenticates Docker with a container registry.
|
||||||
|
* Stores credentials in Docker’s credential store.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
|
||||||
|
* `username`: registry account username
|
||||||
|
* `password`: registry password or access token
|
||||||
|
* `registry`: registry URL (e.g. Docker Hub or private registry)
|
||||||
|
|
||||||
|
Common use cases:
|
||||||
|
|
||||||
|
* Pulling private images
|
||||||
|
* Pushing images in CI/CD pipelines
|
||||||
|
* Automating registry interactions
|
||||||
|
|
||||||
|
Security note:
|
||||||
|
|
||||||
|
* Avoid hardcoding credentials in source code
|
||||||
|
* Prefer environment variables or secret managers
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. High-Level vs Low-Level API (Important Concept)
|
||||||
|
|
||||||
|
What you are using here is the **high-level Docker client**.
|
||||||
|
|
||||||
|
Characteristics:
|
||||||
|
|
||||||
|
* Pythonic object model
|
||||||
|
* Resource-oriented (containers, images, networks)
|
||||||
|
* Easier to read and maintain
|
||||||
|
|
||||||
|
The SDK also exposes a **low-level API**:
|
||||||
|
|
||||||
|
* Direct access to Docker REST endpoints
|
||||||
|
* More control, less abstraction
|
||||||
|
|
||||||
|
As a DevOps engineer, you will typically:
|
||||||
|
|
||||||
|
* Use high-level API for automation
|
||||||
|
* Drop to low-level API for advanced edge cases
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Summary
|
||||||
|
|
||||||
|
In this setup phase, you learned how to:
|
||||||
|
|
||||||
|
* Install the Docker SDK for Python
|
||||||
|
* Connect to Docker using environment-based configuration
|
||||||
|
* Explicitly define Docker connection settings
|
||||||
|
* Verify Docker availability
|
||||||
|
* Retrieve system-level Docker information
|
||||||
|
* Authenticate with container registries
|
||||||
|
|
||||||
|
This foundation is critical before moving on to:
|
||||||
|
|
||||||
|
* Managing containers
|
||||||
|
* Building images
|
||||||
|
* Working with volumes and networks
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
Official Docker SDK for Python documentation:
|
||||||
|
|
||||||
|
* [https://docker-py.readthedocs.io/](https://docker-py.readthedocs.io/)
|
||||||
360
Docs/Libs/Docker/02-Images.md
Normal file
360
Docs/Libs/Docker/02-Images.md
Normal file
@@ -0,0 +1,360 @@
|
|||||||
|
# Docker SDK for Python – Working with Images
|
||||||
|
|
||||||
|
This document explains how to **manage Docker images** using the Docker SDK for Python. Instead of treating the SDK as a set of function calls, we’ll approach images the same way Docker itself does: as immutable artifacts that are pulled, built, tagged, pushed, inspected, and eventually cleaned up.
|
||||||
|
|
||||||
|
All examples assume:
|
||||||
|
|
||||||
|
* Docker is installed and running
|
||||||
|
* The Python process has access to the Docker socket
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Creating the Docker Client
|
||||||
|
|
||||||
|
```python
|
||||||
|
import docker
|
||||||
|
|
||||||
|
client = docker.DockerClient(base_url='unix://var/run/docker.sock')
|
||||||
|
ping_docker = client.ping()
|
||||||
|
```
|
||||||
|
|
||||||
|
### Explanation
|
||||||
|
|
||||||
|
* `DockerClient` establishes a connection to the Docker daemon.
|
||||||
|
* `ping()` verifies that Docker is reachable before doing any real work.
|
||||||
|
|
||||||
|
This is a common pattern in automation:
|
||||||
|
|
||||||
|
* Fail fast if Docker is unavailable
|
||||||
|
* Avoid partial execution later in the script
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Pulling Images from a Registry
|
||||||
|
|
||||||
|
```python
|
||||||
|
def pull_image(name_image, tag_image):
|
||||||
|
image = client.images.pull(name_image, tag=tag_image)
|
||||||
|
print(image)
|
||||||
|
```
|
||||||
|
|
||||||
|
### What this does
|
||||||
|
|
||||||
|
* Downloads an image from a registry (Docker Hub or private registry).
|
||||||
|
* If the image already exists locally, Docker may reuse layers.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
|
||||||
|
* `name_image`: repository name (e.g. `alpine`, `nginx`, `myrepo/app`)
|
||||||
|
* `tag_image`: specific version or variant (e.g. `3.20`, `latest`)
|
||||||
|
|
||||||
|
Returned value:
|
||||||
|
|
||||||
|
* An `Image` object representing the pulled image
|
||||||
|
|
||||||
|
Why this matters:
|
||||||
|
|
||||||
|
* Pulling explicitly avoids relying on implicit image downloads
|
||||||
|
* Makes automation predictable and repeatable
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Building Images from a Dockerfile
|
||||||
|
|
||||||
|
### Basic build
|
||||||
|
|
||||||
|
```python
|
||||||
|
def build_image():
|
||||||
|
image, logs = client.images.build(
|
||||||
|
path=".",
|
||||||
|
tag="myapp:1.0"
|
||||||
|
)
|
||||||
|
|
||||||
|
for log in logs:
|
||||||
|
if "stream" in log:
|
||||||
|
print(log["stream"].strip())
|
||||||
|
```
|
||||||
|
|
||||||
|
### Explanation
|
||||||
|
|
||||||
|
* `path="."` tells Docker to use the current directory as the build context.
|
||||||
|
* Docker automatically looks for a file named `Dockerfile`.
|
||||||
|
* `tag="myapp:1.0"` assigns a name and version to the resulting image.
|
||||||
|
|
||||||
|
The build process returns:
|
||||||
|
|
||||||
|
* `image`: the final built image object
|
||||||
|
* `logs`: a stream of build output messages
|
||||||
|
|
||||||
|
Printing build logs is important because:
|
||||||
|
|
||||||
|
* Docker build failures are only visible in logs
|
||||||
|
* CI pipelines rely on this output for debugging
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Advanced Build with Custom Dockerfile and Build Arguments
|
||||||
|
|
||||||
|
```python
|
||||||
|
def build_image_2():
|
||||||
|
image, logs = client.images.build(
|
||||||
|
path=".",
|
||||||
|
dockerfile="Dockerfile.prod",
|
||||||
|
tag="myapp:prod",
|
||||||
|
buildargs={
|
||||||
|
"APP_ENV": "production",
|
||||||
|
"VERSION": "1.0.0"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Explanation
|
||||||
|
|
||||||
|
This version adds more control:
|
||||||
|
|
||||||
|
* `dockerfile="Dockerfile.prod"`
|
||||||
|
|
||||||
|
* Allows multiple Dockerfiles per project
|
||||||
|
* Common for dev vs prod builds
|
||||||
|
|
||||||
|
* `buildargs`
|
||||||
|
|
||||||
|
* Passed to `ARG` instructions inside the Dockerfile
|
||||||
|
* Enables parameterized builds without editing the Dockerfile
|
||||||
|
|
||||||
|
Typical DevOps use cases:
|
||||||
|
|
||||||
|
* Environment-specific builds
|
||||||
|
* Injecting version numbers
|
||||||
|
* Feature flags during build time
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Tagging Images
|
||||||
|
|
||||||
|
```python
|
||||||
|
def tag_image():
|
||||||
|
image = client.images.get("myapp:1.0")
|
||||||
|
image.tag("myrepo/myapp", tag="latest")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Explanation
|
||||||
|
|
||||||
|
* Docker images are immutable, but tags are not.
|
||||||
|
* This creates an additional reference to the same image ID.
|
||||||
|
|
||||||
|
Why tagging is important:
|
||||||
|
|
||||||
|
* One image can have multiple tags
|
||||||
|
* Tags represent lifecycle stages (`1.0`, `prod`, `latest`)
|
||||||
|
|
||||||
|
This is how promotion pipelines work:
|
||||||
|
|
||||||
|
* Build once
|
||||||
|
* Tag many times
|
||||||
|
* Push selectively
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Removing Images
|
||||||
|
|
||||||
|
```python
|
||||||
|
def remove_image():
|
||||||
|
client.images.remove("myapp:1.0", force=True)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Explanation
|
||||||
|
|
||||||
|
* Removes the image reference from the local Docker host.
|
||||||
|
* `force=True` removes the image even if it is in use by stopped containers.
|
||||||
|
|
||||||
|
Use with care:
|
||||||
|
|
||||||
|
* Running containers still prevent deletion
|
||||||
|
* Forced removal is destructive
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Pushing Images to a Registry
|
||||||
|
|
||||||
|
```python
|
||||||
|
def push_image():
|
||||||
|
client.images.push(
|
||||||
|
repository="myrepo/myapp",
|
||||||
|
tag="latest"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Explanation
|
||||||
|
|
||||||
|
* Uploads the image layers to a registry.
|
||||||
|
* Requires prior authentication (`client.login`).
|
||||||
|
|
||||||
|
Important notes:
|
||||||
|
|
||||||
|
* Only new or changed layers are pushed
|
||||||
|
* Tags determine what remote users pull
|
||||||
|
|
||||||
|
This step is usually automated in:
|
||||||
|
|
||||||
|
* CI/CD pipelines
|
||||||
|
* Release workflows
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Cleaning Up Unused Images
|
||||||
|
|
||||||
|
```python
|
||||||
|
def prune_images():
|
||||||
|
result = client.images.prune()
|
||||||
|
print(result)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Explanation
|
||||||
|
|
||||||
|
* Removes dangling images (untagged and unused).
|
||||||
|
* Helps reclaim disk space on build servers.
|
||||||
|
|
||||||
|
The result includes:
|
||||||
|
|
||||||
|
* Number of images removed
|
||||||
|
* Amount of disk space freed
|
||||||
|
|
||||||
|
This is essential for:
|
||||||
|
|
||||||
|
* CI runners
|
||||||
|
* Long-lived build machines
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Inspecting Image Metadata
|
||||||
|
|
||||||
|
```python
|
||||||
|
def inspect_image():
|
||||||
|
alpine_image = client.images.get("alpine:3.20")
|
||||||
|
|
||||||
|
print(alpine_image.attrs)
|
||||||
|
print(alpine_image.attrs["Id"])
|
||||||
|
print(alpine_image.attrs["Size"])
|
||||||
|
print(alpine_image.attrs["Config"]["Env"])
|
||||||
|
print(alpine_image.attrs["Config"]["Cmd"])
|
||||||
|
```
|
||||||
|
|
||||||
|
### Explanation
|
||||||
|
|
||||||
|
* `attrs` exposes the raw Docker image inspection data.
|
||||||
|
* This is equivalent to `docker image inspect`.
|
||||||
|
|
||||||
|
Useful fields:
|
||||||
|
|
||||||
|
* `Id`: content-addressable image hash
|
||||||
|
* `Size`: image size in bytes
|
||||||
|
* `Config.Env`: environment variables baked into the image
|
||||||
|
* `Config.Cmd`: default command
|
||||||
|
|
||||||
|
This information is often used for:
|
||||||
|
|
||||||
|
* Debugging unexpected behavior
|
||||||
|
* Auditing images
|
||||||
|
* Validating build output
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. Listing Local Images
|
||||||
|
|
||||||
|
```python
|
||||||
|
def image_list():
|
||||||
|
images = client.images.list()
|
||||||
|
for item in images:
|
||||||
|
print(item.id, item.tags)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Explanation
|
||||||
|
|
||||||
|
* Lists all images stored locally.
|
||||||
|
* Each image may have multiple tags or none.
|
||||||
|
|
||||||
|
This mirrors:
|
||||||
|
|
||||||
|
* `docker images`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. Ensuring an Image Exists
|
||||||
|
|
||||||
|
```python
|
||||||
|
def ensure_image(name):
|
||||||
|
try:
|
||||||
|
client.images.get(name)
|
||||||
|
print(f"{name} exists")
|
||||||
|
except docker.errors.ImageNotFound:
|
||||||
|
print(f"Pulling {name}")
|
||||||
|
client.images.pull(name)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Explanation
|
||||||
|
|
||||||
|
This is a very common DevOps pattern:
|
||||||
|
|
||||||
|
* Check if the image exists locally
|
||||||
|
* Pull it only if necessary
|
||||||
|
|
||||||
|
Benefits:
|
||||||
|
|
||||||
|
* Avoids unnecessary network calls
|
||||||
|
* Makes scripts idempotent
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. Important Exceptions to Know
|
||||||
|
|
||||||
|
When working with images, you must handle failures explicitly.
|
||||||
|
|
||||||
|
### `docker.errors.ImageNotFound`
|
||||||
|
|
||||||
|
* Raised when an image does not exist locally
|
||||||
|
* Common when calling `get()`
|
||||||
|
|
||||||
|
### `docker.errors.BuildError`
|
||||||
|
|
||||||
|
* Raised when an image build fails
|
||||||
|
* Usually due to Dockerfile errors or missing files
|
||||||
|
|
||||||
|
### `docker.errors.APIError`
|
||||||
|
|
||||||
|
* Raised for general Docker API failures
|
||||||
|
* Includes permission issues, daemon errors, and network problems
|
||||||
|
|
||||||
|
Catching these exceptions is critical for:
|
||||||
|
|
||||||
|
* Reliable automation
|
||||||
|
* Meaningful error reporting
|
||||||
|
* CI/CD stability
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 13. Summary
|
||||||
|
|
||||||
|
In this section, you learned how to:
|
||||||
|
|
||||||
|
* Pull images from registries
|
||||||
|
* Build images using Dockerfiles
|
||||||
|
* Use build arguments and multiple Dockerfiles
|
||||||
|
* Tag and push images
|
||||||
|
* Inspect and list images
|
||||||
|
* Clean up unused images
|
||||||
|
* Handle common Docker image errors
|
||||||
|
|
||||||
|
This image workflow is the backbone of:
|
||||||
|
|
||||||
|
* CI pipelines
|
||||||
|
* Release automation
|
||||||
|
* Platform engineering systems
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
Official Docker SDK for Python documentation:
|
||||||
|
|
||||||
|
* [https://docker-py.readthedocs.io/](https://docker-py.readthedocs.io/)
|
||||||
284
Docs/Libs/Docker/03-Containers.md
Normal file
284
Docs/Libs/Docker/03-Containers.md
Normal file
@@ -0,0 +1,284 @@
|
|||||||
|
# Docker SDK for Python – Working with Containers
|
||||||
|
|
||||||
|
This document explains how to **manage Docker containers** using the Docker SDK for Python. Containers are the runtime unit of Docker, so this section focuses on lifecycle management: listing, creating, running, starting, stopping, restarting, pausing, and inspecting logs.
|
||||||
|
|
||||||
|
The goal is to understand **how container state changes**, how the Python SDK maps to Docker CLI behavior, and how these operations are typically used in real DevOps automation.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Creating the Docker Client
|
||||||
|
|
||||||
|
```python
|
||||||
|
import docker
|
||||||
|
import time
|
||||||
|
|
||||||
|
client = docker.DockerClient(base_url='unix://var/run/docker.sock')
|
||||||
|
ping_docker = client.ping()
|
||||||
|
```
|
||||||
|
|
||||||
|
### Explanation
|
||||||
|
|
||||||
|
* Establishes a connection to the Docker daemon via the Unix socket.
|
||||||
|
* `ping()` is used as a sanity check before executing container operations.
|
||||||
|
|
||||||
|
In production-grade scripts, this check prevents:
|
||||||
|
|
||||||
|
* Silent failures
|
||||||
|
* Partial execution when Docker is down
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Listing Running Containers
|
||||||
|
|
||||||
|
```python
|
||||||
|
def get_containers_list():
|
||||||
|
containers = client.containers.list()
|
||||||
|
|
||||||
|
for c in containers:
|
||||||
|
print(c.id, c.name, c.status)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Explanation
|
||||||
|
|
||||||
|
* `containers.list()` returns **only running containers** by default.
|
||||||
|
* Each returned object represents a live container instance.
|
||||||
|
|
||||||
|
Common attributes:
|
||||||
|
|
||||||
|
* `id`: unique container identifier
|
||||||
|
* `name`: human-readable container name
|
||||||
|
* `status`: runtime state (running)
|
||||||
|
|
||||||
|
This is equivalent to:
|
||||||
|
|
||||||
|
* `docker ps`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Listing All Containers (Including Stopped)
|
||||||
|
|
||||||
|
```python
|
||||||
|
def get_all_containers_list():
|
||||||
|
containers = client.containers.list(all=True)
|
||||||
|
|
||||||
|
for c in containers:
|
||||||
|
print(c.id, c.name, c.status)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Explanation
|
||||||
|
|
||||||
|
* `all=True` includes stopped, exited, and created containers.
|
||||||
|
* Useful for cleanup, auditing, and lifecycle reconciliation.
|
||||||
|
|
||||||
|
Equivalent CLI command:
|
||||||
|
|
||||||
|
* `docker ps -a`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Creating a Container (Without Starting It)
|
||||||
|
|
||||||
|
```python
|
||||||
|
def create_container():
|
||||||
|
container = client.containers.create(
|
||||||
|
image="nginx:latest",
|
||||||
|
name="my_nginx",
|
||||||
|
ports={"80/tcp": 8080},
|
||||||
|
detach=True
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Explanation
|
||||||
|
|
||||||
|
This creates a container in the **created** state.
|
||||||
|
|
||||||
|
Key parameters:
|
||||||
|
|
||||||
|
* `image`: base image for the container
|
||||||
|
* `name`: explicit container name
|
||||||
|
* `ports`: port mapping (container → host)
|
||||||
|
* `detach=True`: container runs in background when started
|
||||||
|
|
||||||
|
Important distinction:
|
||||||
|
|
||||||
|
* `create()` does **not** start the container
|
||||||
|
* This mirrors `docker create`
|
||||||
|
|
||||||
|
Use cases:
|
||||||
|
|
||||||
|
* Deferred startup
|
||||||
|
* Multi-step initialization
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Running a Container (Create + Start)
|
||||||
|
|
||||||
|
```python
|
||||||
|
def run_container():
|
||||||
|
container = client.containers.run(
|
||||||
|
"nginx:latest",
|
||||||
|
name="nginx_run",
|
||||||
|
ports={"80/tcp": 8081},
|
||||||
|
detach=True
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Explanation
|
||||||
|
|
||||||
|
* `run()` is a convenience method.
|
||||||
|
* Internally performs `create()` followed by `start()`.
|
||||||
|
|
||||||
|
Equivalent CLI command:
|
||||||
|
|
||||||
|
* `docker run -d -p 8081:80 nginx:latest`
|
||||||
|
|
||||||
|
This is the most common approach for:
|
||||||
|
|
||||||
|
* Short-lived workloads
|
||||||
|
* Simple services
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Managing Container Lifecycle
|
||||||
|
|
||||||
|
```python
|
||||||
|
def start_container():
|
||||||
|
container = client.containers.get("my_nginx")
|
||||||
|
|
||||||
|
container.start()
|
||||||
|
time.sleep(1000)
|
||||||
|
|
||||||
|
container.restart()
|
||||||
|
time.sleep(1000)
|
||||||
|
|
||||||
|
container.pause()
|
||||||
|
container.unpause()
|
||||||
|
time.sleep(1000)
|
||||||
|
|
||||||
|
container.stop(timeout=10)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Explanation
|
||||||
|
|
||||||
|
This function demonstrates multiple lifecycle transitions.
|
||||||
|
|
||||||
|
#### `containers.get(name)`
|
||||||
|
|
||||||
|
* Retrieves an existing container by name or ID.
|
||||||
|
* Raises an exception if the container does not exist.
|
||||||
|
|
||||||
|
#### `start()`
|
||||||
|
|
||||||
|
* Transitions container from `created` or `stopped` → `running`.
|
||||||
|
|
||||||
|
#### `restart()`
|
||||||
|
|
||||||
|
* Stops and immediately starts the container.
|
||||||
|
* Often used after configuration changes.
|
||||||
|
|
||||||
|
#### `pause()` / `unpause()`
|
||||||
|
|
||||||
|
* Freezes container processes using cgroups.
|
||||||
|
* Network and filesystem state remain intact.
|
||||||
|
|
||||||
|
#### `stop(timeout=10)`
|
||||||
|
|
||||||
|
* Sends SIGTERM, then SIGKILL after timeout.
|
||||||
|
* Allows graceful shutdown.
|
||||||
|
|
||||||
|
The `sleep()` calls simulate:
|
||||||
|
|
||||||
|
* Long-running services
|
||||||
|
* Observing container behavior between states
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Reading Container Logs
|
||||||
|
|
||||||
|
```python
|
||||||
|
def log_container():
|
||||||
|
container = client.containers.get("my_nginx")
|
||||||
|
logs = container.logs(tail=20)
|
||||||
|
print(logs.decode())
|
||||||
|
```
|
||||||
|
|
||||||
|
### Explanation
|
||||||
|
|
||||||
|
* Retrieves logs from the container’s stdout/stderr.
|
||||||
|
* `tail=20` limits output to the last 20 lines.
|
||||||
|
|
||||||
|
Important details:
|
||||||
|
|
||||||
|
* Logs are returned as bytes
|
||||||
|
* Decoding is required for readable output
|
||||||
|
|
||||||
|
Equivalent CLI command:
|
||||||
|
|
||||||
|
* `docker logs --tail 20 my_nginx`
|
||||||
|
|
||||||
|
This is critical for:
|
||||||
|
|
||||||
|
* Debugging runtime issues
|
||||||
|
* Health checks
|
||||||
|
* Observability tooling
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Conditional Execution Based on Docker Availability
|
||||||
|
|
||||||
|
```python
|
||||||
|
if ping_docker:
|
||||||
|
get_containers_list()
|
||||||
|
```
|
||||||
|
|
||||||
|
### Explanation
|
||||||
|
|
||||||
|
* Ensures container operations only run if Docker is reachable.
|
||||||
|
* Prevents unhandled API errors.
|
||||||
|
|
||||||
|
This pattern is common in:
|
||||||
|
|
||||||
|
* Entry-point scripts
|
||||||
|
* Health probes
|
||||||
|
* Automation jobs
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Container States (Conceptual Model)
|
||||||
|
|
||||||
|
Understanding container states is essential:
|
||||||
|
|
||||||
|
* `created`: container exists but is not running
|
||||||
|
* `running`: container processes are active
|
||||||
|
* `paused`: execution is suspended
|
||||||
|
* `exited`: container stopped normally
|
||||||
|
* `dead`: container failed unexpectedly
|
||||||
|
|
||||||
|
Every method in this document transitions the container between these states.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. Summary
|
||||||
|
|
||||||
|
In this section, you learned how to:
|
||||||
|
|
||||||
|
* List running and stopped containers
|
||||||
|
* Create containers separately from starting them
|
||||||
|
* Run containers in a single step
|
||||||
|
* Control container lifecycle states
|
||||||
|
* Read container logs
|
||||||
|
* Safely execute operations based on Docker availability
|
||||||
|
|
||||||
|
This container-level control is the foundation for:
|
||||||
|
|
||||||
|
* Service orchestration
|
||||||
|
* CI/CD job execution
|
||||||
|
* Debugging and recovery automation
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
Official Docker SDK for Python documentation:
|
||||||
|
|
||||||
|
* [https://docker-py.readthedocs.io/](https://docker-py.readthedocs.io/)
|
||||||
68
Docs/Libs/Docker/05-Networks.md
Normal file
68
Docs/Libs/Docker/05-Networks.md
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
```python
|
||||||
|
import docker
|
||||||
|
import time
|
||||||
|
|
||||||
|
docker_client = docker.DockerClient(base_url="unix://var/run/docker.sock")
|
||||||
|
docker_client.ping()
|
||||||
|
|
||||||
|
print("All Networks:\n")
|
||||||
|
|
||||||
|
all_networks = docker_client.networks.list()
|
||||||
|
|
||||||
|
for network in all_networks:
|
||||||
|
print(network.name, network.id)
|
||||||
|
|
||||||
|
print("\nNetworks Named host and bridge:\n")
|
||||||
|
|
||||||
|
system_networks = docker_client.networks.list(names=["host", "bridge"])
|
||||||
|
|
||||||
|
for network in system_networks:
|
||||||
|
print(network.name, network.id)
|
||||||
|
|
||||||
|
print("\nNetwork With Custom ID:\n")
|
||||||
|
|
||||||
|
custom_id_networks = docker_client.networks.list(
|
||||||
|
ids=["29c9e588bb8e0db6445f2a2278a1c2f42e39dc163c0a404f744dc4139fe47d21"]
|
||||||
|
)
|
||||||
|
|
||||||
|
for network in custom_id_networks:
|
||||||
|
print(network.name, network.id)
|
||||||
|
|
||||||
|
print("\nNetwork With Custom ID (Including Attributes):\n")
|
||||||
|
|
||||||
|
custom_id_networks = docker_client.networks.list(
|
||||||
|
ids=["29c9e588bb8e0db6445f2a2278a1c2f42e39dc163c0a404f744dc4139fe47d21"]
|
||||||
|
)
|
||||||
|
|
||||||
|
for network in custom_id_networks:
|
||||||
|
print(network.name, network.id, network.attrs)
|
||||||
|
|
||||||
|
print("\nNetwork With Custom Filter:\n")
|
||||||
|
|
||||||
|
filtered_networks = docker_client.networks.list(
|
||||||
|
names=["gitea_default"],
|
||||||
|
filters={"driver": "bridge"}
|
||||||
|
)
|
||||||
|
|
||||||
|
for network in filtered_networks:
|
||||||
|
if network.attrs["Driver"]:
|
||||||
|
print(network.name, network.id)
|
||||||
|
|
||||||
|
print("\nNetwork With Custom Filter (Greedy):\n")
|
||||||
|
|
||||||
|
filtered_networks = docker_client.networks.list(
|
||||||
|
names=["gitea_default"],
|
||||||
|
filters={"driver": "bridge"},
|
||||||
|
greedy=True
|
||||||
|
)
|
||||||
|
|
||||||
|
for network in filtered_networks:
|
||||||
|
if network.attrs["Driver"]:
|
||||||
|
print(network.name, network.id, network.attrs)
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
|
||||||
|
```
|
||||||
0
Docs/Libs/Docker/06-Volumes.md
Normal file
0
Docs/Libs/Docker/06-Volumes.md
Normal file
0
Docs/Libs/Docker/07-Monitoring.md
Normal file
0
Docs/Libs/Docker/07-Monitoring.md
Normal file
0
Docs/Libs/Docker/08-Error-Handeling.md
Normal file
0
Docs/Libs/Docker/08-Error-Handeling.md
Normal file
0
Docs/Libs/Docker/09-Compose.md
Normal file
0
Docs/Libs/Docker/09-Compose.md
Normal file
127
Docs/Libs/FastAPI/04-Post-Method.md
Normal file
127
Docs/Libs/FastAPI/04-Post-Method.md
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
# FastAPI – POST Endpoint and JSON Input
|
||||||
|
|
||||||
|
This section demonstrates how to handle **POST requests** in FastAPI to create new resources using request data and return JSON responses.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Example Application (POST Request)
|
||||||
|
|
||||||
|
Extend `main.py` with the following code:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
users = [
|
||||||
|
{"name": "abbas", "age": 20},
|
||||||
|
{"name": "mmd", "age": 37},
|
||||||
|
{"name": "asghar", "age": 19},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/")
|
||||||
|
def home_page():
|
||||||
|
return {"msg": "API is working"}
|
||||||
|
|
||||||
|
|
||||||
|
@app.post("/new_user")
|
||||||
|
def create_user(name: str, age: int):
|
||||||
|
new_user = {"name": name, "age": age}
|
||||||
|
users.append(new_user)
|
||||||
|
return {"msg": "User created successfully"}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Code Overview
|
||||||
|
|
||||||
|
### POST Endpoint Definition
|
||||||
|
|
||||||
|
```python
|
||||||
|
@app.post("/new_user")
|
||||||
|
def create_user(name: str, age: int):
|
||||||
|
```
|
||||||
|
|
||||||
|
* Registers an HTTP **POST** endpoint at `/new_user`
|
||||||
|
* Accepts input parameters:
|
||||||
|
|
||||||
|
* `name` → string
|
||||||
|
* `age` → integer
|
||||||
|
* FastAPI automatically validates input types
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Creating a New Resource
|
||||||
|
|
||||||
|
```python
|
||||||
|
new_user = {"name": name, "age": age}
|
||||||
|
users.append(new_user)
|
||||||
|
```
|
||||||
|
|
||||||
|
* Constructs a new user object
|
||||||
|
* Appends it to the in-memory `users` list
|
||||||
|
* Simulates creating a record in a database
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### JSON Response
|
||||||
|
|
||||||
|
```python
|
||||||
|
return {"msg": "User created successfully"}
|
||||||
|
```
|
||||||
|
|
||||||
|
* Returns a structured JSON response
|
||||||
|
* Automatically serialized by FastAPI
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Example Request
|
||||||
|
|
||||||
|
### Using `curl`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST "http://localhost:8000/new_user?name=ali&age=25"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"msg": "User created successfully"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verifying the Result
|
||||||
|
|
||||||
|
After creating a user, retrieve the updated list:
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /users
|
||||||
|
```
|
||||||
|
|
||||||
|
Response will now include the newly added user.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Running the Application
|
||||||
|
|
||||||
|
Start the FastAPI service using `uvicorn`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uvicorn main:app --reload
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
* POST requests should be used to create resources
|
||||||
|
* Avoid modifying in-memory data in production environments
|
||||||
|
* Use request bodies with Pydantic models instead of query parameters for real APIs
|
||||||
|
* Return appropriate HTTP status codes (`201 Created`)
|
||||||
|
* Validate and sanitize all client-provided input
|
||||||
|
* Replace in-memory storage with persistent databases
|
||||||
|
|
||||||
162
Docs/Libs/FastAPI/05-Put-Method.md
Normal file
162
Docs/Libs/FastAPI/05-Put-Method.md
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
# FastAPI – PUT Method
|
||||||
|
|
||||||
|
This document demonstrates how to use the **HTTP PUT method** in FastAPI to update an existing resource.
|
||||||
|
It builds on previous GET and POST examples and completes a basic CRUD-style workflow.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Example Application
|
||||||
|
|
||||||
|
Create or update `main.py` with the following content:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
users = [
|
||||||
|
{"name": "abbas", "age": 20},
|
||||||
|
{"name": "mmd", "age": 37},
|
||||||
|
{"name": "asghar", "age": 19},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/")
|
||||||
|
def home_page():
|
||||||
|
return {"msg": "API is working"}
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/users")
|
||||||
|
def show_users():
|
||||||
|
return users
|
||||||
|
|
||||||
|
|
||||||
|
@app.post("/create_user")
|
||||||
|
def create_user(name: str, age: int):
|
||||||
|
new_user = {"name": name, "age": age}
|
||||||
|
users.append(new_user)
|
||||||
|
return {"msg": f"user {name} with age {age} created"}
|
||||||
|
|
||||||
|
|
||||||
|
@app.put("/update_user/{target_name}")
|
||||||
|
def update_user(target_name: str, age: int):
|
||||||
|
for user in users:
|
||||||
|
if user["name"] == target_name:
|
||||||
|
user["age"] = age
|
||||||
|
return {"msg": f"user {target_name} updated"}
|
||||||
|
return {"msg": "user not found"}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Code Overview
|
||||||
|
|
||||||
|
### PUT Endpoint Definition
|
||||||
|
|
||||||
|
```python
|
||||||
|
@app.put("/update_user/{target_name}")
|
||||||
|
def update_user(target_name: str, age: int):
|
||||||
|
```
|
||||||
|
|
||||||
|
* Registers an HTTP **PUT** endpoint
|
||||||
|
* `target_name` is a **path parameter**
|
||||||
|
* `age` is a **query parameter**
|
||||||
|
* Used to update an existing user’s data
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Update Logic
|
||||||
|
|
||||||
|
```python
|
||||||
|
for user in users:
|
||||||
|
if user["name"] == target_name:
|
||||||
|
user["age"] = age
|
||||||
|
```
|
||||||
|
|
||||||
|
* Iterates over the in-memory users list
|
||||||
|
* Matches user by name
|
||||||
|
* Updates the `age` field in place
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Success Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"msg": "user abbas updated"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Returned when the target user exists and is updated successfully.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Failure Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"msg": "user not found"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Returned when no matching user exists.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Example Requests
|
||||||
|
|
||||||
|
### Update User Age (PUT)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X PUT "http://localhost:8000/update_user/abbas?age=25"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Verify Update
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /users
|
||||||
|
```
|
||||||
|
|
||||||
|
Updated response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{"name": "abbas", "age": 25},
|
||||||
|
{"name": "mmd", "age": 37},
|
||||||
|
{"name": "asghar", "age": 19}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Running the Application
|
||||||
|
|
||||||
|
Start the service using `uvicorn`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uvicorn main:app --reload
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## HTTP Method Summary
|
||||||
|
|
||||||
|
| Method | Endpoint | Purpose |
|
||||||
|
| ------ | --------------------- | ----------------------- |
|
||||||
|
| GET | `/` | Health check |
|
||||||
|
| GET | `/users` | Retrieve all users |
|
||||||
|
| POST | `/create_user` | Create a new user |
|
||||||
|
| PUT | `/update_user/{name}` | Update an existing user |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
* Use **PUT** for full updates and **PATCH** for partial updates
|
||||||
|
* Return proper HTTP status codes (`404`, `200`, `201`)
|
||||||
|
* Avoid using in-memory data stores in production
|
||||||
|
* Use Pydantic models for request bodies instead of query parameters
|
||||||
|
* Add input validation and error handling
|
||||||
|
* Separate routes, services, and models as the project grows
|
||||||
|
* Make PUT operations idempotent
|
||||||
|
|
||||||
172
Docs/Libs/FastAPI/06-Delete-Method.md
Normal file
172
Docs/Libs/FastAPI/06-Delete-Method.md
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
# FastAPI – DELETE Method (Remove Resource)
|
||||||
|
|
||||||
|
This document demonstrates how to use the **HTTP DELETE method** in FastAPI to remove an existing resource.
|
||||||
|
It completes the CRUD workflow using **GET, POST, PUT, and DELETE** operations.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Example Application
|
||||||
|
|
||||||
|
Create or update `main.py` with the following content:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
users = [
|
||||||
|
{"name": "abbas", "age": 20},
|
||||||
|
{"name": "mmd", "age": 37},
|
||||||
|
{"name": "asghar", "age": 19},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/")
|
||||||
|
def home_page():
|
||||||
|
return {"msg": "API is working"}
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/users")
|
||||||
|
def show_users():
|
||||||
|
return users
|
||||||
|
|
||||||
|
|
||||||
|
@app.post("/create_user")
|
||||||
|
def create_user(name: str, age: int):
|
||||||
|
new_user = {"name": name, "age": age}
|
||||||
|
users.append(new_user)
|
||||||
|
return {"msg": f"user {name} with age {age} created"}
|
||||||
|
|
||||||
|
|
||||||
|
@app.put("/update_user/{target_name}")
|
||||||
|
def update_user(target_name: str, age: int):
|
||||||
|
for user in users:
|
||||||
|
if user["name"] == target_name:
|
||||||
|
user["age"] = age
|
||||||
|
return {"msg": f"user {target_name} updated"}
|
||||||
|
return {"msg": "user not found"}
|
||||||
|
|
||||||
|
|
||||||
|
@app.delete("/delete_user/{target_name}")
|
||||||
|
def delete_user(target_name: str):
|
||||||
|
for user in users:
|
||||||
|
if user["name"] == target_name:
|
||||||
|
users.remove(user)
|
||||||
|
return {"msg": f"user {target_name} deleted"}
|
||||||
|
return {"msg": "user not found"}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Code Overview
|
||||||
|
|
||||||
|
### DELETE Endpoint Definition
|
||||||
|
|
||||||
|
```python
|
||||||
|
@app.delete("/delete_user/{target_name}")
|
||||||
|
def delete_user(target_name: str):
|
||||||
|
```
|
||||||
|
|
||||||
|
* Registers an HTTP **DELETE** endpoint
|
||||||
|
* `target_name` is a **path parameter**
|
||||||
|
* Used to remove a user from the data store
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Delete Logic
|
||||||
|
|
||||||
|
```python
|
||||||
|
for user in users:
|
||||||
|
if user["name"] == target_name:
|
||||||
|
users.remove(user)
|
||||||
|
```
|
||||||
|
|
||||||
|
* Iterates through the users list
|
||||||
|
* Finds a matching user by name
|
||||||
|
* Removes the user from the list
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Success Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"msg": "user abbas deleted"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Returned when the user is successfully removed.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Failure Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"msg": "user not found"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Returned when the specified user does not exist.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Example Requests
|
||||||
|
|
||||||
|
### Delete a User
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X DELETE "http://localhost:8000/delete_user/abbas"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Verify Deletion
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /users
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{"name": "mmd", "age": 37},
|
||||||
|
{"name": "asghar", "age": 19}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Running the Application
|
||||||
|
|
||||||
|
Start the service with `uvicorn`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uvicorn main:app --reload
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## CRUD Endpoint Summary
|
||||||
|
|
||||||
|
| Method | Endpoint | Description |
|
||||||
|
| ------ | --------------------- | ------------------ |
|
||||||
|
| GET | `/` | Health check |
|
||||||
|
| GET | `/users` | Retrieve all users |
|
||||||
|
| POST | `/create_user` | Create a user |
|
||||||
|
| PUT | `/update_user/{name}` | Update a user |
|
||||||
|
| DELETE | `/delete_user/{name}` | Delete a user |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
* Use **DELETE** only for resource removal
|
||||||
|
* Return appropriate HTTP status codes (`204`, `404`)
|
||||||
|
* Ensure delete operations are idempotent
|
||||||
|
* Avoid modifying in-memory data in production
|
||||||
|
* Add authentication and authorization for destructive operations
|
||||||
|
* Log delete actions for auditability
|
||||||
|
* Use database transactions when deleting persistent data
|
||||||
|
|
||||||
199
Docs/Libs/FastAPI/07-Query-Parameter.md
Normal file
199
Docs/Libs/FastAPI/07-Query-Parameter.md
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
# FastAPI – Query Parameters
|
||||||
|
|
||||||
|
This document demonstrates how to use **query parameters** in FastAPI using multiple typing styles, including:
|
||||||
|
|
||||||
|
* Native Python union types (`str | None`)
|
||||||
|
* `Optional` from `typing`
|
||||||
|
* `Annotated` with `Query` validation
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Example Application
|
||||||
|
|
||||||
|
Create or update `main.py` with the following content:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from fastapi import FastAPI, Query
|
||||||
|
from typing import Optional, Annotated
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
users = [
|
||||||
|
{"name": "abbas", "age": 20},
|
||||||
|
{"name": "abbas", "age": 32},
|
||||||
|
{"name": "abbas", "age": 54},
|
||||||
|
{"name": "abbas", "age": 15},
|
||||||
|
{"name": "mmd", "age": 37},
|
||||||
|
{"name": "asghar", "age": 19},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/")
|
||||||
|
def home_page():
|
||||||
|
return {"msg": "API is working"}
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/user")
|
||||||
|
def get_users(target_name: str | None = None):
|
||||||
|
if target_name:
|
||||||
|
return [item for item in users if item["name"] == target_name]
|
||||||
|
return users
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/user2")
|
||||||
|
def get_users_optional(target_name: Optional[str] = None):
|
||||||
|
if target_name:
|
||||||
|
return [item for item in users if item["name"] == target_name]
|
||||||
|
return users
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/user3")
|
||||||
|
def get_users_annotated(
|
||||||
|
target_name: Annotated[str | None, Query(max_length=50)] = None
|
||||||
|
):
|
||||||
|
if target_name:
|
||||||
|
return [item for item in users if item["name"] == target_name]
|
||||||
|
return users
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Query Parameter Overview
|
||||||
|
|
||||||
|
Query parameters are key-value pairs appended to the URL after `?`.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
```
|
||||||
|
/user?target_name=abbas
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Defined Endpoints
|
||||||
|
|
||||||
|
### 1. Basic Query Parameter (Python Union Type)
|
||||||
|
|
||||||
|
```python
|
||||||
|
@app.get("/user")
|
||||||
|
def get_users(target_name: str | None = None):
|
||||||
|
```
|
||||||
|
|
||||||
|
* Uses Python 3.10+ union syntax
|
||||||
|
* `target_name` is optional
|
||||||
|
* If not provided, all users are returned
|
||||||
|
|
||||||
|
**Example Request:**
|
||||||
|
|
||||||
|
```
|
||||||
|
GET /user?target_name=abbas
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. Optional Query Parameter (`typing.Optional`)
|
||||||
|
|
||||||
|
```python
|
||||||
|
@app.get("/user2")
|
||||||
|
def get_users_optional(target_name: Optional[str] = None):
|
||||||
|
```
|
||||||
|
|
||||||
|
* Uses `Optional[str]` for compatibility with older Python versions
|
||||||
|
* Behavior is identical to the first endpoint
|
||||||
|
|
||||||
|
**Example Request:**
|
||||||
|
|
||||||
|
```
|
||||||
|
GET /user2?target_name=abbas
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. Validated Query Parameter (`Annotated + Query`)
|
||||||
|
|
||||||
|
```python
|
||||||
|
@app.get("/user3")
|
||||||
|
def get_users_annotated(
|
||||||
|
target_name: Annotated[str | None, Query(max_length=50)] = None
|
||||||
|
):
|
||||||
|
```
|
||||||
|
|
||||||
|
* Uses `Annotated` for metadata binding
|
||||||
|
* Adds validation rules:
|
||||||
|
|
||||||
|
* `max_length=50`
|
||||||
|
* Automatically returns validation errors if constraints are violated
|
||||||
|
|
||||||
|
**Example Invalid Request:**
|
||||||
|
|
||||||
|
```
|
||||||
|
GET /user3?target_name=verylongnamethatexceedslimit...
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"detail": [
|
||||||
|
{
|
||||||
|
"type": "string_too_long",
|
||||||
|
"loc": ["query", "target_name"],
|
||||||
|
"msg": "String should have at most 50 characters",
|
||||||
|
"input": "..."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Example Responses
|
||||||
|
|
||||||
|
### Filtered Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{"name": "abbas", "age": 20},
|
||||||
|
{"name": "abbas", "age": 32},
|
||||||
|
{"name": "abbas", "age": 54},
|
||||||
|
{"name": "abbas", "age": 15}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Default Response (No Query Parameter)
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{"name": "abbas", "age": 20},
|
||||||
|
{"name": "abbas", "age": 32},
|
||||||
|
{"name": "abbas", "age": 54},
|
||||||
|
{"name": "abbas", "age": 15},
|
||||||
|
{"name": "mmd", "age": 37},
|
||||||
|
{"name": "asghar", "age": 19}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Running the Application
|
||||||
|
|
||||||
|
Start the service using `uvicorn`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uvicorn main:app --reload
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
* Use query parameters for filtering and searching
|
||||||
|
* Always provide defaults for optional parameters
|
||||||
|
* Use `Query()` for validation and constraints
|
||||||
|
* Return full datasets when no filters are applied
|
||||||
|
* Avoid large in-memory datasets in production
|
||||||
|
* Use pagination for large result sets
|
||||||
|
* Combine query parameters with database queries in real systems
|
||||||
|
|
||||||
192
Docs/Libs/FastAPI/08.Status-Codes.md
Normal file
192
Docs/Libs/FastAPI/08.Status-Codes.md
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
# FastAPI – HTTP Status Codes and Error Handling
|
||||||
|
|
||||||
|
This document demonstrates how to use **HTTP status codes** in FastAPI to accurately represent the result of an API operation.
|
||||||
|
Correct status codes improve API reliability, observability, and client-side behavior.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Example Application
|
||||||
|
|
||||||
|
Create or update `main.py` with the following content:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from fastapi import FastAPI, status, HTTPException
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
users = [
|
||||||
|
{"name": "abbas", "age": 20},
|
||||||
|
{"name": "mmd", "age": 37},
|
||||||
|
{"name": "asghar", "age": 19},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/", status_code=status.HTTP_200_OK)
|
||||||
|
def home_page():
|
||||||
|
return {"msg": "API is working"}
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/users", status_code=status.HTTP_200_OK)
|
||||||
|
def show_users():
|
||||||
|
return users
|
||||||
|
|
||||||
|
|
||||||
|
@app.post("/create_user", status_code=status.HTTP_201_CREATED)
|
||||||
|
def create_user(name: str, age: int):
|
||||||
|
new_user = {"name": name, "age": age}
|
||||||
|
users.append(new_user)
|
||||||
|
return {"msg": f"user {name} with age {age} created"}
|
||||||
|
|
||||||
|
|
||||||
|
@app.put("/update_user/{target_name}", status_code=status.HTTP_202_ACCEPTED)
|
||||||
|
def update_user(target_name: str, age: int):
|
||||||
|
for user in users:
|
||||||
|
if user["name"] == target_name:
|
||||||
|
user["age"] = age
|
||||||
|
return {"msg": f"user {target_name} updated"}
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_404_NOT_FOUND,
|
||||||
|
detail="User not found"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.delete("/delete_user/{target_name}", status_code=status.HTTP_204_NO_CONTENT)
|
||||||
|
def delete_user(target_name: str):
|
||||||
|
for user in users:
|
||||||
|
if user["name"] == target_name:
|
||||||
|
users.remove(user)
|
||||||
|
return
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_404_NOT_FOUND,
|
||||||
|
detail="User not found"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Status Code Overview
|
||||||
|
|
||||||
|
HTTP status codes communicate the result of an API request to clients and monitoring systems.
|
||||||
|
|
||||||
|
| Code | Meaning | Usage |
|
||||||
|
| ---- | ---------- | --------------------------------- |
|
||||||
|
| 200 | OK | Successful GET requests |
|
||||||
|
| 201 | Created | Resource successfully created |
|
||||||
|
| 202 | Accepted | Update request accepted |
|
||||||
|
| 204 | No Content | Resource deleted successfully |
|
||||||
|
| 404 | Not Found | Requested resource does not exist |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Endpoint Behavior
|
||||||
|
|
||||||
|
### Root Endpoint
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /
|
||||||
|
```
|
||||||
|
|
||||||
|
* Returns HTTP **200 OK**
|
||||||
|
* Used as a health check
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Create User
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /create_user
|
||||||
|
```
|
||||||
|
|
||||||
|
* Returns HTTP **201 Created**
|
||||||
|
* Indicates successful resource creation
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Update User
|
||||||
|
|
||||||
|
```http
|
||||||
|
PUT /update_user/{target_name}
|
||||||
|
```
|
||||||
|
|
||||||
|
* Returns HTTP **202 Accepted** on success
|
||||||
|
* Raises HTTP **404 Not Found** if user does not exist
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Delete User
|
||||||
|
|
||||||
|
```http
|
||||||
|
DELETE /delete_user/{target_name}
|
||||||
|
```
|
||||||
|
|
||||||
|
* Returns HTTP **204 No Content** on success
|
||||||
|
* Returns no response body
|
||||||
|
* Raises HTTP **404 Not Found** if user does not exist
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Error Handling with `HTTPException`
|
||||||
|
|
||||||
|
```python
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_404_NOT_FOUND,
|
||||||
|
detail="User not found"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
* Immediately stops request processing
|
||||||
|
* Returns structured error responses
|
||||||
|
* Automatically serialized by FastAPI
|
||||||
|
|
||||||
|
**Error Response Example:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"detail": "User not found"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Example Requests
|
||||||
|
|
||||||
|
### Create User
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST "http://localhost:8000/create_user?name=ali&age=25"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Update User
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X PUT "http://localhost:8000/update_user/ali?age=30"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Delete User
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X DELETE "http://localhost:8000/delete_user/ali"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Running the Application
|
||||||
|
|
||||||
|
Start the application using `uvicorn`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uvicorn main:app --reload
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
* Always return meaningful HTTP status codes
|
||||||
|
* Use `status` module instead of hard-coded numbers
|
||||||
|
* Use `HTTPException` for predictable error handling
|
||||||
|
* Do not return response bodies with `204 No Content`
|
||||||
|
* Align status codes with REST conventions
|
||||||
|
* Ensure monitoring systems rely on status codes, not messages
|
||||||
|
* Standardize error formats across services
|
||||||
|
|
||||||
122
Docs/Libs/FastAPI/09-Json-Responce.md
Normal file
122
Docs/Libs/FastAPI/09-Json-Responce.md
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
# FastAPI – JSONResponse (Explicit JSON Responses)
|
||||||
|
|
||||||
|
This document demonstrates how to return **explicit JSON responses** in FastAPI using `JSONResponse`.
|
||||||
|
While FastAPI automatically serializes dictionaries to JSON, `JSONResponse` is useful when you need **full control** over the response.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Example Application
|
||||||
|
|
||||||
|
Create or update `main.py` with the following content:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from fastapi import FastAPI, status
|
||||||
|
from fastapi.responses import JSONResponse
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/")
|
||||||
|
def home():
|
||||||
|
return JSONResponse(
|
||||||
|
content={"msg": "API is working"},
|
||||||
|
status_code=status.HTTP_200_OK
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Why Use `JSONResponse`
|
||||||
|
|
||||||
|
FastAPI automatically converts Python dictionaries into JSON responses.
|
||||||
|
However, `JSONResponse` is useful when you need to:
|
||||||
|
|
||||||
|
* Explicitly control the response type
|
||||||
|
* Set custom status codes dynamically
|
||||||
|
* Customize headers
|
||||||
|
* Return non-standard JSON structures
|
||||||
|
* Override default response behavior
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Response Behavior
|
||||||
|
|
||||||
|
### Endpoint
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /
|
||||||
|
```
|
||||||
|
|
||||||
|
### Response Body
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"msg": "API is working"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### HTTP Status Code
|
||||||
|
|
||||||
|
```
|
||||||
|
200 OK
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Comparison: Default Response vs JSONResponse
|
||||||
|
|
||||||
|
### Default FastAPI Response
|
||||||
|
|
||||||
|
```python
|
||||||
|
@app.get("/")
|
||||||
|
def home():
|
||||||
|
return {"msg": "API is working"}
|
||||||
|
```
|
||||||
|
|
||||||
|
* Automatically serialized to JSON
|
||||||
|
* Simpler and recommended for most cases
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Explicit JSONResponse
|
||||||
|
|
||||||
|
```python
|
||||||
|
return JSONResponse(
|
||||||
|
content={"msg": "API is working"},
|
||||||
|
status_code=status.HTTP_200_OK
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
* Explicit control over response
|
||||||
|
* Useful for advanced use cases
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## When to Use `JSONResponse`
|
||||||
|
|
||||||
|
* Returning conditional status codes
|
||||||
|
* Adding custom headers
|
||||||
|
* Returning responses outside standard request flow
|
||||||
|
* Building middleware or exception handlers
|
||||||
|
* Integrating with legacy systems
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Running the Application
|
||||||
|
|
||||||
|
Start the application using `uvicorn`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uvicorn main:app --reload
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
* Prefer returning dictionaries for simple APIs
|
||||||
|
* Use `JSONResponse` only when additional control is required
|
||||||
|
* Keep response formats consistent across endpoints
|
||||||
|
* Avoid mixing response styles unnecessarily
|
||||||
|
* Use response models for structured APIs
|
||||||
|
|
||||||
238
Docs/Libs/FastAPI/10-Query-Path--AdvancedParm.md
Normal file
238
Docs/Libs/FastAPI/10-Query-Path--AdvancedParm.md
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
# FastAPI – Advanced Path and Query Parameters
|
||||||
|
|
||||||
|
This document demonstrates advanced usage of **path parameters** and **query parameters** in FastAPI, including:
|
||||||
|
|
||||||
|
* Validation rules
|
||||||
|
* Aliases
|
||||||
|
* Descriptions for OpenAPI
|
||||||
|
* Deprecation flags
|
||||||
|
* Clear separation of responsibilities between path and query parameters
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Example Application
|
||||||
|
|
||||||
|
Create or update `main.py` with the following content:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from fastapi import FastAPI, Query, Path, status
|
||||||
|
from fastapi.responses import JSONResponse
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
users_db = [
|
||||||
|
{"id": "1", "name": "radin"}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/user/{target_id}")
|
||||||
|
def get_user_by_path(
|
||||||
|
target_id: int = Path(
|
||||||
|
...,
|
||||||
|
alias="User ID",
|
||||||
|
description="Enter target unique ID",
|
||||||
|
deprecated=True,
|
||||||
|
)
|
||||||
|
):
|
||||||
|
for item in users_db:
|
||||||
|
if int(item["id"]) == target_id:
|
||||||
|
return JSONResponse(
|
||||||
|
content={"msg": f"Your target user name is {item['name']}"},
|
||||||
|
status_code=status.HTTP_200_OK,
|
||||||
|
)
|
||||||
|
|
||||||
|
return JSONResponse(
|
||||||
|
content={"msg": "user not found"},
|
||||||
|
status_code=status.HTTP_404_NOT_FOUND,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/user")
|
||||||
|
def get_user_by_query(
|
||||||
|
target: int | None = Query(
|
||||||
|
default=None,
|
||||||
|
gt=0,
|
||||||
|
alias="User ID",
|
||||||
|
description="Enter target unique ID",
|
||||||
|
)
|
||||||
|
):
|
||||||
|
for item in users_db:
|
||||||
|
if item["id"] == str(target):
|
||||||
|
return JSONResponse(
|
||||||
|
content={"msg": f"Your target user name is {item['name']}"},
|
||||||
|
status_code=status.HTTP_200_OK,
|
||||||
|
)
|
||||||
|
|
||||||
|
return JSONResponse(
|
||||||
|
content={"msg": "user not found"},
|
||||||
|
status_code=status.HTTP_404_NOT_FOUND,
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Path Parameter Example
|
||||||
|
|
||||||
|
### Endpoint
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /user/{target_id}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example Request:**
|
||||||
|
|
||||||
|
```
|
||||||
|
/user/1
|
||||||
|
```
|
||||||
|
|
||||||
|
### Characteristics
|
||||||
|
|
||||||
|
* Always required
|
||||||
|
* Defined as part of the route
|
||||||
|
* Used to identify a specific resource
|
||||||
|
* Missing value results in **404 Not Found**
|
||||||
|
* Supports validation, aliases, and documentation metadata
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Query Parameter Example
|
||||||
|
|
||||||
|
### Endpoint
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /user?User%20ID=1
|
||||||
|
```
|
||||||
|
|
||||||
|
### Characteristics
|
||||||
|
|
||||||
|
* Optional by default
|
||||||
|
* Used for filtering and searching
|
||||||
|
* Not part of the route path
|
||||||
|
* Supports validation and documentation metadata
|
||||||
|
* Uses default values when not provided
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Advanced Parameter Configuration
|
||||||
|
|
||||||
|
### `Path()` Example
|
||||||
|
|
||||||
|
```python
|
||||||
|
Path(
|
||||||
|
...,
|
||||||
|
alias="User ID",
|
||||||
|
description="Enter target unique ID",
|
||||||
|
deprecated=True
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
* `...` → parameter is required
|
||||||
|
* `alias` → custom name in documentation and URL
|
||||||
|
* `description` → shown in Swagger UI
|
||||||
|
* `deprecated` → marked as deprecated in OpenAPI
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `Query()` Example
|
||||||
|
|
||||||
|
```python
|
||||||
|
Query(
|
||||||
|
default=None,
|
||||||
|
gt=0,
|
||||||
|
alias="User ID",
|
||||||
|
description="Enter target unique ID"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
* `gt=0` → value must be greater than zero
|
||||||
|
* Optional parameter with validation rules
|
||||||
|
* Appears in API documentation
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Path vs Query Parameters
|
||||||
|
|
||||||
|
### 1. Path Parameters
|
||||||
|
|
||||||
|
**What they are**
|
||||||
|
Values embedded directly in the URL path that identify a specific resource.
|
||||||
|
|
||||||
|
**When to use**
|
||||||
|
When the parameter is mandatory and uniquely identifies a resource.
|
||||||
|
|
||||||
|
**Example URL**
|
||||||
|
|
||||||
|
```
|
||||||
|
/users/42
|
||||||
|
```
|
||||||
|
|
||||||
|
**FastAPI Example**
|
||||||
|
|
||||||
|
```python
|
||||||
|
@app.get("/users/{user_id}")
|
||||||
|
def get_user(user_id: int):
|
||||||
|
return {"user_id": user_id}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Key Points**
|
||||||
|
|
||||||
|
* Always required
|
||||||
|
* Part of the route definition
|
||||||
|
* Used for IDs and unique identifiers
|
||||||
|
* Missing value → 404 error
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. Query Parameters
|
||||||
|
|
||||||
|
**What they are**
|
||||||
|
Key-value pairs appended to the URL after `?`.
|
||||||
|
|
||||||
|
**When to use**
|
||||||
|
For optional filtering, searching, sorting, and pagination.
|
||||||
|
|
||||||
|
**Example URL**
|
||||||
|
|
||||||
|
```
|
||||||
|
/users?limit=10&active=true
|
||||||
|
```
|
||||||
|
|
||||||
|
**FastAPI Example**
|
||||||
|
|
||||||
|
```python
|
||||||
|
@app.get("/users")
|
||||||
|
def list_users(limit: int = 10, active: bool = True):
|
||||||
|
return {"limit": limit, "active": active}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Key Points**
|
||||||
|
|
||||||
|
* Optional by default
|
||||||
|
* Not part of the route path
|
||||||
|
* Used to modify or filter results
|
||||||
|
* Defaults are used when missing
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Side-by-Side Comparison
|
||||||
|
|
||||||
|
| Feature | Path Parameter | Query Parameter |
|
||||||
|
| ------------- | ------------------- | --------------------------------- |
|
||||||
|
| Location | Inside URL path | After `?` |
|
||||||
|
| Required | Yes | No (by default) |
|
||||||
|
| Purpose | Identify a resource | Filter or modify results |
|
||||||
|
| Example | `/items/5` | `/items?limit=10` |
|
||||||
|
| Missing Value | 404 Not Found | Default value or validation error |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
* Use path parameters for resource identification
|
||||||
|
* Use query parameters for filtering and modifiers
|
||||||
|
* Avoid spaces in parameter aliases for production APIs
|
||||||
|
* Deprecate parameters instead of removing them
|
||||||
|
* Use validation (`gt`, `lt`, `regex`) for safer APIs
|
||||||
|
* Keep URL design consistent across services
|
||||||
|
* Prefer response models over manual JSON responses when possible
|
||||||
|
|
||||||
226
Docs/Libs/FastAPI/11-Post-Types.md
Normal file
226
Docs/Libs/FastAPI/11-Post-Types.md
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
# POST Request Types and Content Types
|
||||||
|
|
||||||
|
This document explains the **body types of POST requests** and the most common **Content-Types** used in APIs.
|
||||||
|
Understanding these formats is essential for building interoperable and production-ready FastAPI services.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## POST Request Body Types
|
||||||
|
|
||||||
|
A POST request sends data to the server in the **request body**.
|
||||||
|
The format of this data is defined by the **Content-Type** header.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Form Data
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
Used primarily for HTML form submissions. Common in browser-based applications.
|
||||||
|
|
||||||
|
### Content-Type
|
||||||
|
|
||||||
|
```
|
||||||
|
application/x-www-form-urlencoded
|
||||||
|
```
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
```
|
||||||
|
multipart/form-data
|
||||||
|
```
|
||||||
|
|
||||||
|
### Characteristics
|
||||||
|
|
||||||
|
* Key-value pairs
|
||||||
|
* Supports file uploads (multipart)
|
||||||
|
* Common in login and upload forms
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /login
|
||||||
|
Content-Type: application/x-www-form-urlencoded
|
||||||
|
|
||||||
|
username=admin&password=secret
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. JSON
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
The most common data format for REST APIs.
|
||||||
|
|
||||||
|
### Content-Type
|
||||||
|
|
||||||
|
```
|
||||||
|
application/json
|
||||||
|
```
|
||||||
|
|
||||||
|
### Characteristics
|
||||||
|
|
||||||
|
* Structured, readable, and language-independent
|
||||||
|
* Easily parsed and validated
|
||||||
|
* Default choice for FastAPI APIs
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "abbas",
|
||||||
|
"age": 25
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. XML
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
An older but still widely used data format in enterprise systems and legacy APIs.
|
||||||
|
|
||||||
|
### Content-Type
|
||||||
|
|
||||||
|
```
|
||||||
|
application/xml
|
||||||
|
```
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
```
|
||||||
|
text/xml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Characteristics
|
||||||
|
|
||||||
|
* Verbose and schema-driven
|
||||||
|
* Common in SOAP-based services
|
||||||
|
* Less common in modern REST APIs
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<user>
|
||||||
|
<name>abbas</name>
|
||||||
|
<age>25</age>
|
||||||
|
</user>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Plain Text
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
Used when sending raw text without structure.
|
||||||
|
|
||||||
|
### Content-Type
|
||||||
|
|
||||||
|
```
|
||||||
|
text/plain
|
||||||
|
```
|
||||||
|
|
||||||
|
### Characteristics
|
||||||
|
|
||||||
|
* No schema or structure
|
||||||
|
* Useful for logs, messages, or simple payloads
|
||||||
|
* Requires custom parsing on the server
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
```
|
||||||
|
Hello FastAPI
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Binary Data
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
Used for sending non-textual data such as images, videos, or files.
|
||||||
|
|
||||||
|
### Content-Type
|
||||||
|
|
||||||
|
```
|
||||||
|
application/octet-stream
|
||||||
|
```
|
||||||
|
|
||||||
|
### Characteristics
|
||||||
|
|
||||||
|
* Raw binary format
|
||||||
|
* Common for file uploads and downloads
|
||||||
|
* Requires stream handling
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
```
|
||||||
|
(binary file data)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. GraphQL
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
GraphQL uses POST requests to execute queries and mutations.
|
||||||
|
|
||||||
|
### Content-Type
|
||||||
|
|
||||||
|
```
|
||||||
|
application/json
|
||||||
|
```
|
||||||
|
|
||||||
|
### Characteristics
|
||||||
|
|
||||||
|
* Single endpoint
|
||||||
|
* Flexible client-driven queries
|
||||||
|
* Requires GraphQL server support
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"query": "query { users { id name } }"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Common Content Types Summary
|
||||||
|
|
||||||
|
| Content-Type | Usage |
|
||||||
|
| ----------------------------------- | -------------------------- |
|
||||||
|
| `application/json` | REST APIs (default) |
|
||||||
|
| `application/x-www-form-urlencoded` | HTML forms |
|
||||||
|
| `multipart/form-data` | Forms with file uploads |
|
||||||
|
| `application/xml` | Legacy / SOAP APIs |
|
||||||
|
| `text/plain` | Raw text |
|
||||||
|
| `application/octet-stream` | Binary data |
|
||||||
|
| `application/graphql` | GraphQL (rare, often JSON) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## FastAPI Considerations
|
||||||
|
|
||||||
|
* JSON is the recommended default for FastAPI
|
||||||
|
* Use Pydantic models for JSON validation
|
||||||
|
* Use `Form()` and `File()` for form and file uploads
|
||||||
|
* Always validate content type in production APIs
|
||||||
|
* Document supported content types clearly
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
* Choose the simplest format that meets requirements
|
||||||
|
* Prefer `application/json` for APIs
|
||||||
|
* Avoid XML unless required by integration
|
||||||
|
* Secure file uploads (size limits, scanning)
|
||||||
|
* Validate all incoming request bodies
|
||||||
|
* Be explicit about supported Content-Types
|
||||||
|
|
||||||
165
Docs/Libs/FastAPI/12-From-Post.md
Normal file
165
Docs/Libs/FastAPI/12-From-Post.md
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
# FastAPI – POST Requests with Form Data
|
||||||
|
|
||||||
|
This document demonstrates how to handle **form-based POST requests** in FastAPI using the `Form()` dependency.
|
||||||
|
Form data is commonly used in **HTML forms**, authentication flows, and legacy systems.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Example Application
|
||||||
|
|
||||||
|
Create or update `main.py` with the following content:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from fastapi import FastAPI, Form, status
|
||||||
|
from fastapi.responses import JSONResponse
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
users_db = [
|
||||||
|
{"id": "1", "name": "radin", "password": "123"}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@app.post("/user/")
|
||||||
|
def get_user_from_form(
|
||||||
|
target: int = Form(
|
||||||
|
...,
|
||||||
|
gt=0,
|
||||||
|
alias="User ID",
|
||||||
|
description="Enter target unique ID",
|
||||||
|
)
|
||||||
|
):
|
||||||
|
for item in users_db:
|
||||||
|
if item["id"] == str(target):
|
||||||
|
return JSONResponse(
|
||||||
|
content={"msg": f"Your target user name is {item['name']}"},
|
||||||
|
status_code=status.HTTP_200_OK,
|
||||||
|
)
|
||||||
|
|
||||||
|
return JSONResponse(
|
||||||
|
content={"msg": "user not found"},
|
||||||
|
status_code=status.HTTP_404_NOT_FOUND,
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Form Data Overview
|
||||||
|
|
||||||
|
### What is Form Data
|
||||||
|
|
||||||
|
Form data is sent in the request body using:
|
||||||
|
|
||||||
|
```
|
||||||
|
Content-Type: application/x-www-form-urlencoded
|
||||||
|
```
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
```
|
||||||
|
multipart/form-data
|
||||||
|
```
|
||||||
|
|
||||||
|
FastAPI requires the `Form()` dependency to explicitly declare form inputs.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Endpoint Behavior
|
||||||
|
|
||||||
|
### Endpoint
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /user/
|
||||||
|
```
|
||||||
|
|
||||||
|
### Request Body (Form Data)
|
||||||
|
|
||||||
|
```
|
||||||
|
User ID=1
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example Using `curl`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST "http://localhost:8000/user/" \
|
||||||
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||||
|
-d "User ID=1"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Response Examples
|
||||||
|
|
||||||
|
### Success Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"msg": "Your target user name is radin"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Status Code: **200 OK**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Failure Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"msg": "user not found"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Status Code: **404 Not Found**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## `Form()` Parameter Configuration
|
||||||
|
|
||||||
|
```python
|
||||||
|
Form(
|
||||||
|
...,
|
||||||
|
gt=0,
|
||||||
|
alias="User ID",
|
||||||
|
description="Enter target unique ID"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
| Parameter | Description |
|
||||||
|
| ------------- | ------------------------------- |
|
||||||
|
| `...` | Field is required |
|
||||||
|
| `gt=0` | Value must be greater than zero |
|
||||||
|
| `alias` | Custom form field name |
|
||||||
|
| `description` | Displayed in API docs |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Swagger / OpenAPI Behavior
|
||||||
|
|
||||||
|
* Form fields appear as input fields
|
||||||
|
* Aliases are reflected in the UI
|
||||||
|
* Validation rules are enforced automatically
|
||||||
|
* Errors are returned with clear messages
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Running the Application
|
||||||
|
|
||||||
|
Start the service using `uvicorn`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uvicorn main:app --reload
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
* Use form data only when required (e.g. HTML forms)
|
||||||
|
* Prefer JSON for APIs and services
|
||||||
|
* Avoid exposing sensitive fields in plain form data
|
||||||
|
* Use HTTPS for all form submissions
|
||||||
|
* Validate and sanitize all inputs
|
||||||
|
* Use authentication and hashing for passwords
|
||||||
|
* Do not store credentials in plain text
|
||||||
|
|
||||||
161
Docs/Libs/FastAPI/13-Body-Post.md
Normal file
161
Docs/Libs/FastAPI/13-Body-Post.md
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
# FastAPI – POST Requests with JSON Body (`Body`)
|
||||||
|
|
||||||
|
This document demonstrates how to receive data from the **request body** using `Body()` in FastAPI.
|
||||||
|
This approach is commonly used when clients send **JSON payloads**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Example Application
|
||||||
|
|
||||||
|
Create or update `main.py` with the following content:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from fastapi import FastAPI, Body, status
|
||||||
|
from fastapi.responses import JSONResponse
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
users_db = [
|
||||||
|
{"id": "1", "name": "radin", "password": "123"}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@app.post("/user/")
|
||||||
|
def get_user_from_body(
|
||||||
|
target: int = Body(
|
||||||
|
...,
|
||||||
|
embed=True,
|
||||||
|
gt=0,
|
||||||
|
alias="User ID",
|
||||||
|
description="Enter target unique ID",
|
||||||
|
)
|
||||||
|
):
|
||||||
|
for item in users_db:
|
||||||
|
if item["id"] == str(target):
|
||||||
|
return JSONResponse(
|
||||||
|
content={"msg": f"Your target user name is {item['name']}"},
|
||||||
|
status_code=status.HTTP_200_OK,
|
||||||
|
)
|
||||||
|
|
||||||
|
return JSONResponse(
|
||||||
|
content={"msg": "user not found"},
|
||||||
|
status_code=status.HTTP_404_NOT_FOUND,
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## JSON Body Overview
|
||||||
|
|
||||||
|
### What Is a Request Body
|
||||||
|
|
||||||
|
The request body contains structured data sent by the client, most commonly as **JSON**.
|
||||||
|
|
||||||
|
**Content-Type:**
|
||||||
|
|
||||||
|
```
|
||||||
|
application/json
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Request Format
|
||||||
|
|
||||||
|
### Example JSON Payload
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"User ID": 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
* `embed=True` requires the value to be wrapped inside a JSON object
|
||||||
|
* The key name is controlled by the `alias`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Example Request Using `curl`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST "http://localhost:8000/user/" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"User ID": 1}'
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Response Examples
|
||||||
|
|
||||||
|
### Success Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"msg": "Your target user name is radin"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Status Code: **200 OK**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Failure Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"msg": "user not found"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Status Code: **404 Not Found**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## `Body()` Parameter Configuration
|
||||||
|
|
||||||
|
```python
|
||||||
|
Body(
|
||||||
|
...,
|
||||||
|
embed=True,
|
||||||
|
gt=0,
|
||||||
|
alias="User ID",
|
||||||
|
description="Enter target unique ID"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
| Parameter | Purpose |
|
||||||
|
| ------------- | -------------------------------- |
|
||||||
|
| `...` | Field is required |
|
||||||
|
| `embed=True` | Wraps the value in a JSON object |
|
||||||
|
| `gt=0` | Validates input value |
|
||||||
|
| `alias` | Custom JSON key name |
|
||||||
|
| `description` | Shown in API documentation |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Swagger / OpenAPI Behavior
|
||||||
|
|
||||||
|
* JSON schema is automatically generated
|
||||||
|
* Validation errors are returned if rules are violated
|
||||||
|
* Aliases and descriptions appear in Swagger UI
|
||||||
|
* Request body is clearly documented
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Running the Application
|
||||||
|
|
||||||
|
Start the service using `uvicorn`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uvicorn main:app --reload
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
* Prefer request body over query parameters for POST requests
|
||||||
|
* Use Pydantic models instead of raw `Body()` for complex payloads
|
||||||
|
* Keep JSON structures consistent
|
||||||
|
* Avoid spaces in JSON keys for production APIs
|
||||||
|
* Never send sensitive data in plain text
|
||||||
|
* Use HTTPS for all JSON-based APIs
|
||||||
167
Docs/Libs/FastAPI/14-File-Post.md
Normal file
167
Docs/Libs/FastAPI/14-File-Post.md
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
# FastAPI – POST Requests with File Uploads
|
||||||
|
|
||||||
|
This document demonstrates how to handle **file uploads** in FastAPI.
|
||||||
|
File uploads are essential for APIs that need to receive **images, documents, or binary data** from clients.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Example Application
|
||||||
|
|
||||||
|
Create or update `main.py` with the following content:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from fastapi import FastAPI, File, UploadFile, status
|
||||||
|
from fastapi.responses import JSONResponse
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
users_db = [
|
||||||
|
{"id": "1", "name": "radin", "password": "123"}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@app.post("/file")
|
||||||
|
def upload_file_bytes(file: bytes = File(...)):
|
||||||
|
"""
|
||||||
|
Receive file as raw bytes.
|
||||||
|
Returns the size of the uploaded file.
|
||||||
|
"""
|
||||||
|
return {"file_size": len(file)}
|
||||||
|
|
||||||
|
|
||||||
|
@app.post("/uploadfile")
|
||||||
|
def upload_file_uploadfile(file: UploadFile):
|
||||||
|
"""
|
||||||
|
Receive file as UploadFile.
|
||||||
|
Returns filename, content type, and size.
|
||||||
|
"""
|
||||||
|
content = file.read()
|
||||||
|
return {
|
||||||
|
"filename": file.filename,
|
||||||
|
"content_type": file.content_type,
|
||||||
|
"file_size": len(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@app.post("/uploadmultifile")
|
||||||
|
def upload_multiple_files(files: List[UploadFile]):
|
||||||
|
"""
|
||||||
|
Receive multiple files as UploadFile list.
|
||||||
|
Returns filenames and content types.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
{"filename": file.filename, "content_type": file.content_type}
|
||||||
|
for file in files
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## File Upload Methods
|
||||||
|
|
||||||
|
### 1. `File` as Bytes
|
||||||
|
|
||||||
|
* Accepts the uploaded file as raw bytes
|
||||||
|
* Suitable for small files or direct in-memory processing
|
||||||
|
* Fast but lacks metadata (filename, content type)
|
||||||
|
|
||||||
|
**Example Request (curl):**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST "http://localhost:8000/file" \
|
||||||
|
-F "file=@example.txt"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"file_size": 128
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. `UploadFile`
|
||||||
|
|
||||||
|
* Accepts file as `UploadFile` object
|
||||||
|
* Provides metadata: `filename` and `content_type`
|
||||||
|
* Supports `.read()`, `.write()`, and `.seek()` operations
|
||||||
|
* More efficient for large files (uses spooled temporary files)
|
||||||
|
|
||||||
|
**Example Request (curl):**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST "http://localhost:8000/uploadfile" \
|
||||||
|
-F "file=@example.txt"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"filename": "example.txt",
|
||||||
|
"content_type": "text/plain",
|
||||||
|
"file_size": 128
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. Multiple File Uploads
|
||||||
|
|
||||||
|
* Accepts a list of `UploadFile`
|
||||||
|
* Allows uploading multiple files in one request
|
||||||
|
* Useful for batch uploads or form submissions
|
||||||
|
|
||||||
|
**Example Request (curl):**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST "http://localhost:8000/uploadmultifile" \
|
||||||
|
-F "files=@file1.txt" \
|
||||||
|
-F "files=@file2.txt"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{"filename": "file1.txt", "content_type": "text/plain"},
|
||||||
|
{"filename": "file2.txt", "content_type": "text/plain"}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Content-Type
|
||||||
|
|
||||||
|
For file uploads, the request must include:
|
||||||
|
|
||||||
|
```
|
||||||
|
Content-Type: multipart/form-data
|
||||||
|
```
|
||||||
|
|
||||||
|
* Each file is sent as a separate part in the multipart request
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Running the Application
|
||||||
|
|
||||||
|
Start the service using `uvicorn`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uvicorn main:app --reload
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
* Use `UploadFile` for large or multiple files
|
||||||
|
* Validate file type and size on the server
|
||||||
|
* Avoid loading very large files fully into memory
|
||||||
|
* Use HTTPS for secure file transfer
|
||||||
|
* Store files in dedicated storage (S3, local disk, or DB)
|
||||||
|
* Return clear metadata (filename, size, content type) to clients
|
||||||
|
* Support multiple files when needed for batch operations
|
||||||
121
Docs/Libs/FastAPI/15-Life-Span.md
Normal file
121
Docs/Libs/FastAPI/15-Life-Span.md
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
# FastAPI – Application Lifespan (Startup & Shutdown Events)
|
||||||
|
|
||||||
|
FastAPI allows you to run code when your application **starts up** or **shuts down**.
|
||||||
|
This is useful for initializing resources, database connections, caches, or background tasks.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Deprecated Method: `@app.on_event`
|
||||||
|
|
||||||
|
Older FastAPI versions use the `@app.on_event` decorator for lifecycle events:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
|
||||||
|
@app.on_event("startup")
|
||||||
|
def on_startup():
|
||||||
|
print("App is loading")
|
||||||
|
|
||||||
|
|
||||||
|
@app.on_event("shutdown")
|
||||||
|
def on_shutdown():
|
||||||
|
print("App is shutting down")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Characteristics
|
||||||
|
|
||||||
|
* `startup` runs once when the app starts
|
||||||
|
* `shutdown` runs once when the app is stopped
|
||||||
|
* Works for synchronous and asynchronous functions
|
||||||
|
* Still supported but **deprecated** in favor of the `lifespan` parameter
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Recommended Modern Approach: `lifespan` with `asynccontextmanager`
|
||||||
|
|
||||||
|
FastAPI now recommends using the `lifespan` parameter in the `FastAPI` constructor.
|
||||||
|
This uses Python's `asynccontextmanager` to define a **single lifecycle context**.
|
||||||
|
|
||||||
|
```python
|
||||||
|
from fastapi import FastAPI
|
||||||
|
from contextlib import asynccontextmanager
|
||||||
|
|
||||||
|
@asynccontextmanager
|
||||||
|
async def lifespan(app: FastAPI):
|
||||||
|
# Code to run before the app starts
|
||||||
|
print("App is loading")
|
||||||
|
yield # Application runs after this point
|
||||||
|
# Code to run after the app stops
|
||||||
|
print("App is shutting down")
|
||||||
|
|
||||||
|
app = FastAPI(lifespan=lifespan)
|
||||||
|
```
|
||||||
|
|
||||||
|
### How It Works
|
||||||
|
|
||||||
|
1. Code **before `yield`** executes on startup
|
||||||
|
2. Code **after `yield`** executes on shutdown
|
||||||
|
3. Supports async operations, e.g., connecting to a database
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Example: Using Lifespan for Database Initialization
|
||||||
|
|
||||||
|
```python
|
||||||
|
from fastapi import FastAPI
|
||||||
|
from contextlib import asynccontextmanager
|
||||||
|
|
||||||
|
@asynccontextmanager
|
||||||
|
async def lifespan(app: FastAPI):
|
||||||
|
app.state.db = await connect_to_db()
|
||||||
|
print("Database connected")
|
||||||
|
yield
|
||||||
|
await app.state.db.close()
|
||||||
|
print("Database disconnected")
|
||||||
|
|
||||||
|
app = FastAPI(lifespan=lifespan)
|
||||||
|
```
|
||||||
|
|
||||||
|
* `app.state` is used to store shared resources
|
||||||
|
* Clean startup and shutdown handling
|
||||||
|
* Ensures proper resource cleanup
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Benefits of the Lifespan Approach
|
||||||
|
|
||||||
|
* Centralized lifecycle management
|
||||||
|
* Cleaner async support
|
||||||
|
* Avoids multiple scattered `@app.on_event` decorators
|
||||||
|
* Better for testing and production-ready apps
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Running the Application
|
||||||
|
|
||||||
|
Start the service with `uvicorn`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uvicorn main:app --reload
|
||||||
|
```
|
||||||
|
|
||||||
|
* On startup, `App is loading` prints to the console
|
||||||
|
* On shutdown (Ctrl+C), `App is shutting down` prints to the console
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
* Always use `lifespan` for new applications
|
||||||
|
* Use `app.state` to store shared resources
|
||||||
|
* Close database connections, caches, or background services in shutdown
|
||||||
|
* Keep startup logic lightweight to avoid blocking the server
|
||||||
|
* Avoid printing in production; use logging instead
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
This approach provides a **modern, production-ready pattern** for managing application startup and shutdown events in FastAPI.
|
||||||
|
|
||||||
Reference in New Issue
Block a user