Chapter 5.2: Creating Simple Views for the API
Study time: 45 minutes
1. Task: Visualize the Data
Our API in Chapter 2 can return data in JSON format. This is great for machines, but people prefer to see information on beautifully designed web pages. Our goal is to create two such pages:
- A list of all planets (
/planets
) - A page for a single planet (
/planets/{id}
)
To do this, we will use the "Route → Controller → View" combination.
💡 Space Analogy:
Imagine that the JSON from the API is raw telemetry data, just a stream of numbers. Our task today is to create two screens in Mission Control (two "views"):
- General screen: shows the status of all objects in the system (list of planets).
- Detailed screen: when you click on an object, it displays all the information about it (single planet page).
2. Step 1: Creating a Controller for Web Pages
For the sake of clean architecture, you should not mix the logic of the API and the logic of web pages in one controller. Let's create a new controller specifically for displaying our Blade views.
Execute in the terminal:
We are creating it in theWeb
subdirectory to separate it from the API controllers.
Open the created file app/Http/Controllers/Web/PlanetPageController.php
.
3. Step 2: Page with a List of All Planets
1. Create a method in the controller:
In PlanetPageController
, add an index
method that will get all the planets from the database and pass them to the view.
<?php
namespace App\Http\Controllers\Web;
use App\Http\Controllers\Controller;
use App\Models\Planet; // Don't forget to import the model
class PlanetPageController extends Controller
{
/**
* Shows a page with a list of all planets.
*/
public function index()
{
// 1. Get all planets from the DB
$planets = Planet::all();
// 2. Return the view and pass the data to it
return view('planets.index', ['planets' => $planets]);
}
}
2. Create a Blade view:
Create a file resources/views/planets/index.blade.php
. We will use the layout created in the last chapter.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Planets</title>
<style>
body {
font-family: sans-serif;
background-color: #f4f4f9;
color: #333;
margin: 0;
padding: 2em;
}
.container {
max-width: 960px;
margin: 0 auto;
}
h2 {
color: #1a202c;
}
hr {
border: none;
border-top: 1px solid #e2e8f0;
margin: 1.5em 0;
}
.planet-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1.5em;
}
.planet-card {
background-color: #fff;
border: 1px solid #e2e8f0;
border-radius: 0.5em;
padding: 1.5em;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
transition: transform 0.2s;
}
.planet-card:hover {
transform: translateY(-5px);
}
.planet-card h3 {
margin-top: 0;
color: #2d3748;
}
.planet-card p {
margin-bottom: 0.5em;
color: #4a5568;
}
.planet-card a {
color: #4299e1;
text-decoration: none;
font-weight: bold;
}
.planet-card a:hover {
text-decoration: underline;
}
.no-planets {
color: #718096;
}
</style>
</head>
<body>
<div class="container">
<h2>List of All Known Planets</h2>
<hr>
<div class="planet-list">
@forelse($planets as $planet)
<div class="planet-card">
<h3>{{ $planet->name }}</h3>
<p>Solar System: {{ $planet->solar_system }}</p>
<p>Diameter: {{ number_format($planet->size_km, 0, '.', ' ') }} km</p>
<a href="/planets/{{ $planet->id }}">Learn more →</a>
</div>
@empty
<p class="no-planets">There are no planets in the database. Please run the seeders.</p>
@endforelse
</div>
</div>
</body>
</html>
number_format(...)
is a regular PHP function for nicely formatting numbers. It can be used directly in Blade.
3. Create a route in routes/web.php
:
use App\Http\Controllers\Web\PlanetPageController;
// ...
Route::get('/planets', [PlanetPageController::class, 'index']);
/planets
in your browser, you will see a page with a list of planets!
4. Step 3: Single Planet Page
1. Create a method in the controller:
In PlanetPageController
, add a show
method. Thanks to Route Model Binding, Laravel will automatically find the planet by ID and pass it to the method.
<?php
// Inside the PlanetPageController class
/**
* Shows the page of a single specific planet.
*/
public function show(Planet $planet)
{
// Laravel has already found the planet for us.
// If it is not found, it will automatically return a 404 error.
return view('planets.show', ['planet' => $planet]);
}
2. Create a Blade view:
Create a file resources/views/planets/show.blade.php
.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ $planet->name }}</title>
<style>
body {
font-family: sans-serif;
background-color: #f4f4f9;
color: #333;
margin: 0;
padding: 2em;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
.container {
max-width: 600px;
width: 100%;
}
.planet-detail {
background-color: #fff;
border: 1px solid #e2e8f0;
border-radius: 0.5em;
padding: 2em;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
}
.planet-detail h1 {
margin-top: 0;
color: #2d3748;
}
.planet-detail p {
margin-bottom: 1em;
color: #4a5568;
font-size: 1.1em;
}
.back-link {
display: inline-block;
margin-top: 1.5em;
color: #4299e1;
text-decoration: none;
font-weight: bold;
}
.back-link:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<div class="container">
<div class="planet-detail">
@if($planet->image_url)
<img src="{{ $planet->image_url }}" alt="Image of {{ $planet->name }}" style="max-width: 100%; height: auto; border-radius: 0.5em; margin-bottom: 1em;">
@endif
<h1>{{ $planet->name }}</h1>
@if($planet->description)
<p>{{ $planet->description }}</p>
@endif
<p><strong>Solar System:</strong> {{ $planet->solar_system }}</p>
<p><strong>Diameter:</strong> {{ number_format($planet->size_km, 0, '.', ' ') }} km</p>
<a href="/planets" class="back-link">← Back to the list of planets</a>
</div>
</div>
</body>
</html>
3. Create a route in routes/web.php
:
// Add this route after the route for /planets
Route::get('/planets/{planet}', [PlanetPageController::class, 'show']);
{planet}
must match the name of the variable in the controller method (show(Planet $planet)
) for Route Model Binding to work correctly.
Now, by clicking on the "Learn more" link on the list page, you will be taken to the detailed page of a specific planet.
Quiz to Reinforce
🚀 Chapter Summary:
You have successfully created a "showcase" for your API using the Laravel MVC architecture. You now have:
- A separate controller for web page logic.
- A dynamic page with a list of all planets, receiving data from the DB.
- A detailed page for each planet using Route Model Binding.
- Two web routes in
routes/web.php
to access these pages.
You have turned raw data into understandable and useful information for the user. In the next chapter, we will add interactivity by embedding JavaScript in our Blade views to interact with the API without reloading the page.