moudarir/codeigniter-rest-api

Codeigniter 3 Rest API

3.0.0 2024-04-24 22:22 UTC

This package is auto-updated.

Last update: 2024-09-24 23:22:04 UTC


README

GitHub release (latest) GitHub license

基于 CodeIgniter RestServer 的 Codeigniter 3 RESTful 服务器实现

重大变更 在版本 3.0 中实现。进行了完整的代码重构并实现了新的路由系统,灵感来自 Luthier CI

目录

  1. 需求
  2. 安装
  3. 实现
  4. 使用方法
  5. Postman 收集
  6. 待办事项

需求

  • PHP: 7.48.2 已测试。
  • Codeigniter: ^3.1.13
  • Composer

安装

当前版本 3.0.* 需要 php 7.4 或更高版本 (php 支持的版本)

此库使用 Composer 进行安装。

在您的 composer.json 文件相同的路径下运行此命令行(推荐)

composer require moudarir/codeigniter-rest-api

或者,在您的 composer.json 文件中,在 require 部分添加以下代码

{
  ...
  "require": {
    ...
    "moudarir/codeigniter-rest-api": "^3.0"
  },
  ...
}

然后运行

composer install

实现

语言/翻译

您可以在 application/language/ 文件夹中找到与您的语言相关的文件。它基于您的 [your-project]/application/config/config.php 配置文件中的 $config['language'] 设置。

支持的语言

  • 英语
  • 法语
  • 阿拉伯语

文件与配置

首先,将 CI 项目中所有必需的文件复制到您的 CI 项目中

  • application/config/rest-api-server.php => [your-project]/application/config/rest-api-server.php
  • application/controllers/DefaultController.php => [your-project]/application/controllers/DefaultController.php
  • application/language/*/rest-api-server_lang.php => [your-project]/application/language/*/rest-api-server_lang.php
  • application/routes/* => [your-project]/application/routes/*

不要 更改 [your-project]/application/config/rest-api-server.php[your-project]/application/language/*/rest-api-server_lang.php 的文件名。

确保 [your-project]/application/config/config.php 文件中的 enable_hookscomposer_autoload 键设置为以下内容

$config['enable_hooks'] = true;
$config['composer_autoload'] = true; // Or the path to 'autoload.php' file. Ex: APPPATH.'vendor/autoload.php'

接下来,在 [your-project]/application/config/hooks.php 文件中设置以下代码

$hook = \Moudarir\CodeigniterApi\Routes\Hook::initialize();

并在 [your-project]/application/config/routes.php 文件中

$route = \Moudarir\CodeigniterApi\Routes\Router::getRoutes();

重要

执行 dumping/queries.sql 文件以创建 API 正确工作所需的表。

将要创建的表是 usersapi_keysapi_key_limitsapi_key_logs

现在,您可以使用此库了 👌。

关于路由

旧路由的实现已弃用。现在路由已简化以实现最佳使用。请参阅 使用方法

使用方法

[your-project]/application/routes/api.php 文件中添加一些路由(如果不存在)。

\Moudarir\CodeigniterApi\Routes\Router::group('users', ['namespace' => 'api'], function () {
    \Moudarir\CodeigniterApi\Routes\Router::get('', 'apiUsers@index');
    \Moudarir\CodeigniterApi\Routes\Router::post('', 'apiUsers@create');
    \Moudarir\CodeigniterApi\Routes\Router::post('login', 'apiUsers@login');
    \Moudarir\CodeigniterApi\Routes\Router::put('{id}', 'apiUsers@update');
    \Moudarir\CodeigniterApi\Routes\Router::get('{id}', 'apiUsers@show');
});

// This will generate route array like this:
/**
$route = [
  "users" => [
    "GET" => "api/apiUsers/index",
    "POST" => "api/apiUsers/create",
  ],
  "users/login" => [
    "POST" => "api/apiUsers/login"
  ],
  "users/([0-9]+)" => [
    "PUT" => "api/apiUsers/update/$1"
    "GET" => "api/apiUsers/show/$1"
  ],
  "default_controller" => "welcome", // Can be changed in '[your-project]/application/config/rest-api-server.php' file.
  "translate_uri_dashes" => false, // Can be changed in '[your-project]/application/config/rest-api-server.php' file.
  "404_override" => "pageNotFound/index", // Can be changed in '[your-project]/application/config/rest-api-server.php' file.
]
**/

现在,我们可以创建我们的 [your-project]/application/controllers/api/ApiUsers.php 控制器

<?php
defined('BASEPATH') || exit('No direct script access allowed');

use Firebase\JWT\JWT;
use Moudarir\CodeigniterApi\Exceptions\DatabaseCreateException;
use Moudarir\CodeigniterApi\Http\Server;
use Moudarir\CodeigniterApi\Models\ApiKey;
use Moudarir\CodeigniterApi\Models\User;

class ApiUsers extends Server
{

    public function index()
    {
        $entity = new User();
        $page = $this->get('page');
        $total = $entity->count();
        $response = [
            'total' => $total,
            'items' => $total === 0 ? [] : $entity->all(['page' => $page, 'limit' => $this->get('limit')]),
        ];

        if ($page !== null) {
            $response['page'] = (int)$page === 0 ? 1 : (int)$page;
        }

        self::getResponse()->ok($response);
    }

    public function show(int $id)
    {
        if ($id <= 0) {
            self::getResponse()->badRequest();
        }

        $item = (new User())->find($id);

        if ($item === null) {
            self::getResponse()->notFound();
        }

        self::getResponse()->ok(['item' => $item]);
    }

    public function create()
    {
        $post = $this->post();
        $errors = [];

        if (array_key_exists('email', $post)) {
            $email = $this->post('email');

            if (empty($email) || filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
                $errors['email'] = "This field is not a valid email address.";
            }
        } else {
            $errors['email'] = "This field is required.";
        }

        if (!empty($errors)) {
            self::getResponse()->error($errors);
        }

        $entity = new User();

        try {
            $hashedPassword = password_hash($post['password'], PASSWORD_ARGON2I, [
                'memory_cost' => 1 << 12,
                'time_cost' => 2,
                'threads' => 2
            ]);
            $entity::getDatabase()->trans_start();
            $user = $entity
                ->setFirstname($post['firstname'])
                ->setLastname($post['lastname'])
                ->setEmail($post['email'])
                ->setPassword($hashedPassword)
                ->create();

            $apikey = (new ApiKey())
                ->setUserId($user->getId())
                ->setKey()
                ->setUsername()
                ->setPassword()
                ->create();

            if ($entity::getDatabase()->trans_status() === false) {
                $entity::getDatabase()->trans_rollback();
            } else {
                $entity::getDatabase()->trans_commit();
            }

            self::getResponse()->ok([
                'message' => "User account created successfully.",
                'data' => [
                    'user_id' => $user->getId(),
                    'api_key' => $apikey->getKey(),
                    'username' => $apikey->getUsername(),
                    'password' => $apikey->getPassword(),
                ]
            ]);
        } catch (DatabaseCreateException $e) {
            $entity::getDatabase()->trans_rollback();
            self::getResponse()->error("Error occurred during account creation.");
        }
    }

    public function update($id)
    {
        self::getResponse()->ok([
            'data' => [
                'info' => $this->getAuthData(),
                'args' => $this->put(),
                'id' => $id,
            ]
        ]);
    }

    public function login()
    {
        $apiConfig = $this->getApiConfig();
        $secret = getenv("JWT_SECRET");
        $secret !== false || $secret = $apiConfig['jwt_secret'];
        $user = (new User())->find($this->getApiKey()['user_id']);
        $payload = [
            'iss' => 'http://example.org',
            'aud' => 'http://example.com',
            'iat' => 1356999524,
            'nbf' => 1357000000,
            'user' => [
                'user_id' => $user['id'],
                'firstname' => $user['firstname'],
                'lastname' => $user['lastname'],
                'email' => $user['email'],
            ]
        ];
        self::getResponse()->ok([
            'data' => [
                'jwt_key' => JWT::encode($payload, $secret, $apiConfig['jwt_algorithm']),
            ]
        ]);
    }
}

认证方法

Rest 服务器可以与 BasicBearer 授权类型一起使用。然而,它也可以不使用任何授权类型(不安全)。

请求限制目前仅在 Basic 授权类型中工作。

Postman 收集

导入收集

下载我们的 Postman 收集,并将其导入 Postman。

导入环境

我们还提供了一个Postman 环境文件,您也需要导入。

要了解Postman环境是什么,请查看此链接

编辑环境变量

更新endpoint变量以指向您的Rest服务器。例如:(https//myapi.com/),结尾带斜杠。

✨ 就这么简单!

现在您可以使用Postman集合来测试可用请求。

在Postman集合中,必须遵守请求的执行顺序。

待办事项

  • 编写使用说明文档。
  • 改进文档。