Neste tutorial, você aprenderá como criar uma REST API em PHP do zero, sem usar dependências externas. Aprenda a estruturar, configurar e testar sua própria API e dê vida às suas aplicações web.

Quer saber mais sobre APIs REST? Visite nosso post em REST API: O que é e como funciona?

1 – Requisitos

Antes de começarmos a criar nossa REST API em PHP sem usar dependências, certifique-se de que você tenha os seguintes requisitos instalados e configurados em seu ambiente de desenvolvimento:

  • Servidor Web: Um servidor web capaz de executar PHP, como o Apache ou o Nginx.
  • PHP: A linguagem de programação PHP na versão 7.4 ou superior. Verifique se as extensões necessárias estão habilitadas (por exemplo, MySQLi, PDO, etc.).
  • Banco de dados: Um banco de dados para armazenar e gerenciar os dados da sua API. O MySQL é uma opção popular, mas você pode escolher outro banco de dados que seja compatível com PHP, como PostgreSQL ou SQLite.
  • Ferramenta de teste de API: Um cliente REST para testar suas rotas e funcionalidades da API, como Postman ou Insomnia.
  • Editor de código-fonte: Um editor de código-fonte de sua escolha para escrever e editar o código PHP, como Visual Studio Code, PhpStorm, Sublime Text ou Atom.

Uma vez que todos os requisitos estejam instalados e configurados corretamente, você pode prosseguir com a criação da REST API em PHP.

2 – Criando a estrutura de diretórios

Organizar a estrutura de diretórios é fundamental para manter seu projeto limpo e fácil de entender. Vamos criar a estrutura de diretórios para nossa REST API em PHP. No diretório raiz do seu projeto, crie os seguintes diretórios e arquivos:

rest-api-php/
│
├── .htaccess
├── config/
│   └── config.php
│
├── controllers/
│
├── models/
│
├── routes/
│   └── routes.php
│
└── utils/
    └── database.php

Explicação da estrutura:

  • .htaccess: Arquivo de configuração do Apache para reescrever URLs e outras configurações específicas do servidor.
  • config/: Diretório que armazena o arquivo de configuração do projeto.
    • config.php: Arquivo de configuração com parâmetros, como informações do banco de dados e outras configurações globais.
  • controllers/: Diretório que armazena os controladores responsáveis por manipular as requisições e respostas da API.
  • models/: Diretório que armazena os modelos responsáveis pela lógica de negócios e interação com o banco de dados.
  • routes/: Diretório que armazena o arquivo de rotas.
    • routes.php: Arquivo responsável por mapear as rotas da API para os controladores correspondentes.
  • utils/: Diretório que armazena arquivos utilitários e de serviços, como a conexão com o banco de dados.
    • database.php: Arquivo responsável pela conexão com o banco de dados.

Agora que criamos a estrutura de diretórios, podemos seguir para a configuração do arquivo .htaccess e a implementação dos arquivos de configuração, conexão com o banco de dados, rotas, modelos e controladores.

3 – Configurando o arquivo .htaccess

O arquivo .htaccess é usado para configurar o servidor Apache e permitir a reescrita de URLs, o que é importante para criar uma API RESTful. Abra o arquivo .htaccess na raiz do projeto e adicione o seguinte conteúdo:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)$ routes/routes.php [QSA,L]

Explicação das regras:

  • RewriteEngine On: Habilita o mecanismo de reescrita do Apache.
  • RewriteCond %{REQUEST_FILENAME} !-d: Verifica se a solicitação não corresponde a um diretório existente.
  • RewriteCond %{REQUEST_FILENAME} !-f: Verifica se a solicitação não corresponde a um arquivo existente.
  • RewriteRule ^(.+)$ routes/routes.php [QSA,L]: Redireciona todas as solicitações que não correspondem a arquivos ou diretórios existentes para o arquivo routes/routes.php. A flag [QSA] (Query String Append) preserva a string de consulta, enquanto a flag [L] (Last) indica que esta é a última regra de reescrita a ser aplicada.

Certifique-se de que o módulo mod_rewrite do Apache esteja habilitado em seu servidor. Se você estiver usando o Nginx ou outro servidor web, consulte a documentação correspondente para configurar a reescrita de URLs.

Com o arquivo .htaccess configurado, o servidor web redirecionará todas as solicitações para o arquivo routes/routes.php, permitindo que você gerencie as rotas da API de maneira centralizada.

4 – Criando o arquivo de configuração

O arquivo de configuração config.php armazenará as informações de configuração do projeto, como os detalhes do banco de dados e outras configurações globais. Abra o arquivo config/config.php e adicione o seguinte conteúdo:

<?php

define('DB_HOST', 'localhost');
define('DB_NAME', 'your_database_name');
define('DB_USER', 'your_database_user');
define('DB_PASSWORD', 'your_database_password');

define('DEBUG', true); // Altere para 'false' no ambiente de produção

Substitua 'your_database_name', 'your_database_user' e 'your_database_password' pelos detalhes do seu banco de dados.

  • DB_HOST: O endereço do servidor de banco de dados.
  • DB_NAME: O nome do banco de dados.
  • DB_USER: O nome de usuário do banco de dados.
  • DB_PASSWORD: A senha do usuário do banco de dados.
  • DEBUG: Um sinalizador para controlar o modo de depuração do projeto. Defina como true no ambiente de desenvolvimento e false no ambiente de produção.

Agora que você criou o arquivo de configuração, as informações do banco de dados e outras configurações globais estão disponíveis em todo o projeto através das constantes definidas.

5 – Criando o arquivo de conexão com o banco de dados

O arquivo database.php gerenciará a conexão com o banco de dados. Abra o arquivo utils/database.php e adicione o seguinte conteúdo:

<?php

require_once '../config/config.php';

class Database {
    private $connection;

    public function __construct() {
        $this->connect();
    }

    private function connect() {
        $this->connection = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);

        if ($this->connection->connect_error) {
            die("Connection failed: " . $this->connection->connect_error);
        }
    }

    public function getConnection() {
        return $this->connection;
    }
}

Neste arquivo, criamos uma classe chamada Database para gerenciar a conexão com o banco de dados. A classe contém os seguintes métodos:

  • __construct(): Construtor da classe que chama o método connect() para estabelecer a conexão com o banco de dados.
  • connect(): Método privado que cria uma nova conexão com o banco de dados usando a extensão mysqli. Se houver um erro de conexão, o script será encerrado e a mensagem de erro será exibida.
  • getConnection(): Método público que retorna a conexão estabelecida com o banco de dados.

Agora, a conexão com o banco de dados está pronta para ser usada nos modelos do projeto.

6 – Criando o arquivo de rotas

O arquivo routes.php gerencia todas as rotas da API e direciona as solicitações para os controladores apropriados. Abra o arquivo routes/routes.php e adicione o seguinte conteúdo:

<?php

require_once '../controllers/example_controller.php';

$requestMethod = $_SERVER['REQUEST_METHOD'];
$uri = $_SERVER['REQUEST_URI'];
$uriSegments = explode('/', parse_url($uri, PHP_URL_PATH));

$dbConnection = (new Database())->getConnection();
$controller = new ExampleController($dbConnection);

if ($uriSegments[1] === 'example') {
    $id = isset($uriSegments[2]) ? intval($uriSegments[2]) : null;

    switch ($requestMethod) {
        case 'GET':
            if ($id) {
                $response = $controller->get($id);
            } else {
                $response = $controller->getAll();
            }
            break;
        case 'POST':
            $response = $controller->create();
            break;
        case 'PUT':
            if ($id) {
                $response = $controller->update($id);
            } else {
                $response = ['status' => 'error', 'message' => 'Invalid example ID'];
            }
            break;
        case 'DELETE':
            if ($id) {
                $response = $controller->delete($id);
            } else {
                $response = ['status' => 'error', 'message' => 'Invalid example ID'];
            }
            break;
        default:
            $response = ['status' => 'error', 'message' => 'Invalid request method'];
            break;
    }
} else {
    $response = ['status' => 'error', 'message' => 'Invalid API endpoint'];
}

header('Content-Type: application/json');
echo json_encode($response);

Neste arquivo, primeiro definimos os cabeçalhos para permitir CORS e informar ao cliente que estamos retornando dados no formato JSON.

Em seguida, importamos os arquivos necessários e verificamos o método da solicitação HTTP e a URI para direcionar a solicitação para o controlador e ação apropriados.

Por enquanto, usamos um controlador de exemplo chamado example_controller. Você pode substituí-lo pelos controladores que desejar criar para sua API. As rotas estão configuradas para lidar com os métodos GET, POST, PUT e DELETE. O arquivo routes.php direciona as solicitações para os métodos apropriados do controlador e retorna a resposta em formato JSON.

No próximo passo, você criará os modelos e controladores que serão usados pela API.

7 – Definindo modelos (Model)

Os modelos são responsáveis pela lógica de negócios e interação com o banco de dados. Neste exemplo, vamos criar um modelo de exemplo chamado Example. Crie um arquivo chamado example_model.php no diretório models/ e adicione o seguinte conteúdo:

<?php

class ExampleModel {
    private $conn;
    
    public function __construct($dbConnection) {
        $this->conn = $dbConnection;
    }

    public function getAll() {
        $query = "SELECT * FROM examples";
        $result = $this->conn->query($query);
        return $result;
    }

    public function get($id) {
        $query = "SELECT * FROM examples WHERE id = ?";
        $stmt = $this->conn->prepare($query);
        $stmt->bind_param('i', $id);
        $stmt->execute();
        $result = $stmt->get_result();
        return $result;
    }

    public function create($data) {
		$query = "INSERT INTO examples (name, description) VALUES (?, ?)";
		$stmt = $this->conn->prepare($query);
		$stmt->bind_param('ss', $data['name'], $data['description']);

		if ($stmt->execute()) {
			return ['status' => 'success', 'message' => 'Foi criado com sucesso'];
		} else {
			return ['status' => 'error', 'message' => 'Erro ao criar'];
		}
	}

	public function update($id, $data) {
		$query = "UPDATE examples SET name = ?, description = ? WHERE id = ?";
		$stmt = $this->conn->prepare($query);
		$stmt->bind_param('ssi', $data['name'], $data['description'], $id);

		if ($stmt->execute()) {
			return ['status' => 'success', 'message' => 'Foi atualizado com sucesso'];
		} else {
			return ['status' => 'error', 'message' => 'Erro ao atualizar'];
		}
	}

	public function delete($id) {
		$query = "DELETE FROM examples WHERE id = ?";
		$stmt = $this->conn->prepare($query);
		$stmt->bind_param('i', $id);

		if ($stmt->execute()) {
			return ['status' => 'success', 'message' => 'Foi deletado com sucesso'];
		} else {
			return ['status' => 'error', 'message' => 'Erro ao deletar'];
		}
	}
}

Neste exemplo, criamos uma classe ExampleModel que contém os seguintes métodos:

  • __construct($dbConnection): Construtor da classe que recebe a conexão com o banco de dados e a armazena em uma variável privada.
  • getAll(): Método que retorna todos os registros da tabela examples.
  • get($id): Método que retorna um registro específico da tabela examples com base em seu ID.
  • create($data): Método para criar um novo registro na tabela examples.
  • update($id, $data): Método para atualizar um registro existente na tabela examples com base em seu ID.
  • delete($id): Método para excluir um registro da tabela examples com base em seu ID.

Você deve substituir os nomes das tabelas e colunas pelos nomes reais do seu banco de dados e implementar a lógica nos métodos create, update e delete de acordo com suas necessidades.

Depois de criar o modelo, você pode implementar o controlador correspondente.

8 – Implementando controladores (Controller)

Os controladores são responsáveis por manipular as requisições e respostas da API. Neste exemplo, criaremos um controlador chamado ExampleController para trabalhar com o modelo Example criado anteriormente. Crie um arquivo chamado example_controller.php no diretório controllers/ e adicione o seguinte conteúdo:

<?php

require_once '../models/example_model.php';

class ExampleController {
    private $model;
    
    public function __construct($dbConnection) {
        $this->model = new ExampleModel($dbConnection);
    }

    public function getAll() {
        $result = $this->model->getAll();
        $examples = [];

        if ($result->num_rows > 0) {
            while ($row = $result->fetch_assoc()) {
                array_push($examples, $row);
            }
            return ['status' => 'success', 'data' => $examples];
        } else {
            return ['status' => 'error', 'message' => 'No examples found'];
        }
    }

    public function get($id) {
        $result = $this->model->get($id);

        if ($result->num_rows > 0) {
            $example = $result->fetch_assoc();
            return ['status' => 'success', 'data' => $example];
        } else {
            return ['status' => 'error', 'message' => 'Example not found'];
        }
    }

	public function create() {
		$data = json_decode(file_get_contents('php://input'), true);

		if (!empty($data['name']) && !empty($data['description'])) {
			$result = $this->model->create($data);

			return $result;
		} else {
			return ['status' => 'error', 'message' => 'Name and description fields are required'];
		}
	}

	public function update($id) {
		$data = json_decode(file_get_contents('php://input'), true);

		if (!empty($data['name']) && !empty($data['description'])) {
			$result = $this->model->update($id, $data);

			return $result;
		} else {
			return ['status' => 'error', 'message' => 'Name and description fields are required'];
		}
	}

	public function delete($id) {
		if (!empty($id)) {
			$result = $this->model->delete($id);

			return $result;
		} else {
			return ['status' => 'error', 'message' => 'Invalid example ID'];
		}
	}

}

Neste exemplo, criamos uma classe ExampleController que contém os seguintes métodos:

  • __construct($dbConnection): Construtor da classe que recebe a conexão com o banco de dados e instancia o modelo ExampleModel.
  • getAll(): Método que obtém todos os registros usando o modelo e retorna a resposta no formato apropriado.
  • get($id): Método que obtém um registro específico usando o modelo e retorna a resposta no formato apropriado.
  • create(): Método para criar um novo registro usando o modelo e retornar a resposta no formato apropriado.
  • update($id): Método para atualizar um registro existente usando o modelo e retornar a resposta no formato apropriado.
  • delete($id): Método para excluir um registro usando o modelo e retornar a resposta no formato apropriado.

Você deve implementar a lógica nos métodos create, update e delete de acordo com suas necessidades. O controlador manipula a resposta e retorna os dados no formato apropriado para serem exibidos pelo arquivo routes/routes.php.

Agora que você implementou o controlador, a API está pronta para ser testada.

9 – Testando a API

Para testar a API, você pode usar um cliente HTTP como Postman, Insomnia ou até mesmo o cURL no terminal. Como exemplo, vamos supor que você esteja usando a seguinte estrutura de tabela no banco de dados:

CREATE TABLE examples (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    description TEXT
);

Certifique-se de ter alguns registros na tabela examples para testar a API corretamente.

Aqui estão alguns exemplos de como testar a API com diferentes métodos HTTP:

GET (listar todos os registros):
URL: http://localhost/example
Método: GET

GET (obter um registro específico):
URL: http://localhost/example/1
Método: GET

POST (criar um novo registro):
URL: http://localhost/example
Método: POST
Headers: Content-Type: application/json
Body:

{
    "name": "Joao Almeida",
    "description": "Uma descrição para este exemplo."
}

PUT (atualizar um registro existente):
URL: http://localhost/example/1
Método: PUT
Headers: Content-Type: application/json
Body:

{
    "name": "Valor Atualizado",
    "description": "Descrição para este exemplo de atualização."
}

DELETE (excluir um registro):
URL: http://localhost/example/1
Método: DELETE

Lembre-se de substituir localhost pelo endereço do seu servidor, se aplicável. Ao testar a API, você deve ver as respostas em JSON de acordo com as operações realizadas. Certifique-se de implementar a lógica nos métodos create, update e delete no controlador antes de testar essas ações.

Conclusão:

Agora você possui todas as habilidades necessárias para criar uma REST API em PHP do zero. Com este guia, você aprendeu a estruturar, configurar e testar sua API, tornando-se apto a implementar soluções robustas e escaláveis para suas aplicações web. Continue explorando e aprimorando suas habilidades em PHP e APIs REST!