# FastAPI for AI Engineers - Part 8: Uploading Files with FastAPI

> Source: <https://dev.to/zeroshotanu/fastapi-for-ai-engineers-part-8-uploading-files-with-fastapi-4f9b>
> Published: 2026-08-31 15:37:39+00:00

In the previous article, we learned how to secure our APIs using JWT Authentication and protect routes from unauthorized access.

Now let's explore another feature used in almost every AI application—**file uploads**.

If you've built applications like ChatGPT, document Q&A systems, resume analyzers, legal contract reviewers, or medical report analyzers, one thing is common across all of them:

**The user uploads a file.**

Without file uploads, there is nothing for the AI model to process.

If you haven't read the previous article, check it out first to continue the series:

[Protecting routes with JWT Tokens](https://dev.to/zeroshotanufastapi-for-ai-engineers-part-7-protecting-routes-with-jwt-tokens-273p)

Consider some popular AI applications:

The workflow usually looks like this:

```
  User
   │
   ▼
Upload File
   │
   ▼
FastAPI
   │
   ▼
Save / Read File
   │
   ▼
Process using AI
```

FastAPI makes uploading files extremely simple.

FastAPI uses **python-multipart** to process uploaded files.

Install it using:

```
pip install python-multipart
```

FastAPI provides two important classes:

`File`

`UploadFile`

Let's import them.

``` python
from fastapi import FastAPI, File, UploadFile

app = FastAPI()
python
@app.post("/upload")
def upload_file(file: UploadFile):

    return {
        "filename": file.filename
    }
```

Run the application.

Open Swagger UI.

Click **POST /upload**.

You'll notice FastAPI automatically provides a file picker.

Upload a file.

Response:

```
{
    "filename": "resume.pdf"
}
```

Our API successfully received the uploaded file.

You might wonder:

Why didn't we simply use a string or bytes?

FastAPI provides the `UploadFile`

class because it contains useful information about the uploaded file.

Some commonly used attributes are:

```
file.filename
```

Returns:

```
resume.pdf
file.content_type
```

Returns:

```
application/pdf
await file.read()
```

Reads the file contents.

These attributes become extremely useful when building AI applications.

Suppose we want to know how many bytes were uploaded.

``` python
@app.post("/upload")
async def upload_file(file: UploadFile):

    contents = await file.read()

    return {
        "filename": file.filename,
        "size": len(contents)
    }
```

Example response:

```
{
    "filename": "contract.pdf",
    "size": 254321
}
```

Notice that we changed the function to:

```
async def
```

This is because `file.read()`

is an asynchronous operation.

In many applications, we don't just read the file.

We save it for later processing.

``` python
@app.post("/upload")
async def upload_file(file: UploadFile):

    contents = await file.read()

    with open(file.filename, "wb") as f:
        f.write(contents)

    return {
        "message": "File uploaded successfully."
    }
contents = await file.read()
```

Reads the uploaded file into memory.

```
with open(file.filename, "wb")
```

Creates a new file.

The `"wb"`

mode means:

Binary mode is important because PDFs, images, Word documents, and many other files are not plain text.

```
f.write(contents)
```

Writes the uploaded data to disk.

Suppose a user uploads a legal contract.

```
   contract.pdf
        │
        ▼
FastAPI Upload Endpoint
        │
        ▼
     Save PDF
        │
        ▼
    Extract Text
        │
        ▼
Create Embeddings
        │
        ▼
Store in Vector Database
        │
        ▼
   Ask Questions
```

This is the same workflow followed by many Retrieval-Augmented Generation (RAG) applications.

Similarly,

Resume Analyzer:

```
Resume.pdf
      │
      ▼
Extract Text
      │
      ▼
Skill Extraction
      │
      ▼
  ATS Score
```

Medical Report Analyzer:

```
Blood_Report.pdf
        │
        ▼
OCR / Text Extraction
        │
        ▼
  LLM Analysis
        │
        ▼
  Health Summary
```

File uploads are the entry point for almost every document-based AI application.

FastAPI also allows uploading files as raw bytes.

``` python
@app.post("/upload")
async def upload(file: bytes = File()):

    return {
        "size": len(file)
    }
```

Although this works, it is rarely used for large files.

`UploadFile`

is generally preferred because:

For most production applications, **UploadFile** is the recommended choice.

``` python
from fastapi import FastAPI, UploadFile

app = FastAPI()

@app.post("/upload")
async def upload_file(file: UploadFile):

    contents = await file.read()

    with open(file.filename, "wb") as f:
        f.write(contents)

    return {
        "filename": file.filename,
        "content_type": file.content_type,
        "size": len(contents),
        "message": "Upload Successful"
    }
User Uploads File
        │
        ▼
FastAPI Receives Upload
        │
        ▼
UploadFile Object Created
        │
        ▼
    Read File
        │
        ▼
    Save File
        │
        ▼
AI Processing Begins
```

Uploading files is one of the most important capabilities of modern AI backends.

Whether you're building a chatbot over PDFs, a resume analyzer, a legal contract assistant, or a medical report analyzer, every application begins with accepting user files.

Today we learned how to:

`UploadFile`

objectIt's been some time since I've uploaded. We will continue with our FastAPI series in the upcoming posts.
