As APIs RESTful transformaram-se no padrão de comunicação entre aplicações modernas, oferecendo interoperabilidade e flexibilidade across diferentes plataformas. Este tutorial apresenta a implementação completa de uma API RESTful utilizando PHP e MySQL, focando nas operações CRUD (Create, Read, Update, Delete) e seguindo as melhores práticas de desenvolvimento.
Fundamentos das APIs RESTful
REST (Representational State Transfer) utiliza os métodos HTTP padrão para realizar operações em recursos. Cada recurso possui uma URL única e as operações são definidas pelos verbos HTTP:
- GET: Recuperar dados
- POST: Criar novos recursos
- PUT: Atualizar recursos existentes
- DELETE: Remover recursos
Esta arquitetura oferece simplicidade comparada a alternativas como SOAP, resultando em implementações mais leves e eficientes. Segundo pesquisas da Web.dev, APIs REST podem ser até 40% mais rápidas em cenários típicos de aplicações web.
Estrutura do Projeto
Organizaremos nossa API em múltiplos arquivos para manter a separação de responsabilidades e facilitar a manutenção:
| Arquivo | Responsabilidade | Função Principal |
|---|---|---|
| config/db.php | Conexão com banco | Gerenciar conexões PDO com MySQL |
| api/index.php | Roteamento | Processar requisições HTTP e rotear |
| models/Item.php | Lógica de negócio | Operações CRUD e validações |
| utils/Response.php | Respostas padronizadas | Formatar retornos JSON |
Configuração do Ambiente
Configure seu ambiente de desenvolvimento com Apache/Nginx, PHP 7.4+ e MySQL 8.0+. Para desenvolvimento local, utilize XAMPP, WAMP ou configure um servidor VPS para testes mais realistas. Certifique-se de habilitar as extensões PDO e pdo_mysql no PHP.
Criação da Base de Dados
Execute este script SQL para criar a estrutura inicial:
CREATE DATABASE api_restful;
USE api_restful;
CREATE TABLE items (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
description TEXT,
price DECIMAL(10,2),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);Configuração da Conexão MySQL
Crie o arquivo config/db.php para gerenciar conexões de forma segura:
conn = null;
try {
$this->conn = new PDO(
"mysql:host=" . $this->host . ";dbname=" . $this->db_name,
$this->username,
$this->password
);
$this->conn->exec("set names utf8");
$this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $exception) {
error_log("Connection error: " . $exception->getMessage());
}
return $this->conn;
}
}Implementação do Modelo de Dados
Desenvolva a classe models/Item.php contendo toda a lógica de acesso aos dados:
conn = $db;
}
// READ - Buscar todos os itens
public function read() {
$query = "SELECT id, name, description, price, created_at FROM " . $this->table_name . " ORDER BY created_at DESC";
$stmt = $this->conn->prepare($query);
$stmt->execute();
return $stmt;
}
// CREATE - Criar novo item
public function create() {
$query = "INSERT INTO " . $this->table_name . " SET name=:name, description=:description, price=:price";
$stmt = $this->conn->prepare($query);
// Sanitização dos dados
$this->name = htmlspecialchars(strip_tags($this->name));
$this->description = htmlspecialchars(strip_tags($this->description));
$this->price = htmlspecialchars(strip_tags($this->price));
$stmt->bindParam(":name", $this->name);
$stmt->bindParam(":description", $this->description);
$stmt->bindParam(":price", $this->price);
return $stmt->execute();
}
// READ SINGLE - Buscar item específico
public function readOne() {
$query = "SELECT * FROM " . $this->table_name . " WHERE id = :id LIMIT 0,1";
$stmt = $this->conn->prepare($query);
$stmt->bindParam(\':id\', $this->id);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if($row) {
$this->name = $row[\'name\'];
$this->description = $row[\'description\'];
$this->price = $row[\'price\'];
return true;
}
return false;
}
// UPDATE - Atualizar item
public function update() {
$query = "UPDATE " . $this->table_name . " SET name=:name, description=:description, price=:price WHERE id=:id";
$stmt = $this->conn->prepare($query);
$this->name = htmlspecialchars(strip_tags($this->name));
$this->description = htmlspecialchars(strip_tags($this->description));
$this->price = htmlspecialchars(strip_tags($this->price));
$this->id = htmlspecialchars(strip_tags($this->id));
$stmt->bindParam(\':name\', $this->name);
$stmt->bindParam(\':description\', $this->description);
$stmt->bindParam(\':price\', $this->price);
$stmt->bindParam(\':id\', $this->id);
return $stmt->execute();
}
// DELETE - Deletar item
public function delete() {
$query = "DELETE FROM " . $this->table_name . " WHERE id = :id";
$stmt = $this->conn->prepare($query);
$this->id = htmlspecialchars(strip_tags($this->id));
$stmt->bindParam(\':id\', $this->id);
return $stmt->execute();
}
}Controlador Principal da API
O arquivo api/index.php gerencia todas as requisições HTTP e implementa o roteamento:
getConnection();
$item = new Item($db);
$request_method = $_SERVER[\'REQUEST_METHOD\'];
$path_info = isset($_SERVER[\'PATH_INFO\']) ? $_SERVER[\'PATH_INFO\'] : \'/\';
switch($request_method) {
case \'GET\':
if ($path_info == \'/\') {
// GET /api/ - Listar todos os itens
$stmt = $item->read();
$num = $stmt->rowCount();
if($num > 0) {
$items_arr = array();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
extract($row);
$item_data = array(
"id" => $id,
"name" => $name,
"description" => $description,
"price" => $price,
"created_at" => $created_at
);
array_push($items_arr, $item_data);
}
http_response_code(200);
echo json_encode(array("data" => $items_arr));
} else {
http_response_code(404);
echo json_encode(array("message" => "Nenhum item encontrado."));
}
} else {
// GET /api/{id} - Buscar item específico
$id = basename($path_info);
$item->id = $id;
if($item->readOne()) {
$item_data = array(
"id" => $item->id,
"name" => $item->name,
"description" => $item->description,
"price" => $item->price
);
http_response_code(200);
echo json_encode($item_data);
} else {
http_response_code(404);
echo json_encode(array("message" => "Item não encontrado."));
}
}
break;
case \'POST\':
// POST /api/ - Criar novo item
$data = json_decode(file_get_contents("php://input"));
if(!empty($data->name) && !empty($data->price)) {
$item->name = $data->name;
$item->description = $data->description ?? \'\';
$item->price = $data->price;
if($item->create()) {
http_response_code(201);
echo json_encode(array("message" => "Item criado com sucesso."));
} else {
http_response_code(503);
echo json_encode(array("message" => "Não foi possível criar o item."));
}
} else {
http_response_code(400);
echo json_encode(array("message" => "Dados incompletos. Nome e preço são obrigatórios."));
}
break;
case \'PUT\':
// PUT /api/{id} - Atualizar item
$id = basename($path_info);
$data = json_decode(file_get_contents("php://input"));
$item->id = $id;
$item->name = $data->name;
$item->description = $data->description;
$item->price = $data->price;
if($item->update()) {
http_response_code(200);
echo json_encode(array("message" => "Item atualizado com sucesso."));
} else {
http_response_code(503);
echo json_encode(array("message" => "Não foi possível atualizar o item."));
}
break;
case \'DELETE\':
// DELETE /api/{id} - Deletar item
$id = basename($path_info);
$item->id = $id;
if($item->delete()) {
http_response_code(200);
echo json_encode(array("message" => "Item deletado com sucesso."));
} else {
http_response_code(503);
echo json_encode(array("message" => "Não foi possível deletar o item."));
}
break;
default:
http_response_code(405);
echo json_encode(array("message" => "Método não permitido."));
break;
}Testando a API
Utilize ferramentas como Postman ou curl para testar os endpoints. Exemplos de requisições:
# Listar todos os itens
curl -X GET http://localhost/api/
# Criar novo item
curl -X POST http://localhost/api/ \\
-H "Content-Type: application/json" \\
-d \'{"name":"Produto Teste","description":"Descrição do produto","price":29.99}\'
# Buscar item específico
curl -X GET http://localhost/api/1
# Atualizar item
curl -X PUT http://localhost/api/1 \\
-H "Content-Type: application/json" \\
-d \'{"name":"Produto Atualizado","description":"Nova descrição","price":39.99}\'
# Deletar item
curl -X DELETE http://localhost/api/1Melhores Práticas e Otimizações
Para APIs em produção, implemente autenticação JWT, validação robusta de dados, rate limiting e logs detalhados. Considere utilizar um hosting otimizado para aplicações PHP que suporte alta disponibilidade.
Validação e Sanitização
Sempre valide e sanitize os dados de entrada para prevenir SQL injection e XSS. Implemente validações específicas para cada campo conforme as regras de negócio.
Tratamento de Erros
Configure logs apropriados e retorne códigos HTTP consistentes. Utilize try-catch blocks para capturar exceções e fornecer feedback adequado aos clientes da API.
Esta implementação fornece uma base sólida para APIs RESTful com PHP e MySQL. A estrutura modular facilita expansões futuras, permitindo adicionar autenticação, cache, documentação automática e outros recursos conforme necessário.
Comentários
0Inicie sessão para deixar um comentário
Iniciar sessãoSé el primero en comentar