Published on: 2023-11-22
In modern development, decoupling frontend and backend provides scalability and clean architecture. This guide walks you through building:
โ
A Symfony API
โ
A Vue 3 frontend using Pinia for state management
โ
Clear integration with Mermaid visualizations
๐ ๏ธ Project Overview
๐ง Part 1 Create Symfony API
1 Install Symfony Skeleton
composer create-project symfony/skeleton my_api_project
2 Install Required Bundles
composer require api symfony/orm-pack
composer require symfony/maker-bundle --dev
3 Configure Database
In .env:
DATABASE_URL="mysql://db_user:db_password@127.0.0.1:3306/my_api_db?serverVersion=8.0"
Create the database:
php bin/console doctrine:database:create
4 Create Task Entity
php bin/console make:entity
Define:
name(string, 255)completed(boolean)
Run migrations:
php bin/console make:migration
php bin/console doctrine:migrations:migrate
5 Expose API Resource
API Platform auto-exposes your entities. Start server:
symfony server:start
Navigate to:
https://localhost:8000/api
for Swagger UI auto-generated docs.
๐ฅ๏ธ Part 2 Create Vue 3 + Pinia Frontend
1 Create Vue 3 App
npm create vite@latest my-vue-app -- --template vue
cd my-vue-app
npm install
2 Install Pinia & Axios
npm install pinia axios
3 Setup Pinia in main.js
import { createApp } from "vue";
import App from "./App.vue";
import { createPinia } from "pinia";
const app = createApp(App);
app.use(createPinia());
app.mount("#app");
4 Create Pinia Store
src/stores/taskStore.js:
import { defineStore } from "pinia";
import axios from "axios";
export const useTaskStore = defineStore("taskStore", {
state: () => ({
tasks: [],
}),
actions: {
async fetchTasks() {
try {
const res = await axios.get("https://localhost:8000/api/tasks");
this.tasks = res.data["hydra:member"];
} catch (error) {
console.error("Error fetching tasks:", error);
}
},
},
});
5 Use Store in Component
Example TaskList.vue:
<script setup>
import { onMounted } from "vue";
import { useTaskStore } from "./stores/taskStore";
const taskStore = useTaskStore();
onMounted(() => {
taskStore.fetchTasks();
});
</script>
<template>
<div>
<h1>Tasks</h1>
<ul>
<li v-for="task in taskStore.tasks" :key="task.id">
{{ task.name }} - {{ task.completed ? "โ
" : "โ" }}
</li>
</ul>
</div>
</template>
6 Frontend Data Flow
๐ Part 3: Handle CORS
Install Nelmio CORS Bundle:
composer require nelmio/cors-bundle
In config/packages/nelmio_cors.yaml:
nelmio_cors:
defaults:
allow_origin: ["*"]
allow_methods: ["GET", "OPTIONS", "POST", "PUT", "DELETE"]
allow_headers: ["Content-Type", "Authorization"]
max_age: 3600
paths:
"^/api/":
allow_origin: ["http://localhost:5173"] # Vite dev server URL
allow_headers: ["Content-Type", "Authorization"]
allow_methods: ["GET", "OPTIONS", "POST", "PUT", "DELETE"]
max_age: 3600
โ Part 4: Run & Test
- Start Symfony backend:
symfony server:start - Start Vue app:
npm run dev - Navigate to your frontend, and your tasks should load from the Symfony API seamlessly.
๐ฏ Next Steps
- Implement POST, PUT, DELETE actions in API and Pinia
- Add JWT authentication for secure routes
- Refactor frontend logic with Composables for reusability
- Deploy backend and frontend with separate pipelines
Using Symfony as a decoupled API backend with Vue 3 + Pinia frontend offers a modern, maintainable, and scalable architecture for your applications. The above visualizations and step-by-step approach will guide your next production-ready builds efficiently.