xp-forge/rest-api

v4.4.0 2024-03-24 13:22 UTC

README

Build status on GitHub XP Framework Module BSD Licence Requires PHP 7.0+ Supports PHP 8.0+ Latest Stable Version

基于注解的REST API

示例

use web\rest\{Get, Post, Resource, Response};

#[Resource('/users')]
class Users {

  #[Get('/')]
  public function listUsers($max= 10) {
    // $max comes from request parameter "max", defaulting to 10
    // ...
  }

  #[Get('/{id}')]
  public function findUser($id) {
    // $id is extracted from URL segment
    // ...
  }

  #[Post('/')]
  public function createUser($user) {
    // $user is deserialized from the request body according to its content type
    // ...
    return Response::created('/users/{id}', $id)->entity($created);
  }
}

在Web应用程序中组合它

use web\Application;

class Service extends Application {

  /** @return [:var] */
  public function routes() {
    return ['/users' => new RestApi(new Users())];
  }
}

使用以下命令运行

$ xp -supervise web Service
@xp.web.Serve(HTTP @ peer.ServerSocket(resource(type= Socket, id= 88) -> tcp://127.0.0.1:8080))
# ...

然后调用 curl -i localhost:8080/users/1549.

参数来源

如果方法参数的名称与花括号中的路径段匹配,则自动从URI段中提取参数。对于没有主体的请求(GET、HEAD、DELETE、OPTIONS),值从请求参数中提取。对于有主体的请求(POST、PUT和PATCH),将反序列化主体并传递。

要显式提供源,您可以使用参数属性

  • #[Param] 将从名为 "max" 的请求参数中获取参数。
  • #[Param('maximum')] 将从名为 "maximum" 的请求参数中获取参数。
  • #[Value] 将使用请求值(例如,通过 pass() 在过滤器中传递的值)作为参数
  • #[Header('Content-Type')] 将使用 Content-Type 标头作为参数的值
  • #[Entity] 将反序列化请求主体并将其值传递给参数
  • #[Body] 将请求主体作为字符串传递
  • #[Stream]io.streams.InputStream 实例传递给流请求主体到参数
  • #[Request] 将完整的 web.Request 对象传递

参数转换

可以将参数从其输入转换。此库自带了一个名为 SeparatedBy 的内置转换。

use web\rest\{Resource, Get, Param, SeparatedBy};

#[Resource('/api/trainings')]
class Trainings {

  #[Get('/completed')]
  public function completed(#[Param, SeparatedBy(',')] array $orgunits) {
    return $this->repository->find(['status' => 'COMPLETED', 'orgunits' => $orgunits]);
  }
}

orgunits 参数现在可以在URL中按如下方式提供:https://example.com/api/trainings/completed?orgunits=A,B,并且 $orgunits 中的结果值将是 ["A", "B"]。可以通过实现 web.rest.Conversion 接口提供用户定义的转换。

矩阵参数

此库支持路径段中的参数,例如:https://example.com/api/trainings/status=COMPLETED;orgunits=A,B/authors

use web\rest\{Resource, Get, Matrix};

#[Resource('/api/trainings')]
class Trainings {

  #[Get('/{filter}/authors')]
  public function authors(#[Matrix] array $filter) {
    $authors= [];
    foreach ($this->repository->find($filter) as $training) {
      $authors[$training->author->id()]= $training->author;
    }
    return $authors;
  }
}

$filter 中的结果值将是 ["status" => "COMPLETED", "orgunits" => ["A", "B"]]

返回类型

方法可以返回任何内容,然后将其序列化并写入响应,状态为 "200 OK"。如果您想对响应有更多的控制,可以使用 web.rest.Response 类。它提供了一个流畅的DSL来处理各种场景。

示例

return Response::created('/users/{id}', $id)->type('application/vnd.example.type-v2+json')->entity($user);

创建

  • Response::ok() - 200 OK
  • Response::created([string $location]) - 201 Created,可选地带有 Location 标头
  • Response::noContent() - 204 No content
  • Response::see(string $location) - 302 Found 和一个 Location 标头
  • Response::notModified() - 304 Not modified
  • Response::notFound([string $message]) - 404 Not found 和一个可选的消息,该消息将被序列化
  • Response::notAcceptable([string $message]) - 406 Not acceptable 和一个可选的消息,该消息将被序列化
  • Response::error(int $code[, string $message]) - 错误和一个可选的消息,该消息将被序列化
  • Response::status(int $code) - 其他任何状态码

标头

  • $response->type(string $mime) 将设置 Content-Type 标头
  • $response->header(string $name, string $value) 将设置一个给定名称和值的标头

主体

  • $response->entity(var $value) 将发送一个值,并将其序列化
  • $response->stream(io.streams.InputStream $in[, int $size]) 将流式传输一个响应
  • $response->body(string $bytes) 将给定的原始字节写入响应

异步调用

以下代码将异步运行上传功能,在文件内容传输的同时继续服务请求。

use io\Folder;
use web\rest\{Async, Post, Resource, Response};

#[Resource('/api')]
class Uploads {
  public function __construct(private Folder $folder) { }

  #[Post('/files')]
  public function upload(#[Request] $req) {
    return new Async(function() use($req) {
      if ($multipart= $req->multipart()) {

        foreach ($multipart->files() as $file) {
          yield from $file->transmit($this->folder);
        }
      }

      return Response::ok();
    });
  }
}

另请参阅

https://github.com/thekid/shorturl - URL缩短服务