How to build an image converter service with FastAPI and deploy it on Deta | Python.
Published: 2022-12-16 14:46:28

---
title: How to build an image converter service with FastAPI and deploy it on Deta | Python.
published: true
date: 2022-10-19 16:26:55 UTC
tags: 
canonical_url: https://carlosmv.hashnode.dev/how-to-build-an-image-converter-service-with-fastapi-and-deploy-it-on-deta-python
---

I have been using Deta for a month and I think is great. It allows you to deploy hobby projects for free, also you have access to Deta Drive to store files.

Prerequisites:

- Basic knowledge of Python

- FastAPI 

Here is what the [documentation](https://docs.deta.sh/docs/home) says about Deta and its services:

Deta:

> Deta is a free cloud crafted with the developer and user experience at heart.
> 
> It is our mission to dramatically reduce the gap between ideas and working cloud applications

Deta Micros:

> Deta Micros are a lightweight but scalable cloud runtime tied to an HTTP endpoint. They are meant to get your apps up and running blazingly fast. Focus on writing your code and Deta will take care of everything else.

Deta Drive:

> Deta Drive is a managed, secure, and scalable file storage service with a focus on end-user simplicity.

In this article, we are going to build a service that allows the user to upload an image file to Deta Drive, convert it to another format, and download it.

To simplify this article, the service will take`.webp` images and convert them to `.png` using the Pillow library.

We need to create an account in Deta first, go to its [website](https://www.deta.sh/), and create one by clicking on "Join Deta".

### Installing Deta

To create a Deta Micro we need to install Deta CLI.

Windows, via PowerShell

```
iwr https://get.deta.dev/cli.ps1 -useb | iex

```

MacOS and Linux

```
curl -fsSL https://get.deta.dev/cli.sh | sh

```

After Deta CLI is installed and added as an environment variable, we need to login.

```
data login

```

### Creating a Deta Project

To create a project, we go to our home page and select "+ New project".

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1666020627347/dhykdP1-_.png)

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1666020701399/P0jYJjtXa.png)

Then on our machine, we open a terminal, and inside the folder where we want to place our project we create a new micro.

```
deta new --python image_converter --project image_converter

```

If everything is ok, we will see the message "Successfully created a new micro" displayed in our terminal, with the info of our micro.

```
{
"name": "image_converter",
"id": "id",
"project": "project",
"runtime": "python 3.9",
"endpoint": "https://ce4de8.deta.dev",
"region": "sa-east-1",
"visor": "disabled",
"http_auth": "disabled"

}

```

Now, we installed our virtual environment and packages.

```
py -m venv venv

cd venv/Scripts
activate
cd..
cd..


pip install fastapi uvicorn python-multipart python-dotenv pillow deta

```

We go to our Deta home page, select "Project Keys", and click on "Create Key".

Then we copy the project key into our `.env` file.

main.py

```
from fastapi import FastAPI, File, UploadFile, HTTPException
from fastapi.responses import HTMLResponse, StreamingResponse
from PIL import Image
from dotenv import load_dotenv

from deta import Deta
from io import BytesIO
import os

app = FastAPI()

load_dotenv()

PROJECT_KEY = os.environ.get('PROJECT_KEY')
deta = Deta(PROJECT_KEY)

drive = deta.Drive("webp_images")

```

We import to `main.py` all the packages we are going to use. Create a FastAPI instance and load our environment variable.

We create a Deta Drive instance. "webp\_images" is our drive's name.

### Uploading a file.

```
@app.get("/", response_class=HTMLResponse)
def render():
    return """
    <form action="/upload" enctype="multipart/form-data" method="post">
        <input name="file" type="file">
        <input type="submit">
    </form>

    """

```

In the same file(we are going to use only the `main.py` file) we create a `GET` endpoint to show a form to upload webp image files.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1666108640011/ZJmvgjb-X.png)

```
def webp_to_png(image):

    try:
        img = Image.open(image)
        img_io = BytesIO()
        img.save(img_io , 'PNG')
        img_io.seek(0)
    except Exception:
        return "Unable to open the image file." 

    finally:
        img.close()
    return img_io

```

This is the function we use to convert the ".webp" image to a ".png" image.

Here we open the image file and create an instance of `BytesIO()`.

The method `Save()` receives a filename (string), `pathlib.Path` object, or file object as first parameter. We are passing a file object. The second parameter is the format.

```
@app.post("/upload")
def upload_image(file: UploadFile = File(...)):

    if not file.filename.endswith(".webp") or not file:
        raise HTTPException(status_code=400 , detail = "Select a '.webp' file")

    webp_name = file.filename
    image = file.file

    try:

        img = webp_to_png(image)
        png_name = webp_name.replace(".webp", ".png")
        res = drive.put(png_name, img)   
        return JSONResponse(status_code =status.HTTP_201_CREATED, content={"message": f"Image: '{res}' successfully uploaded."})  
    except:
        return JSONResponse(status_code=500, content="There was an error converting or uploading the file")

```

In the `POST` endpoint, here we handle the uploaded file. It will raise an HTTP exception if the file doesn't have a ".webp" extension or no file is selected.

The code will upload the file if there is no problem converting or in the uploading process.

We can go to our Deta home page and check the uploaded file by clicking "Deta Drive". It will show a UI with the files uploaded to our drive.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1666109213662/zZgf1cnnQ.png)

### Downloading Images

```
@app.get("/convert/{name}")
def converter(name: str):

    res = drive.get(name)

    if res is None:
        raise HTTPException(status_code=404, detail="Image not found")

    return StreamingResponse(res.iter_chunks(1024), media_type="image/png")

```

With this endpoint, we check if the file is in the drive, if it is, it will be downloaded.

To retrieve a file we have to include the extension of the image file, in this case, ".png".

Now, the last thing to do is deploy our micro.

In our terminal we execute this command:

```
deta deploy

```

We have to make sure the command is executed inside the directory where is the `.deta` folder.

### Conclusion

Deta is simple to use, and for me, it was easy to follow the documentation and tutorials to deploy a micro. Deta supports NodeJS and Python for Deta Micros, Deta Base, and Deta Drive. And there are tutorials for each service using Python and NodeJS.

They have examples of using Deta Drive and Deta Base with Go. I hope in the future we will be able to deploy micros in other languages.

Thank you for taking the time to read this article.

If you have any recommendations about other packages, architectures, how to improve my code, my English, or anything; please leave a comment or contact me through [Twitter](https://twitter.com/Carlos_marcv), or [LinkedIn](https://www.linkedin.com/in/carlos-marcano-a2135a134/).

The source code is [here](https://github.com/carlosm27/deta_fastapi_demo).

### References.

- [Pillow Documentation.](https://pillow.readthedocs.io/en/stable/installation.html)

- [FastAPI Documentation.](https://fastapi.tiangolo.com/)

- [Deta Micros Documentation.](https://docs.deta.sh/docs/micros/about)

- [Deta Drive Documentation.](https://docs.deta.sh/docs/drive/about)

- [Deta Micro Getting Started.](https://docs.deta.sh/docs/micros/getting_started/)

- [Deta Base Python Tutorial.](https://docs.deta.sh/docs/base/py_tutorial/)

- [Deta Drive Python Tutorial.](https://docs.deta.sh/docs/drive/py_tutorial/)