Hello! Over the past few lessons, you've acquired a powerful set of skills for building dynamic web applications with Vue. You've learned how to:
- Install and configure Vue Router to create a Single-Page Application (SPA).
- Define static and dynamic routes to map URLs to specific view components.
- Navigate between these views using
<RouterLink>. - Fetch data from an API using the
onMountedlifecycle hook. - Professionally manage loading and error states to improve user experience.
In this lesson, we'll bring all of these concepts together to complete the mini-project for this module.
Your goal is to build a two-page application that fetches a list of items from an API and displays details for each item on a dynamic route page. This project will solidify your understanding of how to build a core, and very common, piece of functionality found in countless web applications.
Project Overview: The "VueMart" Product Catalog
We're going to build a simple e-commerce-style product catalog. The application will have two main pages:
- A Home Page (
/): This page will fetch and display a list of all available products. - A Product Detail Page (
/product/:id): This is a dynamic route. When a user clicks on a product from the home page, they will be taken here to see more details about that specific product.
This project will require you to structure your routes, fetch data for both a list and a single item, and handle all the navigation and state management in between.
Part 1: Project Setup
Before we write any Vue code, let's get our project foundation and data source ready.
1. Data Source: json-server
Just as in our previous lessons, we'll use json-server to create a mock REST API.
-
In your project directory, create a file named
db.json. -
Paste the following product data into
db.json:{ "products": [ { "id": 1, "title": "Ergonomic Office Chair", "description": "A comfortable and supportive chair designed for long hours of work. Features adjustable height, lumbar support, and breathable mesh back.", "price": 249.99 }, { "id": 2, "title": "Wireless Mechanical Keyboard", "description": "A compact 75% layout keyboard with tactile switches, RGB backlighting, and dual-mode connectivity (Bluetooth & USB-C).", "price": 119.00 }, { "id": 3, "title": "4K Ultra-HD Monitor", "description": "A 27-inch IPS monitor with 4K resolution, 99% sRGB color gamut, and thin bezels. Perfect for content creation and gaming.", "price": 429.50 }, { "id": 4, "title": "Noise-Cancelling Headphones", "description": "Over-ear headphones with industry-leading active noise cancellation, 30-hour battery life, and crystal-clear audio.", "price": 349.00 } ] } -
Open a separate terminal window, navigate to your project folder, and run
json-serverto start the mock API:json-server --watch db.json --port 3001You can now access your products at
http://localhost:3001/products.
2. Vue Router Configuration
Now, let's define the routes for our application. We need a route for the home page and a dynamic route for the product detail page.
Open src/router/index.js and configure your routes array. It should look like this:
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/product/:id', // The dynamic segment is ':id'
name: 'ProductDetail',
// Route-level code-splitting for better performance
component: () => import('../views/ProductDetailView.vue')
}
]
})
export default router
You will also need to create the ProductDetailView.vue file inside the src/views directory. You can leave it empty for now; we'll build it in Part 3.

Part 2: Building the Home Page (Product List)
The HomeView.vue component will be responsible for fetching all products and displaying them as a list of links.
Your task is to implement src/views/HomeView.vue with the following logic:
- Fetch Data: In the
<script setup>block, userefto create reactive variables forproducts,loading, anderror. Use theonMountedhook to fetch data fromhttp://localhost:3001/products. - Handle States: Implement the
try...catch...finallypattern you learned in the last lesson to manage theloadinganderrorstates. - Render the List:
- In the template, use
v-if="loading"to show a "Loading..." message. - Use
v-else-if="error"to show an error message. - Use
v-else-if="products"and av-forloop to iterate over theproductsarray.
- In the template, use
- Link to Detail Page: For each product in the loop, render a
<RouterLink>. Thetoprop of this link should be dynamically bound to the correct path, like'/product/' + product.id.
The video below is an excellent refresher on this entire process, from creating the dynamic route to linking to it from a list.
Vue Router 4 Dynamic Routes | Vue Router 4 tutorial
Watch this video by Tony Xhepa to see a complete walkthrough of fetching a list, creating dynamic links with RouterLink, and setting up the corresponding detail page. The example uses movies, but the concept is identical to our products.
Watch the entire video (about 11 minutes). Pay close attention to how he: Defines the dynamic route in the router file (00:25). Fetches the list of items in one component (similar to our HomeView). Uses <RouterLink> with a bound :to prop to create links like /movies/:id (09:53). Fetches a single item's data in the detail view using the route parameter (02:08).
Part 3: Building the Product Detail Page
This is where the magic of dynamic routing happens. ProductDetailView.vue will render the details of any product based on the ID in the URL.
Your task is to implement src/views/ProductDetailView.vue:
- Get Route Parameter: Use the
useRoutecomposable fromvue-routerto get access to the current route's details. The product ID will be available atroute.params.id. - Fetch Single Item: Just like on the home page, set up reactive refs for
product,loading, anderror. In theonMountedhook, use theidfrom the route parameters to construct your fetch URL (e.g.,`http://localhost:3001/products/${route.params.id}`). - Handle States: Again, use a
try...catch...finallyblock for robust loading and error handling. This is especially important here, as a user could manually type in an invalid ID (e.g.,/product/999), which would cause a 404 error fromjson-server. Your app should handle this gracefully. - Render Details: In your template, use
v-if/v-else-ifto show the loading, error, or product data. If the product exists, display its title, description, and price.
For a deeper look at dynamic routing and accessing parameters, this resource is very helpful.
Vue 3 Routing - Beginner to Advanced
This video from Laiture provides a deep dive into dynamic routing. It's a great supplement if you want to reinforce the 'why' behind this pattern.
Focus on the segment from 32:57 to 42:31. This part specifically explains why we use one dynamic component (CarView.vue in his example) instead of many static ones, and it shows exactly how to use the useRoute composable to access the dynamic :id parameter.

Project Checklist and Final Touches
Use this checklist to make sure you've completed all the requirements.
Core Functionality:
-
json-serveris set up with product data and running. -
router/index.jsdefines a root route (/) and a dynamic product route (/product/:id). -
HomeView.vuefetches and displays the list of all products. -
HomeView.vueshows a loading state during the fetch. - Each product in the list correctly links to its detail page (e.g.,
/product/2). -
ProductDetailView.vuecorrectly extracts theidfrom the URL. -
ProductDetailView.vuefetches and displays the correct single product's data. -
ProductDetailView.vueshows a loading state during its fetch. - Error Handling: Both views gracefully handle API errors (you can test this by stopping
json-serveror navigating to an invalid ID like/product/999).
Best Practice (Bonus):
- Add a "Back to Products" link on the
ProductDetailView.vuepage using<RouterLink to="/">. - Implement a "404 Not Found" page for routes that don't match anything, as shown in the LogRocket article or the Laiture video. This involves adding a "catch-all" route at the end of your routes array.
The ultimate guide to Vue Router
For a text-based guide on the entire process, including dynamic routing and handling 404s, this LogRocket article is an excellent reference.
Review the sections on 'Dynamic routing', 'Navigating between routes', and 'Handling 404 errors'. They provide clear code examples for the concepts you're implementing in this project.
Conclusion
Congratulations! By completing this mini-project, you have successfully built a core component of a modern web application: a multi-page experience that fetches and displays dynamic data from an API. You've demonstrated your ability to manage routing, handle asynchronous operations, and create a resilient user experience. The List -> Detail pattern is something you will build time and time again in your career.
Key Takeaways:
- Vue Router is the backbone of SPAs: It allows you to create different "pages" within a single application.
- Dynamic routes are powerful: They enable you to create flexible, data-driven pages without repeating code.
- Data fetching and routing are intertwined: You often need to fetch data based on the current route, and
useRouteis the key to that connection. - Robust state management is non-negotiable: A professional application must always provide feedback to the user, whether it's loading or encountering an error.
Our "VueMart" app is now fully functional, but it's not much to look at. In our next module, Styling Vue Applications with Tailwind, we'll dive into the world of utility-first CSS to rapidly build beautiful, responsive interfaces for the applications you now know how to create.