API Restful, conceitos e exemplo prático.
Olá, mundo!Tudo bem?
Nos dias atuais existem uma enxurrada de informações, vídeos, até mesmo cursos voltados para este conceito. Que nada mais é de uma forma de comunicação, nada moderna, já idealizada com o Modelo OSI (Open System Interconnection) em 1971.
Afinal, o que é uma API (Application Programming Interface) e o termo Restful? Vejamos a tabela do modelo proposto pelo Modelo OSI:
| CAMADA | FUNÇÃO |
|---|---|
| 7 – Aplicação | Funções especialistas (transferência de arquivos, envio de e-mail, terminal virtual). |
| 6 – Apresentação | Formatação dos dados, conversão de códigos e caracteres (compressão e criptografia). |
| 5 – Sessão | Negociação e conexão com outros nós, analogia. |
| 4 – Transporte | Oferece métodos para a entrega de dados ponto-a-ponto. |
| 3 – Rede | Roteamento de pacotes em uma ou várias redes. |
| 2 – Enlace | Detecção de erros. |
| 1 – Física | Transmissão e recepção dos bits brutos através do meio físico de transmissão. |
Fonte: Tabela obtida no Wikipedia, acesso em https://pt.wikipedia.org/wiki/Modelo_OSI .
Quando falamos sobre API, nos remete a interoperabilidade, ou seja, queremos que Sistemas de linguagens, Sistema Operacionais distintos, até mesmo Banco de Dados e/ou informações, cuja as fontes de dados são divergentes, tenham a devida comunicação. Esta é a real importância e significado de uma API. Não é raro vermos Sistemas em que você realiza a pesquisa de um CEP e retorna, de maneira automática, o preenchimento de seu endereço. Esta função é exercida com o uso de uma API.
E o que seria o Restful?A comunicação em Sistema Web se faz através da representatividade de estado (REST – Representational state transfer), calma! Eu explico, sem melindres e charlatanismo!
Toda requisição Web se faz através de protocolo, correto?Para tal, utilizamos o protocolo HTTP. (Tá bom, vão falar que usam o HTTPS, que apenas tem uma funcionalidade de proteger o cabeçalho, o payload da mensagem com segurança). Desfeito estes mitos, vamos em frente!
Utilizamos os verbos: GET, PUT, POST, PATCH, DELETE, HEAD, nossa aplicação de exemplo, será uma base de cliente, e fará o famoso CRUD (Create, Read, Update e Delete), em português: Criação, Leitura, Atualização e Apagar. Munido destes preceitos básicos, vejamos abaixo os verbos HTTP, especificado e suas respectivas funções na aplicação:
VERBOHTTP |
CRUD |
ENDPOINTS (/cLIENTEs) |
|---|---|---|
| POST | Create | Nosso endpoint direcionará no Controller Clientes /clientes o qual irá gerar um novo registro |
| GET | Read | Neste endpoint iremos pegar uma coleção completa com o método All() do Eloquent e também um outro endpoint /clientes/{id}, que retornará o registro que quisermos filtrar, baseando-se na chave primária do registro. |
| PUT | Update | Este endpoint terá a incumbência de alterar o registro, baseado na rota /clientes/{id} |
| DELETE | Delete | Este endpoint apagará o registro no banco, baseado na rota /clientes/{id} |
Vamos dar início aos trabalhos, criando uma aplicação Laravel! ; )
composer create-project laravel/laravel laravel_api
entramos na pasta do projeto /laravel_api
criamos nosso banco de Dados:
mysql -u root -p
CREATE DATABASE laravel_api;

Voltamos para nossa pasta do projeto e façamos a edição do arquivo .env do Laravel.
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=laravel_api DB_USERNAME=root DB_PASSWORD=<senha do banco de dados>
Vamos criar a classe de Modelo e com a flag -m para a criação da migração para o banco de dados.
php artisan make:model Cliente -m

Vamos até a pasta /app/Models/Cliente.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Cliente extends Model
{
protected $table = 'clientes';
protected $fillable = ['nome', 'telefone'];
}
Agora iremos alterar nossa migração na pasta /laravel_api/database/migrations/2022_06_30_170531_create_clientes_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateClientesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('clientes', function (Blueprint $table) {
$table->id();
$table->string('nome');
$table->integer('telefone');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('clientes');
}
}
Vamos rodar a migração para criação da tabela no banco de dados:
php artisan migrate

Com o banco devidamente criado, vamos agora criar o Controller que atenderá as requisições.
php artisan make:controller ClientesApiController

Vamos incluir os seguintes métodos em nosso Controller, vamos até a pasta /laravel_api/app/Http/Controllers/ClientesApiController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Cliente;
class ClientesApiController extends Controller
{
public function getAllClientes() {
// iremos pegar a coleção de todos os clientes aqui
$clientes = Cliente::get()->toJson(JSON_PRETTY_PRINT);
return response($clientes, 200);
}
public function createCliente(Request $request) {
// Criação do Cliente com Active Record Pattern
$cliente = new Cliente;
$cliente->nome = $request->nome;
$cliente->telefone = $request->telefone;
$cliente->save();
//Retorna em JSON a resposta e a mensagem de "Registro de cliente criado"
return response()->json([
"mensagem" => "Registro de Cliente criado"
], 201);
}
public function getCliente($id) {
// Verifica se o registro existe, caso exista, pega a coleção e tranforma em JSON, caso não encontre
// retorna com "Cliente não encontrado!"
if (Cliente::where('id', $id)->exists()) {
$cliente = Cliente::where('id', $id)->get()->toJson(JSON_PRETTY_PRINT);
return response($cliente, 200);
} else {
return response()->json([
"mensagem" => "Cliente não encontrado!"
], 404);
}
}
public function updateCliente(Request $request, $id) {
// Verifica se o cliente existe, caso exista pega as informações, trata se for valor nulo com o ternário (ambos os valores cliente,telefone)
// ao final salva com o método Active Record Pattern e mostra a mensagem "Registros atualizados com sucesso!"
// Caso não há registro retorna a mensagem "Cliente não encontrado!"
if (Cliente::where('id', $id)->exists()) {
$cliente = Cliente::find($id);
$cliente->nome = is_null($request->nome) ? $cliente->nome : $request->nome;
$cliente->telefone = is_null($request->telefone) ? $cliente->telefone : $request->telefone;
$cliente->save();
return response()->json([
"mensagem" => "Registros atualizados com sucesso!"
], 200);
} else {
return response()->json([
"mensagem" => "Cliente não encontrado!"
], 404);
}
}
public function deleteCliente ($id) {
// método para apagar um cliente, verifica se o registro existe. Caso exista efetua a remoção com método delete().
// Caso não exista, retorna a mensagem "Cliente não encontrado!"
if(Cliente::where('id', $id)->exists()) {
$cliente = Cliente::find($id);
$cliente->delete();
return response()->json([
"mensagem" => "Registros apagados!"
], 202);
} else {
return response()->json([
"mensagem" => "Cliente não encontrado!"
], 404);
}
}
}
Agora vamos colocar no arquivo de rotas do Laravel, nossas endpoints que iremos consumir. /laravel_api/routes/api.php
<?php
use App\Http\Controllers\ClientesApiController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});
Route::get('clientes', [ClientesApiController::class, 'getAllClientes']);
Route::get('clientes/{id}', [ClientesApiController::class, 'getCliente']);
Route::post('clientes', [ClientesApiController::class],'createCliente');
Route::put('clientes/{id}', [ClientesApiController::class],'updateCliente');
Route::delete('clientes/{id}', [ClientesApiController::class, 'deleteCliente']);
Antes de testar nossa aplicação, vamos criar alguns clientes para nossa base experimental:
php artisan make:seed ClienteSeeder

Vamos até a pasta de nossa Seeder criada /laravel_api/database/seeders/ClienteSeeder.php
<?php
namespace Database\Seeders;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use App\Models\Cliente;
class ClienteSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$clientes = [ ["nome" => "Thiago Cantero",
"telefone" => "1199999999"],
["nome" => "Mario Bros",
"telefone" => "1122222222"],
["nome" => "ElePHant",
"telefone" => "11233232"],
["nome" => "Yoshi",
"telefone" => "11222212"]
];
foreach ($clientes as $key => $value) {
Cliente::create($value);
}
}
}
agora vamos executar o comando para popular nossa seeder no banco:
php artisan db:seed --class=ClienteSeeder

Os dados estão na base:

Por fim, vamos testar nossa aplicação. No meu ambiente utilizo o insomnia
Façamos o comando:
php artisan serve

Abrimos o Isomnia, e façamos a rota de acesso a coleção, que em nosso Controller está no método getAllClientes().

Nossa API já está funcionando, ela retorna toda as coleções que fizemos na seed. Vamos pegar um registro apenas, informando o id “4”, este método é o getCliente() de nosso Controller.

Pegamos o registro Yoshi do nosso banco de dados.
Agora vamos apagar o primeiro registro de nossa base de dados. No caso o Id “1”. Que chamará o método deleteCliente() de nosso Controller.

Façamos o chamado de todas nossa coleções novamente.

Perfeito, nossa API está funcional e pronta para ser consumida. É óbvio que este exemplo tem apenas o intuito de demonstrar para que serve uma API e o tais termos REST e RESTFul.
Espero que tenha ajudado.
Código fonte no github.
Sofrer, é só uma vez; vencer, é para a eternidade.