| Recommend this page to a friend! |
| Info | Example | Screenshots | Reputation | Support forum | Blog | Links |
| Last Updated | Ratings | Unique User Downloads | Download Rankings | |||||
| 2024-10-27 (8 months ago) | Not enough user ratings | Total: 37 | All time: 10,991 This week: 30 | |||||
| Version | License | PHP version | Categories | |||
| fastapi 1.0.0 | MIT/X Consortium ... | 5 | PHP 5, Web services, Language |
<?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": "[email protected]", "senha": "1234" } Método: PUT
URL: http://localhost:8000/users/1
Body (raw JSON):
{ "nome": "nomeatualizado", "email": "[email protected]", "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) | ||
| File | Role | Description | ||
|---|---|---|---|---|
| Data | Auxiliary data | |||
| Data | Auxiliary data | |||
| Doc. | Documentation | |||
| / | src |
| File | Role | Description | ||
|---|---|---|---|---|
| | Example | Example script | ||
| / | src | / | Database |
| File | Role | Description |
|---|---|---|
| | Class | Class source |
| | 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. |
| Version Control | Unique User Downloads | Download Rankings | |||||||||||||||
| 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.