O que é o Laravel?
Laravel é um framework PHP de código aberto (open-source) criado por Taylor Otwell em 2011. Ele fornece uma estrutura completa para o desenvolvimento de aplicações web modernas, seguindo o padrão de arquitetura MVC (Model-View-Controller).
Sem um framework, um desenvolvedor PHP precisaria resolver na mão problemas como: conexão com banco de dados, proteção contra ataques, roteamento de URLs, validação de formulários, envio de e-mails… O Laravel resolve tudo isso com código elegante e bem organizado.
"PHP para artesãos" — o Laravel foi projetado para que escrever código seja uma experiência agradável e expressiva, sem sacrificar funcionalidade. Cada linha de código deve ser clara e intuitiva.
Tecnologias e padrões que ele abraça:
O Laravel usa o Composer (gerenciador de pacotes do PHP) para gerenciar suas dependências, o que torna super fácil adicionar novas bibliotecas ao projeto.
Por que o Laravel foi criado?
Para entender o porquê do Laravel existir, precisamos entender o contexto do PHP antes de 2011.
Taylor Otwell trabalhava com CodeIgniter, o framework PHP mais popular da época. Mas ficou frustrado com suas limitações: sem suporte nativo para autenticação, ORM fraco, sem migrations e sem tooling moderno. Ele decidiu criar o seu próprio framework.
Problemas que o Laravel veio resolver
- Conexões com banco feitas manualmente com SQL crú
- Sem estrutura definida — cada projeto era diferente
- Autenticação reescrita do zero em cada projeto
- Zero proteção automática (SQL Injection, XSS, CSRF)
- Deploy caótico, sem controle de versão do banco
- Testes difíceis ou simplesmente ignorados
- Eloquent ORM — banco de dados como objetos PHP
- Estrutura MVC padronizada e consistente
- Autenticação completa já integrada
- Proteção contra ataques já ativada por padrão
- Migrations — versionamento do banco de dados
- Testes facilitados com abstrações prontas
Linha do tempo do Laravel
Padrão MVC no Laravel
MVC (Model-View-Controller) é um padrão de arquitetura de software que separa a aplicação em três camadas com responsabilidades distintas. É o padrão central do Laravel.
📂 Fica em:
app/Models/
📂 Fica em:
resources/views/
📂 Fica em:
app/Http/Controllers/
Como o fluxo MVC funciona?
Exemplos práticos de cada camada
<?php
use App\Http\Controllers\PostController;
use Illuminate\Support\Facades\Route;
// Quando o usuário acessar "/posts", chama o método index() do PostController
Route::get('/posts', [PostController::class, 'index']);
// Quando acessar "/posts/5", chama o método show() passando id=5
Route::get('/posts/{id}', [PostController::class, 'show']);
<?php
namespace App\Http\Controllers;
use App\Models\Post; // Importa o Model
class PostController extends Controller
{
// Lista todos os posts
public function index()
{
// 1. Busca dados no Model
$posts = Post::all();
// 2. Passa os dados para a View
return view('posts.index', ['posts' => $posts]);
}
// Exibe um post específico
public function show($id)
{
$post = Post::findOrFail($id); // Busca por ID (retorna 404 se não achar)
return view('posts.show', compact('post'));
}
}
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
// O Laravel automaticamente mapeia esta classe para a tabela "posts" no banco
// Campos que podem ser preenchidos em massa
protected $fillable = ['titulo', 'conteudo', 'autor_id'];
// Relacionamento: um post pertence a um usuário
public function autor()
{
return $this->belongsTo(User::class, 'autor_id');
}
// Relacionamento: um post tem muitos comentários
public function comentarios()
{
return $this->hasMany(Comentario::class);
}
}
<!-- O Blade usa {{ }} para exibir dados de forma segura (protegido contra XSS) -->
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<title>Lista de Posts</title>
</head>
<body>
<h1>Todos os Posts</h1>
@foreach($posts as $post) {{-- Diretiva Blade para loop --}}
<article>
<h2>{{ $post->titulo }}</h2>
<p>{{ $post->conteudo }}</p>
<small>Por: {{ $post->autor->name }}</small>
</article>
@endforeach
@if($posts->isEmpty())
<p>Nenhum post encontrado.</p>
@endif
</body>
</html>
Active Record — o padrão por trás do Eloquent
O Eloquent ORM do Laravel é construído sobre o padrão de design chamado Active Record. Entender esse padrão explica boa parte do "por que" o Eloquent funciona do jeito que funciona.
📖 Definição: No padrão Active Record, um objeto representa uma linha de uma tabela no banco de dados e carrega junto a si toda a lógica para ler, inserir, atualizar e deletar esse registro. O objeto e seus dados vivem juntos na mesma classe.
Active Record vs outros padrões
A classe modelo representa o objeto e a tabela ao mesmo tempo. Ela sabe como se salvar, se buscar e se deletar.
- Simples e intuitivo para começar
- Menos código boilerplate
- Objeto e persistência acoplados
- Ideal para CRUD e regras de negócio simples
Separa completamente o objeto de negócio (entidade) da lógica de persistência (repositório).
- Mais complexo, porém mais flexível
- Objeto não conhece o banco
- Melhor para domínios complexos (DDD)
- Mais fácil de testar de forma totalmente isolada
Como o Active Record se manifesta no Eloquent
Cada classe Model que estende Illuminate\Database\Eloquent\Model ganha
automaticamente todos os métodos de interação com o banco. A classe em si é
o registro da tabela — não precisa de nenhum repositório externo.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Produto extends Model
{
use SoftDeletes; // Habilita soft delete (deleted_at)
// Eloquent infere a tabela como "produtos" (snake_case + plural)
// Para sobrescrever: protected $table = 'minha_tabela';
// Campos que podem ser preenchidos via create() ou fill()
protected $fillable = ['nome', 'preco', 'estoque', 'ativo'];
// Cast automático de tipos ao ler/escrever atributos
protected $casts = [
'preco' => 'decimal:2',
'ativo' => 'boolean',
'criado_em' => 'datetime',
];
}
<?php
// ─── CREATE ─────────────────────────────────────────────────────────────
// Forma 1: instanciar, atribuir e salvar
$produto = new Produto();
$produto->nome = 'Teclado Mecânico';
$produto->preco = 299.90;
$produto->estoque = 50;
$produto->save(); // Executa: INSERT INTO produtos (nome, preco, estoque) VALUES (...)
// Forma 2: criar em massa de uma vez (requer campos em $fillable)
$produto = Produto::create([
'nome' => 'Mouse Gamer',
'preco' => 149.90,
'estoque' => 30,
]);
// ─── READ ────────────────────────────────────────────────────────────────
$todos = Produto::all(); // SELECT * FROM produtos
$um = Produto::find(1); // SELECT ... WHERE id = 1
$ou404 = Produto::findOrFail(99); // Lança erro 404 se não achar
$caros = Produto::where('preco', '>', 100)->get(); // WHERE preco > 100
$primeiro = Produto::where('ativo', true)->first(); // Retorna apenas um
// Ordenar, limitar e paginar
$produtos = Produto::orderBy('preco', 'desc')->take(10)->get();
$paginado = Produto::paginate(15); // Paginação automática com links
// ─── UPDATE ─────────────────────────────────────────────────────────────
$produto = Produto::find(1);
$produto->preco = 259.90;
$produto->save(); // Executa: UPDATE produtos SET preco = 259.90 WHERE id = 1
// Atualizar múltiplos registros de uma vez
Produto::where('estoque', 0)->update(['ativo' => false]);
// ─── DELETE ─────────────────────────────────────────────────────────────
$produto = Produto::find(1);
$produto->delete(); // Com SoftDeletes: marca deleted_at = now()
// Sem SoftDeletes: DELETE FROM produtos WHERE id = 1
// Soft Delete — o registro não some do banco
$produto->restore(); // Desfaz o soft delete (limpa deleted_at)
$produto->forceDelete(); // Remove de verdade mesmo com SoftDeletes ativo
Convenções automáticas do Eloquent
| Convenção | Padrão assumido | Como sobrescrever |
|---|---|---|
| Nome da tabela | Snake_case plural do Model (Post → posts, OrderItem → order_items) |
protected $table = 'minha_tabela'; |
| Chave primária | id inteiro auto-incremento |
protected $primaryKey = 'codigo'; |
| Timestamps | Colunas created_at e updated_at gerenciadas automaticamente |
public $timestamps = false; |
| Conexão com banco | Conexão padrão definida no .env |
protected $connection = 'mysql_secundario'; |
Relacionamentos — a parte mais poderosa
No Active Record do Eloquent, os relacionamentos entre tabelas são definidos como métodos na própria classe Model. O Eloquent monta as queries SQL automaticamente.
<?php
// ── hasMany: Um user TEM MUITOS posts ────────────────────────────────────
class User extends Model {
public function posts() {
return $this->hasMany(Post::class); // Chave estrangeira inferida: user_id
}
}
// ── belongsTo: Um post PERTENCE A um user ────────────────────────────────
class Post extends Model {
public function autor() {
return $this->belongsTo(User::class, 'user_id');
}
// ── belongsToMany: Um post TEM MUITAS tags (e vice-versa) ────────────
public function tags() {
return $this->belongsToMany(Tag::class); // Tabela pivot inferida: post_tag
}
// ── hasOne: Um post TEM UM resumo ────────────────────────────────────
public function resumo() {
return $this->hasOne(Resumo::class);
}
}
// ── Usando os relacionamentos ─────────────────────────────────────────────
$user = User::find(1);
$posts = $user->posts; // SELECT * FROM posts WHERE user_id = 1
// ── Eager Loading: carrega tudo de uma vez (evita N+1) ───────────────────
$users = User::with('posts')->get();
// Gera APENAS 2 queries — uma para users, uma para todos os posts
// ── Eager Loading aninhado ────────────────────────────────────────────────
$posts = Post::with(['autor', 'tags', 'comentarios.autor'])->get();
❌ Ruim (N+1):
Post::all() + acessar $post->autor no loop = 1 + N queries✅ Bom (eager load):
Post::with('autor')->get() = sempre 2 queries
php artisan make:model Produto — cria só o modelphp artisan make:model Produto -m — model + migrationphp artisan make:model Produto -mcr — model + migration + controller com CRUD completo
Vantagens e Desvantagens
Como toda tecnologia, o Laravel tem seus pontos fortes e fracos. Conhecer ambos ajuda a decidir quando usá-lo e o que esperar durante o aprendizado.
- ✅Sintaxe elegante — Código legível, expressivo e próximo do inglês natural.
- ✅Documentação excelente — Completa, atualizada e com exemplos claros em laravel.com.
- ✅Artisan CLI — Gera arquivos, roda migrations e muito mais com um comando.
- ✅Eloquent ORM — Banco de dados virou objetos PHP. Relacionamentos intuitivos.
- ✅Blade Templates — Motor de templates simples, poderoso e com layouts por herança.
- ✅Segurança embutida — Proteção contra CSRF, SQL Injection e XSS por padrão.
- ✅Ecossistema rico — Livewire, Inertia.js, Filament, Horizon, Telescope…
- ✅Comunidade enorme — Muitos pacotes, tutoriais, vídeos e fóruns de ajuda.
- ✅Queue & Jobs — Sistema de filas para tarefas pesadas em background.
- ✅Suporte LTS — Versões com suporte estendido para projetos de longo prazo.
- ❌Curva de aprendizado — Para iniciantes em PHP, pode ser sobrecarregante no início.
- ❌Muita "magia" — Façades e helpers escondem o que realmente acontece por baixo.
- ❌Pesado para pequenos projetos — Para uma API simples ou script, pode ser excessivo.
- ❌Versões quebram compatibilidade — Upgrades entre versões maiores exigem esforço.
- ❌Performance — Sem configuração adequada (cache, OPcache), pode ser mais lento que PHP puro.
- ❌PHP 8+ obrigatório — Versões recentes exigem PHP moderno, impossível em servidores legados.
- ❌Abstração excessiva — Pode esconder bugs difíceis de debugar para quem não conhece o internals.
Estrutura de Diretórios
Ao criar um novo projeto Laravel com composer create-project laravel/laravel meu-projeto,
você recebe esta estrutura de pastas. Entendê-la é fundamental para trabalhar com o framework.
.env contém senhas e chaves secretas.
O vendor/ pode ser recriado com composer install.
O .gitignore já os exclui por padrão.
As pastas que você mais vai usar
Aqui ficam seus Controllers. Cada controller geralmente corresponde a um recurso (PostController, UserController…). Para criar um: php artisan make:controller PostController
Seus Models Eloquent. Cada model representa uma tabela no banco. Para criar um com migration: php artisan make:model Post -m
Templates Blade (.blade.php). Organize em subpastas por recurso (posts/, users/, layouts/…). São como HTML com superpoderes PHP embutidos.
Cada arquivo representa uma alteração no banco de dados. Execute com php artisan migrate. Permite que o time tenha o mesmo schema do banco sem compartilhar dumps SQL.
Ciclo de Vida de uma Request
Entender o que acontece desde que o usuário digita uma URL até a página aparecer na tela é essencial para dominar o Laravel. Todo esse processo é chamado de ciclo de vida de uma requisição (request lifecycle).
Passo a passo detalhado
O usuário acessa uma URL no navegador. O servidor web (Nginx ou Apache) recebe a requisição HTTP e a direciona para o ponto de entrada do Laravel.
public/index.php — O ponto de entradaTodo tráfego vai para este único arquivo. Ele faz três coisas: (1) carrega o autoloader do Composer, (2) cria a instância da aplicação ($app), e (3) envia a requisição para o Kernel. Você raramente edita este arquivo.
O Service Container do Laravel é criado. É o coração do framework — um sistema de Inversão de Controle (IoC) que sabe como criar e injetar qualquer dependência. Pense nele como um "registro central" de todos os serviços.
O HTTP Kernel define os middleware globais que toda requisição deve passar. Ele também lista os grupos de middleware ("web" e "api") e os bootstrap classes que preparam o ambiente (como carregar variáveis de ambiente e configurações).
Todos os Service Providers listados em config/app.php são carregados.
Primeiro o método register() de todos é chamado, depois o
boot() de todos. É aqui que o framework se "monta" completamente.
A requisição passa por uma "fila" de middleware configurada para aquela rota. Cada middleware pode deixar passar, modificar ou barrar a requisição. Exemplos: verificar se o usuário está logado, verificar CSRF, limitar requisições (rate limiting).
O Router compara a URL e o método HTTP da requisição com as rotas definidas em
routes/web.php ou routes/api.php e encontra a rota
correspondente, identificando qual Controller e método devem ser chamados.
O método do Controller é chamado. Aqui acontece a lógica da sua aplicação: buscar dados no banco via Model, processar, validar e preparar a resposta.
O Controller retorna uma Response (HTML renderizado pelo Blade, JSON, redirect, etc). Essa Response passa pelo middleware de volta (no sentido inverso) para qualquer pós-processamento, e finalmente é enviada para o navegador do usuário.
<?php
// 1. Carrega o autoloader do Composer (conhece todas as classes do Laravel)
require __DIR__.'/../vendor/autoload.php';
// 2. "Liga" o Laravel: cria o Application Container
$app = require_once __DIR__.'/../bootstrap/app.php';
// 3. Cria o Kernel HTTP (que gerencia middleware e bootstrap)
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
// 4. Passa a requisição para o Kernel e obtém a Response
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
// 5. Envia a Response para o browser
$response->send();
// 6. Finaliza e limpa (dispara eventos de encerramento)
$kernel->terminate($request, $response);
Service Providers
Service Providers são a espinha dorsal do bootstrap do Laravel. São eles que "montam" o framework, registrando todos os componentes no Service Container antes de qualquer requisição ser tratada.
🔑 Analogia: Imagine que você está abrindo uma loja. Antes de abrir a porta para os clientes, você precisa ligar as luzes, colocar os produtos nas prateleiras, ligar o caixa, conectar o sistema… Isso tudo é o que os Service Providers fazem com o Laravel antes de atender uma requisição.
Os dois métodos de um Service Provider
Chamado primeiro. Use para registrar bindings no Service Container. Aqui você diz ao Laravel: "quando alguém precisar de X, crie assim". Nunca use o método boot() de outros providers aqui — eles podem não estar carregados ainda.
Chamado depois que todos os providers foram registrados. Use para tarefas que dependem de outros serviços: registrar rotas, publicar views, definir validators customizados, registrar observers de Model, etc.
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Services\PagamentoService;
use App\Contracts\PagamentoInterface;
class AppServiceProvider extends ServiceProvider
{
/**
* register() — Liga classes/interfaces a implementações no Container.
* Chamado ANTES de qualquer outro boot().
*/
public function register(): void
{
// Diz ao Laravel: "quando alguém pedir PagamentoInterface,
// entregue uma instância de PagamentoService"
$this->app->bind(PagamentoInterface::class, PagamentoService::class);
// Singleton: cria apenas UMA instância durante toda a requisição
$this->app->singleton('relatorio', function ($app) {
return new \App\Services\RelatorioService(
config('relatorio.driver')
);
});
}
/**
* boot() — Inicializações que dependem de outros serviços.
* Chamado APÓS todos os register().
*/
public function boot(): void
{
// Força HTTPS em produção
if ($this->app->environment('production')) {
\URL::forceScheme('https');
}
// Registra um validator customizado
\Validator::extend('cpf_valido', function ($attribute, $value) {
return validarCpf($value);
});
// Registra observer do Model Post
\App\Models\Post::observe(\App\Observers\PostObserver::class);
}
}
<?php
return [
// ...
'providers' => ServiceProvider::defaultProviders()->merge([
/*
* Providers do Framework (não mexa nestes)
*/
// Illuminate\Auth\AuthServiceProvider::class,
// Illuminate\Cache\CacheServiceProvider::class,
// ...
/*
* Providers da sua aplicação
*/
App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,
// Providers de pacotes de terceiros:
// Spatie\Permission\PermissionServiceProvider::class,
])->toArray(),
];
php artisan make:provider MeuNomeProvider
O arquivo é criado em
app/Providers/. Não esqueça de registrá-lo em
config/app.php (nas versões mais antigas) ou em bootstrap/providers.php
(Laravel 11+).
Facades
Facades são uma das features mais características do Laravel. Elas fornecem uma interface estática simples para classes disponíveis no Service Container, sem precisar injetar dependências manualmente.
🪟 Analogia: Uma Facade é como o painel de controle de um avião. O piloto aperta um botão e o motor responde — ele não precisa saber como os pistões funcionam internamente. A Facade esconde a complexidade e expõe uma interface simples.
Como as Facades funcionam internamente?
Quando você escreve Cache::get('usuario_1'), o Laravel faz o seguinte:
Facades mais usados no dia a dia
| Facade | O que faz | Exemplo de uso |
|---|---|---|
Route |
Define rotas da aplicação | Route::get('/home', [HomeController::class, 'index']); |
DB |
Acesso ao banco de dados | DB::table('users')->where('id', 1)->first(); |
Cache |
Armazenamento em cache | Cache::put('chave', 'valor', 3600); |
Auth |
Autenticação de usuários | Auth::user(); / Auth::check(); |
Mail |
Envio de e-mails | Mail::to($user)->send(new WelcomeMail()); |
Storage |
Sistema de arquivos | Storage::disk('public')->put('foto.jpg', $conteudo); |
Log |
Registro de logs | Log::error('Erro crítico!', ['dados' => $dados]); |
Session |
Dados de sessão | Session::put('carrinho', $itens); |
Event |
Disparar e ouvir eventos | Event::dispatch(new UserRegistered($user)); |
Validator |
Validação de dados | Validator::make($dados, ['nome' => 'required|max:255']); |
Facade vs Injeção de Dependência
Ambas as abordagens são válidas. A Facade é mais concisa; a injeção de dependência é mais explícita e facilita os testes unitários.
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
class UserController extends Controller
{
public function index()
{
// Simples e direto
$users = Cache::remember(
'all_users',
3600,
fn() => User::all()
);
Log::info('Users listados');
return view('users.index', compact('users'));
}
}
<?php
namespace App\Http\Controllers;
use Illuminate\Cache\CacheManager;
use Psr\Log\LoggerInterface;
class UserController extends Controller
{
public function __construct(
private CacheManager $cache,
private LoggerInterface $log
) {}
public function index()
{
// Mais explícito — ótimo para testes
$users = $this->cache->remember(
'all_users',
3600,
fn() => User::all()
);
$this->log->info('Users listados');
return view('users.index', compact('users'));
}
}
cache(), auth(), session(), config(),
view(), redirect()… São funções comuns que podem ser chamadas de qualquer lugar.
Middleware
Middleware são camadas intermediárias que uma requisição atravessa antes de chegar ao Controller (e que a resposta pode atravessar no caminho de volta). É o mecanismo de "filtros" do Laravel.
🛡️ Analogia: Imagine entrar num prédio corporativo. Antes de chegar à sua sala (o Controller), você passa pela portaria (autenticação), pelo detector de metais (validação de segurança) e pelo leitor de crachá (autorização de acesso). Cada um desses é um middleware.
Middlewares nativos do Laravel
| Middleware | Alias | O que faz |
|---|---|---|
Authenticate |
auth |
Verifica se o usuário está autenticado. Redireciona para login se não estiver. |
VerifyCsrfToken |
csrf |
Protege contra ataques CSRF (Cross-Site Request Forgery) em formulários. |
ThrottleRequests |
throttle |
Limita o número de requisições por minuto. Padrão: 60/minuto para APIs. |
RedirectIfAuthenticated |
guest |
Redireciona usuários já logados (para não acessar login/registro novamente). |
EnsureEmailIsVerified |
verified |
Garante que o e-mail do usuário foi verificado para acessar a rota. |
TrimStrings |
— (global) | Remove espaços extras de todos os inputs automaticamente. |
HandleCors |
— (global) | Configura os headers CORS para APIs acessadas por outros domínios. |
Criando um Middleware customizado
# Gera o arquivo em app/Http/Middleware/VerificarIdade.php
php artisan make:middleware VerificarIdade
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class VerificarIdade
{
/**
* Toda a lógica fica no método handle().
*
* @param Request $request A requisição atual
* @param Closure $next A "próxima camada" do pipeline
*/
public function handle(Request $request, Closure $next): Response
{
$idade = $request->input('idade');
// Se a idade for menor que 18, barra a requisição
if ($idade !== null && $idade < 18) {
return response()->json([
'erro' => 'Acesso restrito para maiores de 18 anos.'
], 403);
}
// "Deixa passar" para o próximo middleware ou controller
return $next($request);
}
}
<?php
use App\Http\Controllers\PainelController;
use App\Http\Controllers\AdminController;
use Illuminate\Support\Facades\Route;
// Aplica um middleware em uma rota específica
Route::get('/painel', [PainelController::class, 'index'])
->middleware('auth'); // Apenas usuários logados
// Aplica múltiplos middlewares
Route::get('/admin', [AdminController::class, 'index'])
->middleware(['auth', 'verified']); // Logado + e-mail verificado
// Grupo de rotas com middleware compartilhado
Route::middleware(['auth'])->group(function () {
Route::get('/perfil', [PerfilController::class, 'show']);
Route::get('/configuracoes', [ConfigController::class, 'index']);
Route::get('/pedidos', [PedidoController::class, 'index']);
});
// Usando o middleware customizado com alias
Route::get('/conteudo-adulto', [ConteudoController::class, 'index'])
->middleware('verificar.idade');
app/Http/Kernel.php no array
$routeMiddleware. No Laravel 11+, use o arquivo
bootstrap/app.php com ->withMiddleware().
'verificar.idade' => \App\Http\Middleware\VerificarIdade::class
Grupos de Middleware: "web" vs "api"
webAplicado automaticamente em routes/web.php. Inclui:
- Sessões (StartSession)
- Proteção CSRF (VerifyCsrfToken)
- Cookies criptografados
- Flash messages
- Compartilhar erros com views
apiAplicado automaticamente em routes/api.php. Inclui:
- Rate limiting (60 req/min)
- Sem sessão (stateless)
- Sem CSRF (usa tokens de autenticação)
- Prefixo
/apiautomático
Parabéns! Você chegou ao final.
Agora você entende os conceitos fundamentais da arquitetura Laravel: MVC, ciclo de vida de uma requisição, Service Providers, Facades e Middleware. Essa é a base para construir aplicações profissionais!
Próximos passos sugeridos
- Eloquent ORM e Relacionamentos
- Migrations e Seeders
- Blade Templates avançado
- Validação com Form Requests
- Autenticação com Laravel Breeze
- Queues e Jobs
- Events e Listeners
- APIs REST com Sanctum
- Testes com PHPUnit/Pest
- Deploy com Laravel Forge/Vapor