Skip to content
Shop

Use FastAPI with VueJS

April 6, 2025

You will learn how to make a simple backend in fastapi and connect it to a simple vuejs frontend.

What you will need:

  • FastAPI - a web framework for building APIs with Python based on standard Python type hints.
  • Vue CDN - my frontend framework of choice
  • Uvicorn - an ASGI web server implementation for Python.
  • Tailwind CDN (optional) - for fast CSS styling

Project setup

app/
    server/
        main.py
        assets/
            image.jpeg
            image.png
    client/
        index.html

The frontend and backend

VS Code's live server uses 5500 so that was added. You will need to add the origin of your frontend.

python
from typing import Union
import os
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
import base64

app = FastAPI()

# The origins allowed to hit this server
origins = [
    "http://localhost.upskil.dev",
    "https://localhost.upskil.dev",
    "http://localhost",
    "http://localhost:8080",
    "http://localhost:5500",
    "http://127.0.0.1:5500"
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

class FileLister():
    @classmethod
    def get_files(cls,directory,extensions):
        all_files = [f for f in os.listdir(directory) if f.endswith(extensions)]
        return all_files

@app.get("/")
def read_root():
    return {"Hello": "World"}

@app.get("/images")
def get_images():
    all_images = FileLister.get_files('./assets',('.png','.PNG','.jpg','.JPG','.webp','.WEBP','.gif','.jpeg'))
    encoded_images = []
    for i in all_images:
        with open("./assets/"+i, "rb") as image_file:
            encoded_string = base64.b64encode(image_file.read())
            encoded_images.append(encoded_string)
    return {"images": encoded_images}

@app.get("/items/{item_id}")
def read_item(item_id: int, q: Union[str, None] = None):
    return {"item_id": item_id, "q": q}
html
<!DOCTYPE html>
<html lang='en'>

<head>
    <meta charset='UTF-8'>
    <meta http-equiv='X-UA-Compatible' content='IE=edge'>
    <meta name='viewport' content='width=device-width, initial-scale=1.0'>
    <title>FastAPI + Vue</title>
    <script src='https://cdn.tailwindcss.com'></script>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>

<body id="app" class="bg-gray-200">
    <div>
        <nav class="bg-white p-4 w-full">
            <ul class="flex justify-between w-full">
                <li>{{message}}</li>
                <li>FastAPI + Vue</li>
                <li><button @click="fetchData()" class="rounded-lg bg-black text-white px-4 py-2">Get Images</button>
                </li>
            </ul>
        </nav>

        <div class="container mx-auto w-full p-10">
            <main class="w-full">
                <div>
                    <h1>MAIN AREA</h1>
                    <div v-if="response_data" class="mt-4 flex flex-wrap gap-4">
                        <img class="object-cover w-64 h-64 rounded-lg" v-for="i in response_data.images"
                            :src="'data:image/png;base64, '+i">
                    </div>
                </div>
            </main>
        </div>
    </div>

    <script>
        const { createApp, ref } = Vue

        createApp({
            setup() {
                const message = ref('Home');

                const response_data = ref();

                async function fetchData() {
                    try {
                        const response = await fetch("http://127.0.0.1:8000/images");
                        if (!response.ok) {
                            throw new Error(response.statusText)
                        }
                        const data = await response.json();
                        console.log(data)
                        response_data.value = data
                    } catch (error) {
                        console.log(error)
                    }
                }

                return {
                    message, response_data, fetchData
                }
            }
        }).mount('#app')
    </script>

</body>

</html>

TIP

You will need to create the assets directory at the same level as your main.py file and add images to it

Start the FastAPI server

Navigate to your server folder and run the FastAPI server from the terminal

cd server
uvicorn main:app --reload

Open index.html using a server

I used vscode's live server to open the index.html file. You can do this by right clicking on index.html and then clicking Open with Live Server.

Resources