Skip to content

Capítulo 5.2: Criando Visões Simples para API

Tempo de estudo: 45 minutos


1. Tarefa: Visualizar dados

Nossa API no Capítulo 2 é capaz de fornecer dados no formato JSON. Isso é excelente para máquinas, mas as pessoas preferem ver as informações em páginas web bem projetadas. Nosso objetivo é criar duas dessas páginas:

  1. Lista de todos os planetas (/planets)
  2. Página de um único planeta (/planets/{id})

Para isso, usaremos a combinação "Rota → Controlador → Visão".

💡 Analogia espacial:

Imagine que o JSON da API são dados brutos de telemetria, apenas um fluxo de números. Nossa tarefa hoje é criar dois monitores (duas "visões") no Centro de Controle de Missão:

  • Tela geral: mostra o status de todos os objetos no sistema (lista de planetas).
  • Tela detalhada: ao clicar em um objeto, exibe todas as informações sobre ele (página de um planeta).

2. Passo 1: Criando um controlador para páginas web

Para a pureza da arquitetura, não se deve misturar a lógica da API e a lógica das páginas web em um único controlador. Criaremos um novo controlador especificamente para exibir nossas views Blade.

Execute no terminal:

php artisan make:controller Web/PlanetPageController
Estamos criando-o na subpasta Web para separá-lo dos controladores de API.

Abra o arquivo criado app/Http/Controllers/Web/PlanetPageController.php.


Passo 2: Página com a lista de todos os planetas

1. Criando um método no controlador: Em PlanetPageController, adicione o método index, que obterá todos os planetas do banco de dados e os passará para a view.

<?php

namespace App\Http\Controllers\Web;

use App\Http\Controllers\Controller;
use App\Models\Planet; // Não se esqueça de importar o modelo

class PlanetPageController extends Controller
{
    /**
     * Mostra a página com a lista de todos os planetas.
     */
    public function index()
    {
        // 1. Obtém todos os planetas do BD
        $planets = Planet::all();

        // 2. Retorna a view e passa os dados para ela
        return view('planets.index', ['planets' => $planets]);
    }
}

2. Criando uma view Blade: Crie o arquivo resources/views/planets/index.blade.php. Usaremos o layout criado no capítulo anterior.

<!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>Lista de todos os planetas conhecidos</h2>
        <hr>
        <div class="planet-list">
            @forelse($planets as $planet)
                <div class="planet-card">
                    <h3>{{ $planet->name }}</h3>
                    <p>Sistema Solar: {{ $planet->solar_system }}</p>
                    <p>Diâmetro: {{ number_format($planet->size_km, 0, '.', ' ') }} km</p>
                    <a href="/planets/{{ $planet->id }}">Saber mais &rarr;</a>
                </div>
            @empty
                <p class="no-planets">Não há nenhum planeta no banco de dados. Por favor, execute os seeders.</p>
            @endforelse
        </div>
    </div>
</body>
</html>
  • number_format(...) — é uma função PHP comum para formatar números de forma elegante. Pode ser usada diretamente no Blade.

3. Criando uma rota em routes/web.php:

use App\Http\Controllers\Web\PlanetPageController;

// ...

Route::get('/planets', [PlanetPageController::class, 'index']);
Agora, se você navegar para /planets no navegador, você verá a página com a lista de planetas!


4. Passo 3: Página de um único planeta

1. Criando um método no controlador:

Em PlanetPageController, adicionaremos o método show. Graças ao Route Model Binding, Laravel encontrará automaticamente o planeta pelo ID e o passará para o método.

<?php
// Dentro da classe PlanetPageController
/**
 * Mostra a página de um planeta específico.
 */
public function show(Planet $planet)
{
    // O Laravel já encontrou o planeta para nós.
    // Se não for encontrado, ele retornará automaticamente um erro 404.

    return view('planets.show', ['planet' => $planet]);
}

2. Criando uma view Blade:

Crie o arquivo 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>Sistema Solar:</strong> {{ $planet->solar_system }}</p>
            <p><strong>Diâmetro:</strong> {{ number_format($planet->size_km, 0, '.', ' ') }} km</p>
            <a href="/planets" class="back-link">&larr; Voltar para a lista de planetas</a>
        </div>
    </div>
</body>
</html>

3. Criando uma rota em routes/web.php:

// Adicione esta rota após a rota para /planets
Route::get('/planets/{planet}', [PlanetPageController::class, 'show']);
- O nome do parâmetro {planet} deve corresponder ao nome da variável no método do controlador (show(Planet $planet)) para que o Route Model Binding funcione corretamente.

Agora, ao clicar no link "Saber mais" na página da lista, você será direcionado para a página detalhada de um planeta específico.


Quiz para consolidação

1. Qual abordagem é a melhor prática para separar a lógica da API e das páginas web?

2. O que faz return view('planets.index', ['planets' => $planets]);?

3. O que é Route Model Binding no contexto de `show(Planet $planet)`?

4. Como é possível formatar a data do campo `created_at` no Blade?

5. Se a rota especifica `/posts/{post}`, como deve ser a assinatura do método no controlador para que o Route Model Binding funcione?


🚀 Resumo do Capítulo:

Você criou com sucesso uma "vitrine" para sua API, usando a arquitetura Laravel MVC. Agora você tem:

  • Um controlador separado para a lógica das páginas web.
  • Uma página dinâmica com uma lista de todos os planetas, obtendo dados do BD.
  • Uma página de detalhes para cada planeta usando Route Model Binding.
  • Duas rotas web em routes/web.php para acessar essas páginas.

Você transformou dados brutos em informações compreensíveis e úteis para o usuário. No próximo capítulo, adicionaremos interatividade, incorporando JavaScript em nossas views Blade para interagir com a API sem recarregar a página.