Containerize a Python Archive Processor

Build a validated FastAPI archive processor and run it locally in Docker.

Introduction

30 Second Summary

Automations move quickly, including when the information they receive is incomplete. A missing course or lesson can turn a simple archive request into a confusing failure later.

In this project, you will build a local Python API that validates archive-job JSON before accepting it. You will run the same processor inside a Docker container for reuse in the next stage of your automation.

What You'll Build

Submit a complete archive job through FastAPI's interactive page to see a structured ready result come back from the Docker container.

By the end of this project, you'll have:

  • Submit a complete archive job to receive an Archive job accepted result with a ready status.
  • Test an incomplete request to see Pydantic validation reject it before processing.
  • Run the processor through a host-only port inside Docker. Inspect the container logs to find the processed job identifier.
  • Secret Mission: strengthen the schema so present-but-empty job details are rejected too.

Are there any prerequisites?

Complete Projects 1 and 2 before starting. You also need the working local n8n installation plus the published PowerShell-to-n8n-to-Discord workflow from those projects.

Before We Start

Before the hands-on work begins, take a moment to commit to the Python processor you are building. Its role gives the final automation a clear processing boundary.

Set Up the Processor Project

The archive processor needs a clean place to keep its Python packages. A virtual environment prevents those packages from mixing with other projects on your computer.

A pinned requirements file also gives the future Docker build an explicit package list. This makes the local service reproducible before you package it.

In this step, get ready to:
  • Create the processor workspace.
  • Verify the installed runtimes.
  • Install the pinned dependencies inside an isolated environment.
Create the project workspace

A folder opened in Visual Studio Code becomes a workspace. Its integrated PowerShell terminal starts inside that folder.

  • Press the Windows key to open Windows search.
  • Type Visual Studio Code into the search field.
  • Press Enter to open Visual Studio Code.
  • Select File from the top menu.
  • Select Open Folder....
  • Select New Folder in the folder picker.
  • Enter python-archive-processor as the folder name.

Visual Studio Code may show a Workspace Trust prompt after you open the folder. You created this empty folder yourself, so you can enable its workspace features.

  • Select Select Folder to open the new folder.
  • Select Yes, I trust the authors if the Workspace Trust prompt appears.

You should see python-archive-processor at the top of the Explorer sidebar.

  • Select View from the top menu.
  • Select Terminal to display the integrated terminal.
  • Select Launch Profile from the terminal dropdown.
  • Choose PowerShell as the terminal profile.

The new PowerShell terminal should start inside your python-archive-processor folder. Every command in this step now applies to the correct workspace.

Verify the tools and activate the environment

The API packages require Python 3.10 or newer. Docker must expose both its command-line client and its running engine before later container work can succeed.

  • Check the installed Python version by running this command:
python --version

What does this check?

The --version option prints the Python version used by the python command. It exits without starting an interactive Python session.

You should see Python followed by version 3.10 or higher.

Seeing an older Python version?

  • Pause here if the reported version is below 3.10.
  • Use help updating the Python version used by PowerShell before continuing.
  • Check the Docker client and engine by running this command:
docker version

What does this check?

The command asks Docker for version information from the local command-line client. It also contacts the Docker engine running through Docker Desktop.

You should see separate Client and Server sections. Both sections confirm that the Docker tools needed later are available.

Missing the Server section?

  • Start Docker Desktop through Windows search if the output only contains the Client section.
  • Run the check again after Docker Desktop finishes starting.
  • Still stuck? Help me connect the Docker client to Docker Desktop.

A virtual environment stores this project's packages inside the workspace. The .venv folder becomes that isolated package location.

  • Create the virtual environment by running this command:
python -m venv .venv

What does this command do?

The venv module creates an isolated Python environment in .venv. Packages installed after activation stay associated with this processor project.

You should see a new .venv folder in the Explorer sidebar.

  • Activate the virtual environment by running this command:
.\.venv\Scripts\Activate.ps1

What does activation change?

Activation updates the current PowerShell session to use the Python tools inside .venv. Your system-wide Python installation remains unchanged.

You should see (.venv) at the start of the PowerShell prompt. That prefix confirms the isolated environment is active.

PowerShell blocking activation?

  • Look for a message that mentions the PowerShell execution policy.
  • Apply Python's documented current-user execution-policy remedy before activating the environment again.
  • Need a hand? Help me activate this virtual environment safely.
Install the pinned dependencies

A requirements file pins exact package versions so the environment can be recreated later. These three entries become the Docker build's dependency list.

  • Select the New File... button in the Explorer sidebar.
  • Enter requirements.txt as the file name.
  • Add the pinned dependencies by pasting this content into requirements.txt:
fastapi==0.162.0
pydantic==2.14.2
uvicorn==0.54.0

What do these packages provide?

  • FastAPI 0.162.0 provides the API framework used by the processor.
  • Pydantic 2.14.2 provides the request model validation added later.
  • Uvicorn 0.54.0 runs the FastAPI application as a local web service.
  • Press Ctrl+S to save requirements.txt.

You should see requirements.txt listed beside the .venv folder in the Explorer sidebar.

✔️ Awesome, I've got everything

Your requirements file is saved with all three pinned dependencies.

ⓧ I'd like to double check the full code

  • Compare your requirements.txt file with this complete version.
fastapi==0.162.0
pydantic==2.14.2
uvicorn==0.54.0

Requirements file not showing up?

  • Confirm that the Explorer sidebar shows python-archive-processor as the open folder.
  • Check that the file name is exactly requirements.txt.
  • Still stuck? Help me create the requirements file in the correct folder.
  • Install the pinned packages into the active environment by running this command:
python -m pip install -r requirements.txt

What does this command do?

Python starts pip from the active environment. The -r option tells it to install every entry in requirements.txt.

You will see package download and installation activity in the terminal. The PowerShell prompt returns when the installation finishes.

Package installation failed?

  • Confirm that (.venv) still appears at the start of your prompt.
  • Compare each dependency line with the complete requirements.txt reference above.
  • Need help with the installation output? Help me diagnose this pip installation failure.

Before you run the final check, which pinned FastAPI version do you expect the active environment to report?

  • Verify the installed FastAPI package by running this command:
python -m pip show fastapi

What does this check prove?

The command displays package metadata from the active environment. Its version field confirms which FastAPI release the requirements file installed.

You should see Version: 0.162.0 in the output. That is your pinned FastAPI version running inside .venv.

That setup is locked in. Your processor now has an isolated environment with every required package installed.

Seeing another FastAPI version?

  • Confirm that (.venv) appears at the start of the PowerShell prompt.
  • Confirm that the FastAPI line in requirements.txt contains 0.162.0.
  • Still seeing a mismatch? Help me correct the FastAPI version in my virtual environment.

Your workspace now has the exact dependencies needed for the archive processor. Next up, you will build the first runnable endpoint and test what happens when its request body accepts too much.

Build the Naive Processor

Your isolated Python environment is ready. The next goal is a working processing boundary that you can call from a browser.

FastAPI turns a Python function into an API endpoint. This first pass accepts a plain dict so you can see a result quickly.

The final downloader needs jobId, course, and lesson for every archive job. The second request will test whether this JSON shape protects the workflow from incomplete jobs.

In this step, get ready to:
  • Create a FastAPI endpoint that accepts an archive job.
  • Process a complete archive job through the interactive docs.
  • Test the same endpoint with an incomplete archive job.
Create the naive endpoint

FastAPI route decorators connect incoming requests to Python functions. This first version preserves whichever keys arrive in the request dictionary.

  • In the Explorer sidebar from earlier, select the new-file control.
  • Enter main.py as the filename.

You should see main.py listed inside python-archive-processor.

  • Paste the following code into main.py:
from fastapi import FastAPI

app = FastAPI()


@app.post("/process")
async def process_archive_job(job: dict):
    return {
        "message": "Archive job accepted",
        **job,
        "status": "ready",
        "processedBy": "Python",
    }

What does this code do?

  • The app object represents the FastAPI application that the local server runs.
  • The @app.post("/process") decorator registers /process as an HTTP POST endpoint.
  • The job: dict parameter receives the submitted JSON object without a declared field structure.
  • The **job expression copies every submitted key into the response.
  • The fixed fields identify the result as accepted by the Python processor.
  • Save main.py by pressing Ctrl+S.

The unsaved marker disappears from the editor tab. Your endpoint code is now stored in main.py.

✔️ Awesome, I've got everything!

Your saved main.py is ready to run.

ⓧ I'd like to double check the full code

  • Compare your saved main.py with this complete file:
from fastapi import FastAPI

app = FastAPI()


@app.post("/process")
async def process_archive_job(job: dict):
    return {
        "message": "Archive job accepted",
        **job,
        "status": "ready",
        "processedBy": "Python",
    }

What should match?

Your file should contain one FastAPI application object. It should also contain the asynchronous process_archive_job() endpoint shown above.

Is main.py missing or unsaved?

  • Check that the Explorer sidebar still shows the python-archive-processor folder from earlier.
  • Rename the file if it appears as main.py.txt.
  • Still stuck? Help me check why my FastAPI main.py file is missing or not saving in Visual Studio Code.
Run the processor with a complete job

Uvicorn runs the FastAPI application as a local web server. The process keeps the current PowerShell terminal busy until it stops.

  • Start the API in the activated PowerShell terminal by running:
uvicorn main:app --host 0.0.0.0 --port 8000

What does this command do?

  • The main:app value points Uvicorn to the app object inside main.py.
  • The --host 0.0.0.0 option makes the server listen beyond the loopback interface.
  • The --port 8000 option makes the API available on port 8000.

The terminal shows that the server completed its startup. The process remains attached to that terminal while the API is running.

  • Keep this PowerShell terminal running.
  • Open a new tab in your web browser.
  • Enter http://127.0.0.1:8000/docs in the address bar.

You should see FastAPI's interactive documentation page. The page includes a POST /process operation.

  • Expand the POST /process operation.
  • Click Try it out.
  • Replace the example in the request editor with this complete archive job:
{
  "jobId": "archive-001",
  "course": "Machine Learning Foundations",
  "lesson": "Lesson 1"
}

What is in this request?

  • The jobId value identifies this archive request.
  • The course value identifies the course that owns the material.
  • The lesson value identifies the requested lesson.

Before you execute this complete job, which submitted fields do you expect the response to echo back?

  • Click Execute.

The response includes Archive job accepted with a ready status. It also echoes the three values you submitted.

That is your first working processor response. The complete job now travels through the local endpoint as structured JSON.

Is the docs page or request failing?

  • Confirm that the PowerShell terminal still shows the running Uvicorn process.
  • Check that main.py matches the full-file reference from the previous substep.
  • Restore the quotation marks and commas in the request if the editor reports invalid JSON.
  • Still stuck? Help me troubleshoot my local FastAPI docs page or complete POST request.
Challenge the endpoint with missing data

The complete request proves the happy path. The downloader also needs protection when a workflow sends only part of a job.

  • Return to the expanded POST /process operation from earlier.
  • Select the request editor.
  • Replace its contents with this incomplete job:
{"jobId":"archive-001"}

What is this test checking?

This request still supplies jobId. It omits both course and lesson.

Before you execute it, do you think a plain dict can tell that the course details are missing?

  • Click Execute.

You will see another successful response. It still contains Archive job accepted with a ready status.

The API accepted an unusable job

That result is the intended shortfall. A plain dict stores the supplied keys without declaring which fields are required.

The downstream downloader would have no course or lesson to process. The successful status therefore makes an incomplete job look usable.

Did the incomplete job fail instead?

  • Compare main.py with the full-file reference to confirm the parameter still reads job: dict.
  • Check that the return dictionary still contains **job.
  • Confirm that the incomplete request is valid JSON with only the jobId key.
  • Still stuck? Help me reproduce the naive endpoint accepting an incomplete archive job.

You proved the processor runs. Next, you will use this false success to make incomplete jobs fail at the API boundary.

Validate Archive Jobs

Your FastAPI endpoint now proves the processor can return a ready response. The incomplete JSON test also exposed a dangerous gap: a job can reach downstream logic without a course or lesson.

A Pydantic request model sets the fields every archive job must provide. In this step, you'll use that model to block incomplete requests before the endpoint processes them.

In this step, get ready to:
  • Define the required archive job fields.
  • Connect the request model to the processing endpoint.
  • Test rejected and accepted archive jobs.
Define the archive job schema

The running Uvicorn process is still using the naive endpoint. You need to stop that process before changing the request boundary.

  • Switch back to the PowerShell terminal from earlier.
  • Press Ctrl+C to stop the current server.

The terminal returns to the PowerShell prompt. Your .venv environment remains activated.

The request schema belongs near the top of main.py. This keeps the required input shape separate from the endpoint that uses it.

  • Switch back to main.py from earlier.
  • Find the section from from fastapi import FastAPI through app = FastAPI().
  • Replace that section with the imports, app setup, and request model below:
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class ArchiveJob(BaseModel):
    jobId: str
    course: str
    lesson: str

What does this model do?

  • The BaseModel import gives ArchiveJob a schema that FastAPI can validate.
  • The jobId field identifies the archive job.
  • The course and lesson fields identify the material that later processing logic needs.
  • Each field is required because none of the annotations has a default value.
  • Save main.py.

The saved file now contains an ArchiveJob schema with three required strings.

Seeing an editor warning?

  • Confirm that BaseModel uses the same capitalization as the import.
  • Confirm that the editor is using the interpreter from the existing .venv environment.
  • Still stuck? Help me fix the Pydantic import or ArchiveJob model in main.py.
Connect validation to the endpoint

A request model validates traffic only when the endpoint uses that model as its parameter type. The response can then read each approved field from the validated ArchiveJob object.

  • Find the @app.post("/process") decorator in main.py.
  • Select the decorator through the end of the existing process_archive_job() function.
  • Replace the selected function with the validated endpoint below:
@app.post("/process")
async def process_archive_job(job: ArchiveJob):
    print(f"Processed archive job: {job.jobId}", flush=True)
    return {
        "message": "Archive job accepted",
        "jobId": job.jobId,
        "course": job.course,
        "lesson": job.lesson,
        "status": "ready",
        "processedBy": "Python",
    }

How does the endpoint change?

  • The job: ArchiveJob annotation tells FastAPI to validate the request body against the model before running the function.
  • The print() call writes the processed job identifier to the server output.
  • The flush=True argument makes the log line available immediately.
  • The returned dictionary reads every job detail from the validated model.
  • Save main.py.

The saved endpoint now accepts an ArchiveJob object instead of an unrestricted dictionary.

✔️ Awesome, I've got everything!

Your request model and processing endpoint now match the validated processor.

ⓧ I'd like to double check the full code

The complete main.py file should match this reference.

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class ArchiveJob(BaseModel):
    jobId: str
    course: str
    lesson: str


@app.post("/process")
async def process_archive_job(job: ArchiveJob):
    print(f"Processed archive job: {job.jobId}", flush=True)
    return {
        "message": "Archive job accepted",
        "jobId": job.jobId,
        "course": job.course,
        "lesson": job.lesson,
        "status": "ready",
        "processedBy": "Python",
    }

What should match?

The file has two imports, one ArchiveJob model, and one process_archive_job() endpoint. The endpoint returns each field explicitly after validation succeeds.

Test rejected and accepted jobs

The typed endpoint gives FastAPI enough information to validate each request body before processing begins. Restarting the server loads the new model into the interactive API page.

Before you restart the server, what should happen when an incomplete request reaches the typed endpoint? Make your prediction now.

  • Restart Uvicorn with the updated main.py file by running:
uvicorn main:app --host 0.0.0.0 --port 8000

What does this command do?

  • The main:app value loads the app object from main.py.
  • The --host 0.0.0.0 option binds the server beyond loopback.
  • The --port 8000 option keeps the interactive API page available on port 8000.

You'll see server startup output in the terminal. This confirms the updated file loaded without a Python syntax error.

Server not starting?

  • Check that the three fields inside ArchiveJob use the same four-space indentation.
  • Check that the return dictionary remains inside process_archive_job().
  • Still stuck? Help me fix the startup problem in my validated FastAPI endpoint.

Before you test the incomplete job, do you think the request reaches process_archive_job() or stops during validation? Hold that prediction.

  • Switch back to the interactive API page from earlier at http://127.0.0.1:8000/docs.
  • Refresh the page.
  • Expand the POST /process operation.
  • Click Try it out.
  • Replace the request body with the same incomplete job you submitted earlier.
  • Click Execute.

You'll see a validation error that identifies course and lesson as missing. The incomplete job stops before the processing function can report it as ready.

Before you run the complete sample again, which values do you expect the structured response to preserve? Make your prediction now.

  • Replace the incomplete request body with the complete sample job from earlier.
  • Click Execute.

You'll see archive-001 with Machine Learning Foundations in the structured response. The response also includes ready and Python.

  • Switch back to the PowerShell terminal running Uvicorn.

You'll see Processed archive job: archive-001 in the server output. This proves the valid request reached process_archive_job().

That's the validation boundary working: incomplete jobs stop at the schema while complete jobs reach the processor.

Your processor now rejects incomplete archive jobs before they reach downstream logic. Next up, you'll package this validated service into a Docker image and inspect it as a running container.

Containerize the Processor

Your FastAPI processor now rejects incomplete archive jobs. Its successful response also prints the accepted job identifier.

The service still depends on your Windows environment. In this step, you'll package it as a Docker container image and launch a running container that is ready for the next project.

In this step, get ready to:
  • Create the container build files.
  • Launch the containerized processor.
  • Trace a valid archive job through the response and logs.
Create the container files

A Dockerfile defines the recipe for building the processor image. A .dockerignore file keeps the local environment and Python cache files outside that image.

Why Docker here?

A Windows-hosted process depends on the Python installation and packages available on one computer. A container carries the processor's runtime setup in a reusable package.

This approach prepares the service for container-to-container networking with n8n in the next project. The same image can run without rebuilding the Windows setup by hand.

  • Switch back to the PowerShell terminal where Uvicorn is running.
  • Stop the local server by pressing Ctrl+C.
  • Use the file creation control beside python-archive-processor in Visual Studio Code to create Dockerfile.
  • Define the image build steps in Dockerfile by pasting this code:
FROM python:3.14.10-slim

WORKDIR /code

COPY requirements.txt /code/requirements.txt
RUN pip install --no-cache-dir -r /code/requirements.txt

COPY main.py /code/main.py

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

What does this Dockerfile do?

  • The FROM python:3.14.10-slim line gives the processor a pinned Python runtime.
  • The WORKDIR instruction gives the application a predictable location inside the image.
  • The first COPY instruction adds the pinned dependency list before installation.
  • The RUN instruction installs FastAPI, Pydantic, and Uvicorn inside the image.
  • The final COPY instruction adds the validated processor code.
  • The CMD instruction starts Uvicorn on port 8000 when the container launches.
  • Save Dockerfile.
  • Check the file list in Visual Studio Code.

You should see Dockerfile beside main.py and requirements.txt.

Dockerfile missing from the project?

  • Check that you created Dockerfile directly inside python-archive-processor.
  • Confirm the filename has no hidden .txt extension.
  • Still stuck? Help me check my Dockerfile location and contents.
  • Use the file creation control beside python-archive-processor to create .dockerignore.
  • Define the files excluded from the image by pasting this code into .dockerignore:
.venv/
__pycache__/
*.pyc

What does this file exclude?

  • The .venv/ entry keeps the Windows virtual environment outside the Linux image.
  • The __pycache__/ entry excludes generated Python cache directories.
  • The *.pyc entry excludes compiled Python cache files.
  • Save .dockerignore.
  • Check the file list in Visual Studio Code.

You should now see Dockerfile and .dockerignore alongside the two existing project files.

Can't see .dockerignore?

  • Confirm the filename begins with a single dot.
  • Check that the file was created inside python-archive-processor.
  • Still stuck? Help me find or create my .dockerignore file.

✔️ Awesome, I've got everything!

Your four project files are in place. The processor is ready to become a Docker image.

ⓧ I'd like to double check the full code

  • Compare each file in python-archive-processor with the complete versions below.
fastapi==0.162.0
pydantic==2.14.2
uvicorn==0.54.0
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class ArchiveJob(BaseModel):
    jobId: str
    course: str
    lesson: str


@app.post("/process")
async def process_archive_job(job: ArchiveJob):
    print(f"Processed archive job: {job.jobId}", flush=True)
    return {
        "message": "Archive job accepted",
        "jobId": job.jobId,
        "course": job.course,
        "lesson": job.lesson,
        "status": "ready",
        "processedBy": "Python",
    }
FROM python:3.14.10-slim

WORKDIR /code

COPY requirements.txt /code/requirements.txt
RUN pip install --no-cache-dir -r /code/requirements.txt

COPY main.py /code/main.py

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
.venv/
__pycache__/
*.pyc
Build and run the Docker container

An image is the packaged processor blueprint. A container is the running instance created from that image.

The first build can take a little longer because Docker may need to download the base image.

  • Build the archive-processor image from the current project files by running:
docker build -t archive-processor .

What does this command do?

  • The docker build command follows the instructions in Dockerfile.
  • The -t archive-processor option gives the completed image a reusable name.
  • The final . uses the current python-archive-processor folder as the build context.

You should see the build steps finish before PowerShell returns to its prompt. That's the portability milestone reached: your validated processor now exists as a reusable image.

Image build not completing?

  • Confirm Docker Desktop is running.
  • Check that the terminal prompt ends in python-archive-processor.
  • Compare the dependency names in requirements.txt with the full-code tab above.
  • Still stuck? Help me troubleshoot my Docker image build.
  • Start the processor in a detached container with a host-only mapping by running:
docker run -d --name archive-processor -p 127.0.0.1:8000:8000 archive-processor

How is the container launched?

  • The -d option runs the container in the background.
  • The --name archive-processor option gives the container a stable name for later log commands.
  • The -p 127.0.0.1:8000:8000 option publishes the container's port only through the host loopback address.
  • The final archive-processor value selects the image you just built.

You should see a long container identifier in PowerShell. That identifier confirms Docker started the processor in the background.

Container not starting?

  • Confirm the image build completed before retrying the run command.
  • Make sure the local Uvicorn process remains stopped so port 8000 is available.
  • Still stuck? Help me start my archive-processor container.
Test the container and inspect its logs

The interactive docs prove the container can process a validated request. The logs prove the request reached the Python function inside the container.

Before you submit the request, do you expect the containerized processor to preserve the same successful response as the local server?

  • Return to the browser tab containing the interactive API page.
  • Refresh http://127.0.0.1:8000/docs.
  • Expand POST /process.
  • Select Try it out.
  • Replace the generated jobId value with archive-001.
  • Replace the generated course value with Machine Learning Foundations.
  • Replace the generated lesson value with Introduction.
  • Select Execute.

You should see Archive job accepted with ready status. The response also includes archive-001, Machine Learning Foundations, and Python.

You have now preserved the processor's validated response inside Docker. The container behaves like the local service you built.

Before you inspect the logs, do you think the accepted job identifier was printed inside the container?

  • Fetch the output from the running container by running:
docker logs archive-processor

What does this command show?

The docker logs command fetches output written by the process inside archive-processor. The flush=True setting makes the processed job line available immediately.

You'll see Processed archive job: archive-001 in the output. This proves the valid request reached process_archive_job() inside the container.

That's the portability check complete. Your containerized processor returned the validated result from its reusable image.

Processed job missing from the logs?

  • Confirm the interactive docs returned a successful response for archive-001.
  • Check that the log command names archive-processor.
  • Submit the valid request again before fetching the logs once more.
  • Still stuck? Help me find my processed archive job in the container logs.

Secret mission

Reject Empty Job Details

A required string can still be empty. Add Pydantic length constraints to block blank job details. Rebuild the image to prove invalid requests fail while valid requests keep the same response.

Clean Up Your Resources

Clean Up Your Resources

Everything here runs on your Windows machine, so there are no ongoing service charges. Decide whether to keep the processor running, stop the container for later, or remove the local resources that use disk space.

Resources you used:

  • The running archive-processor Docker container.
  • The archive-processor Docker image.
  • The .venv environment inside python-archive-processor.
  • The requirements.txt, main.py, Dockerfile, and .dockerignore files inside python-archive-processor.

Keep everything running

No action is needed. Choose this if you plan to connect the processor to n8n in Project 4.

  • Your archive-processor container stays running.
  • Your interactive API page remains available at http://127.0.0.1:8000/docs.
  • Your archive-processor image remains ready for future containers.
  • Your python-archive-processor folder remains available for Project 4.

Pause - I'll come back to this later

Pausing stops the processor from running while preserving the container, image, environment, and project files. You can restart the same container when you return.

  • Stop the running processor by running this command:
docker stop archive-processor

What does this command do?

Docker stops the process inside archive-processor. The terminal prints the container name when the stop succeeds.

The stopped container remains available for a later restart.

  • Check the terminal for archive-processor to confirm the stop completed.

Container Won't Stop?

  • Confirm Docker Desktop is running.
  • Ask for help with the stop command.
  • Resume the preserved processor later by running this command:
docker start archive-processor

What does this command do?

Docker starts the preserved archive-processor container. The processor becomes available through the same host-only port.

  • Open http://127.0.0.1:8000/docs in your browser to confirm the interactive API page loads again.

Processor Won't Resume?

  • Confirm Docker Desktop is running before retrying the start command.
  • Ask for help restarting the preserved container.

Delete - I don't want to use this again

Deleting these resources is permanent, so this option is for starting over. Keep python-archive-processor if you plan to continue to Project 4.

  • Remove the container and its image by running these commands:
docker stop archive-processor
docker rm archive-processor
docker image rm archive-processor

What do these commands remove?

  • The docker stop archive-processor command stops the local processor.
  • The docker rm archive-processor command removes the stopped container.
  • The docker image rm archive-processor command removes the reusable image from local storage.
  • Return to Docker Desktop to confirm no container named archive-processor remains.
  • Confirm no image named archive-processor remains.

Docker Resource Still Listed?

  • Confirm Docker Desktop is running before retrying the commands.
  • Check Docker Desktop for another container using the archive-processor image.
  • Ask for help removing the remaining resource.
  • Close Visual Studio Code.
  • Use File Explorer to delete python-archive-processor only if you do not need it for Project 4.
  • Check File Explorer to confirm python-archive-processor is no longer listed.

Nice Work!

Nice Work!

You did it! Your validated Python archive processor now runs inside a Docker container.

You've learned how to:

  • Turn archive-job JSON into a structured ready response through an HTTP POST endpoint.
  • Experience a designed failure where an untyped request accepted incomplete data. Apply required-field validation with FastAPI and Pydantic to reject incomplete jobs.
  • Package the service as a pinned Docker image. Reach the processor through a host-only published port. Inspect container logs for Processed archive job.
  • Complete the optional Secret Mission by applying minimum-length constraints that reject empty job details.

Ready to quiz yourself?