Suas ideias em realidade digital!
Neste guia você vai montar uma API REST em PHP puro (sem framework) com:
/public
/api
index.php
.htaccess
/src
/Controllers
PostController.php
/Core
Router.php
Response.php
Auth.php
/Db
Database.php
Crie /public/api/.htaccess:
RewriteEngine On
# se arquivo ou pasta existe, entrega direto
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
# tudo vai para o index.php
RewriteRule ^ index.php [QSA,L]
Crie /public/api/index.php:
get('/api/health', function() {
Response::json(['ok' => true, 'service' => 'makrosites-api']);
});
// Posts CRUD (exemplo)
$controller = new PostController();
$router->get('/api/posts', [$controller, 'index']);
$router->get('/api/posts/{id}', [$controller, 'show']);
// rotas protegidas
$router->post('/api/posts', function() use ($controller) {
Auth::requireBearer();
$controller->store();
});
$router->put('/api/posts/{id}', function($params) use ($controller) {
Auth::requireBearer();
$controller->update($params['id']);
});
$router->delete('/api/posts/{id}', function($params) use ($controller) {
Auth::requireBearer();
$controller->destroy($params['id']);
});
// executa
$router->dispatch($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI']);
Crie /src/Core/Router.php:
add('GET', $path, $handler); }
public function post($path, $handler) { $this->add('POST', $path, $handler); }
public function put($path, $handler) { $this->add('PUT', $path, $handler); }
public function delete($path, $handler) { $this->add('DELETE', $path, $handler); }
private function add($method, $path, $handler) {
$this->routes[] = compact('method', 'path', 'handler');
}
public function dispatch($method, $uri) {
$path = parse_url($uri, PHP_URL_PATH);
foreach ($this->routes as $r) {
if ($r['method'] !== $method) continue;
$params = [];
$pattern = preg_replace('#\{([a-zA-Z_][a-zA-Z0-9_]*)\}#', '(?P<$1>[^/]+)', $r['path']);
$pattern = '#^' . $pattern . '$#';
if (preg_match($pattern, $path, $matches)) {
foreach ($matches as $k => $v) {
if (!is_int($k)) $params[$k] = $v;
}
// handler pode ser callable direto ou closure que recebe params
if (is_array($r['handler'])) {
return call_user_func($r['handler'], $params);
}
return $r['handler']($params);
}
}
Response::error('Not Found', 404);
}
}
Crie /src/Core/Response.php:
$message];
if ($details !== null) $payload['details'] = $details;
self::json($payload, $code);
}
public static function readJsonBody(): array {
$raw = file_get_contents('php://input');
$data = json_decode($raw, true);
if (!is_array($data)) self::error('JSON inválido', 422);
return $data;
}
}
Crie /src/Core/Auth.php:
6) PostController.php: CRUD de exemplo
Crie /src/Controllers/PostController.php:
1, 'title' => 'Post 1'],
['id' => 2, 'title' => 'Post 2'],
]);
}
public function show($params) {
$id = (int)($params['id'] ?? 0);
if ($id <= 0) Response::error('ID inválido', 422);
Response::json(['id' => $id, 'title' => 'Exemplo de post']);
}
public function store() {
$data = Response::readJsonBody();
if (empty($data['title'])) Response::error('title é obrigatório', 422);
// aqui você salva no banco...
Response::json(['message' => 'Criado com sucesso', 'data' => $data], 201);
}
public function update($id) {
$id = (int)$id;
if ($id <= 0) Response::error('ID inválido', 422);
$data = Response::readJsonBody();
Response::json(['message' => 'Atualizado', 'id' => $id, 'data' => $data]);
}
public function destroy($id) {
$id = (int)$id;
if ($id <= 0) Response::error('ID inválido', 422);
Response::json(['message' => 'Deletado', 'id' => $id]);
}
}
7) Testando com curl
GET sem token:
curl -i https://www.makrosites.com.br/api/posts
POST com Bearer Token:
curl -i -X POST https://www.makrosites.com.br/api/posts \
-H "Authorization: Bearer SEU_TOKEN_FIXO_DE_TESTE" \
-H "Content-Type: application/json" \
-d '{"title":"Meu post"}'
Melhorias recomendadas (para produção)
- Validar token no banco e expiração
- Adicionar CORS se a API for consumida por front externo
- Log de erros e padronização de responses (success/data/error)
- Rate limit simples para evitar abuso