Recommend this page to a friend! |
Download |
Info | Example | Screenshots | Files | Install with Composer | Download | Reputation | Support forum | Blog | Links |
Last Updated | Ratings | Unique User Downloads | Download Rankings | |||||
2024-10-27 (13 hours ago) | Not yet rated by the users | Total: Not yet counted | Not yet ranked |
Version | License | PHP version | Categories | |||
fastapi 1.0 | MIT/X Consortium ... | 5 | PHP 5, Web services, Language |
Description | Author | |
This package can create an API from controllers' PHPDoc comments. |
<?php |
O FastApi é um projeto de backend que facilita a inclusão de rotas em uma aplicação REST, permitindo a criação rápida de endpoints CRUD com operações básicas. O projeto utiliza anotações nos comentários (DocBlocks) dos controladores para definir as rotas, inspirado no estilo do FastAPI em Python. O banco de dados utilizado é o SQLite para facilitar os testes e a configuração inicial. Este projeto não possui frontend, focando apenas no backend.
git clone https://github.com/faustinopsy/fastapi.git
composer install
php -S localhost:8000
<?php
namespace Fast\Api\Controllers;
use Fast\Api\Models\User;
use Fast\Api\Repositories\UserRepository;
class UserController {
private $userRepository;
public function __construct() {
$this->userRepository = new UserRepository();
}
/
* @GET("/users")
*/
public function getAllUsers() {
// Retorna todos os usuários
}
/
* @GET("/users/{id}")
*/
public function getUserById($id) {
// Retorna um usuário pelo ID
}
/
* @POST("/users")
*/
public function createUser() {
// Cria um novo usuário
}
/
* @PUT("/users/{id}")
*/
public function updateUser($id) {
// Atualiza um usuário existente
}
/
* @DELETE("/users/{id}")
*/
public function deleteUser($id) {
// Deleta um usuário existente
}
}
O projeto inclui sete operações CRUD nas mesmas rotas, variando apenas o método HTTP. Veja abaixo os endpoints disponíveis:
Para testar os endpoints, você pode usar o Postman ou Thunder Client.
Body (raw JSON):
{
"nome": "seunome",
"email": "seunome@gmail.com",
"senha": "1234"
}
Método: PUT
URL: http://localhost:8000/users/1
Body (raw JSON):
{
"nome": "nomeatualizado",
"email": "emailatualizado@gmail.com",
"senha": "nova_senha"
}
Método: DELETE
URL: http://localhost:8000/users/1
As rotas são definidas diretamente nos métodos dos controladores usando anotações nos DocBlocks. O DocBlockRouter é responsável por ler essas anotações e registrar as rotas. Não é necessário registrar manualmente os controladores; o sistema carrega automaticamente todos os controladores presentes na pasta /Controllers. As rotas podem conter parâmetros, como {id}, que serão passados como argumentos para os métodos.
/
* @GET("/users/{id}")
*/
public function getUserById($id) {
// $id será o valor capturado da URL
}
O projeto utiliza a seguinte dependência:
phpdocumentor/reflection-docblock: Utilizada para interpretar as anotações nos DocBlocks. - Instalação via Composer:
composer require phpdocumentor/reflection-docblock
Certifique-se de que o composer.json está configurado para o autoloading das classes:
{
"autoload": {
"psr-4": {
"Fast\\Api\\": "src/"
}
}
}
O arquivo index.php é responsável por inicializar o roteamento e processar as requisições:
<?php
namespace Fast\Api;
use Fast\Api\Http\HttpHeader;
use Fast\Api\Rotas\DocBlockRouter;
require_once '../vendor/autoload.php';
// Define os cabeçalhos HTTP padrão
HttpHeader::setCabecalhosPadrao();
// Trata requisições OPTIONS para CORS
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(204);
exit();
}
// Obtém o método HTTP e a URI da requisição
$metodoHttp = $_SERVER['REQUEST_METHOD'];
$uri = $_SERVER['REQUEST_URI'];
// Cria uma instância do roteador
$roteador = new DocBlockRouter();
// Define o caminho base e o namespace para os controladores
$caminhoControladores = __DIR__ . '/../src/Controllers';
$namespaceBase = 'Fast\\Api\\Controllers';
// Obtém todas as classes de controladores dinamicamente
$classesControladoras = obterClassesControladoras($caminhoControladores, $namespaceBase);
// Passa todas as classes de controladores para o roteador
foreach ($classesControladoras as $classeControladora) {
$roteador->passaControlador($classeControladora);
}
// Resolve a rota com base no método HTTP e URI
$roteador->resolve($metodoHttp, $uri);
// Função para obter todas as classes de controladores
function obterClassesControladoras($caminhoControladores, $namespaceBase) {
$classesControladoras = [];
$iterador = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($caminhoControladores)
);
foreach ($iterador as $arquivo) {
if ($arquivo->isFile() && $arquivo->getExtension() === 'php') {
// Obtém o caminho do arquivo relativo ao caminho dos controladores
$caminhoRelativo = substr($arquivo->getPathname(), strlen($caminhoControladores));
// Remove os separadores de diretório iniciais
$caminhoRelativo = ltrim($caminhoRelativo, DIRECTORY_SEPARATOR);
// Remove a extensão '.php' do arquivo
$caminhoRelativo = substr($caminhoRelativo, 0, -4);
// Substitui os separadores de diretório pelos separadores de namespace
$parteNomeClasse = str_replace(DIRECTORY_SEPARATOR, '\\', $caminhoRelativo);
// Monta o nome completo da classe, incluindo o namespace
$nomeClasse = $namespaceBase . '\\' . $parteNomeClasse;
// Verifica se a classe existe (autoload)
if (!class_exists($nomeClasse)) {
// Inclui o arquivo para carregar a classe
require_once $arquivo->getPathname();
}
// Se a classe existe após inclusão, adiciona à lista de classes controladoras
if (class_exists($nomeClasse)) {
$classesControladoras[] = $nomeClasse;
}
}
}
return $classesControladoras;
}
este arquivo é dependente do Reflection e do phpDocumentor https://phpdoc.org/ https://www.php.net/manual/en/book.reflection.php
<?php
namespace Fast\Api\Rotas;
use ReflectionClass;
use ReflectionMethod;
use phpDocumentor\Reflection\DocBlockFactory;
class DocBlockRouter {
private array $rotas = [];
public function passaControlador(string $classeControladora) {
// Cria uma reflexão da classe controladora
$reflexaoControladora = new ReflectionClass($classeControladora);
// Obtém todos os métodos públicos da classe controladora
$metodos = $reflexaoControladora->getMethods(ReflectionMethod::IS_PUBLIC);
// Cria uma instância da fábrica de DocBlocks
$fabricaDocBlock = DocBlockFactory::createInstance();
// Percorre cada método público da classe controladora
foreach ($metodos as $metodo) {
// Obtém o comentário do DocBlock do método
$comentarioDoc = $metodo->getDocComment();
if ($comentarioDoc) {
// Cria um objeto DocBlock a partir do comentário
$docBlock = $fabricaDocBlock->create($comentarioDoc);
$metodosHttp = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'];
// Verifica se o DocBlock possui alguma das tags HTTP
foreach ($metodosHttp as $metodoHttp) {
if ($docBlock->hasTag($metodoHttp)) {
// Obtém a primeira tag correspondente ao método HTTP
$tagRota = $docBlock->getTagsByName($metodoHttp)[0];
// Obtém o conteúdo da descrição da tag (ex: '("/usuarios")')
$conteudo = $tagRota->getDescription()->render();
// Extrai o caminho da rota a partir do conteúdo da tag
preg_match('/\("(.*)"\)/', $conteudo, $correspondencias);
$caminho = $correspondencias[1] ?? '';
// Armazena a rota no array de rotas, associando o método HTTP, caminho e ação
$this->rotas[$metodoHttp][$caminho] = [$classeControladora, $metodo->getName()];
}
}
}
}
}
public function resolve($metodoHttp, $uri) {
// Verifica se existem rotas para o método HTTP solicitado
if (!isset($this->rotas[$metodoHttp])) {
http_response_code(405);
echo json_encode(['status' => false, 'message' => 'Método não permitido']);
exit();
}
// Obtém o caminho da URI (sem query strings)
$uri = parse_url($uri, PHP_URL_PATH);
// Percorre cada rota registrada para o método HTTP
foreach ($this->rotas[$metodoHttp] as $rota => $acao) {
// Substitui os parâmetros da rota por expressões regulares nomeadas
$padrao = preg_replace_callback('/\{([a-zA-Z_][a-zA-Z0-9_]*)\}/', function ($matches) {
$nomeParametro = $matches[1];
// Para parâmetros genéricos, permite qualquer sequência que não contenha '/'
return '(?P<' . $nomeParametro . '>[^/]+)';
}, $rota);
// Define o padrão como uma expressão regular completa
$padrao = '#^' . $padrao . '$#u';
// Verifica se a URI corresponde ao padrão da rota
if (preg_match($padrao, $uri, $correspondencias)) {
// Cria uma instância da classe controladora
$instanciaControladora = new $acao[0]();
$nomeMetodo = $acao[1];
// Filtra os parâmetros nomeados capturados na expressão regular
$parametros = array_filter(
$correspondencias,
fn($chave) => is_string($chave),
ARRAY_FILTER_USE_KEY
);
// Obtém os dados do corpo da requisição (se houver)
$dados = json_decode(file_get_contents('php://input'), true);
// Obtém os parâmetros esperados pelo método através da reflexão
$metodoRefletido = new ReflectionMethod($instanciaControladora, $nomeMetodo);
$parametrosMetodo = $metodoRefletido->getParameters();
$argumentos = [];
// Prepara os argumentos a serem passados para o método, na ordem correta
foreach ($parametrosMetodo as $parametro) {
$nome = $parametro->getName();
if (isset($parametros[$nome])) {
$argumentos[] = $parametros[$nome];
} elseif ($nome === 'dados') {
$argumentos[] = $dados;
} else {
$argumentos[] = null;
}
}
// Chama o método da controladora com os argumentos obtidos
return call_user_func_array([$instanciaControladora, $nomeMetodo], $argumentos);
}
}
// Se nenhuma rota corresponder, retorna erro 404
http_response_code(404);
echo json_encode(['status' => false, 'message' => 'Rota não encontrada']);
exit();
}
}
Este projeto está licenciado sob a MIT License.
Screenshots (7) | ||
Files (18) |
File | Role | Description | ||
---|---|---|---|---|
src (1 file, 6 directories) | ||||
composer.json | Data | Auxiliary data | ||
composer.lock | Data | Auxiliary data | ||
readme.md | Doc. | Documentation |
Files (18) | / | src |
File | Role | Description | ||
---|---|---|---|---|
Controllers (1 file) | ||||
Database (2 files) | ||||
Http (1 file) | ||||
Models (1 file) | ||||
Repositories (1 file) | ||||
Rotas (1 file) | ||||
index.php | Example | Example script |
Files (18) | / | src | / | Database |
File | Role | Description |
---|---|---|
config.php | Class | Class source |
Database.php | Class | Class source |
The PHP Classes site has supported package installation using the Composer tool since 2013, as you may verify by reading this instructions page. |
Install with Composer |
Version Control | Unique User Downloads | |||||||
100% |
|
Applications that use this package |
If you know an application of this package, send a message to the author to add a link here.