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.