Skip to content

Commit cc74d54

Browse files
committed
Improve the docs
1 parent 663d6c3 commit cc74d54

File tree

11 files changed

+123
-103
lines changed

11 files changed

+123
-103
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
- Added HTTP Access Log Generator middleware
55
- Added command methods to client interfaces
66
- Added Bzip2 message serializer
7-
- Optimize HTTP routing
7+
- Optimized HTTP routing
88

99
- 0.2.1-beta
1010
- Support PSR-15 Server Request Handler interface

README.md

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ $ composer require rubix/server
2323
- [REST Server](#rest-server)
2424
- [RPC Server](#rpc-server)
2525
- [Clients](#clients)
26+
- [REST Client](#rest-client)
2627
- [RPC Client](#rpc-client)
2728
- [HTTP Middleware](#http-middleware)
2829
- [Access Log Generator](#access-log-generator)
@@ -47,7 +48,7 @@ $server = new RESTServer('127.0.0.1', 8080);
4748

4849
$estimator = new KNearestNeighbors(5);
4950

50-
// Import the training set
51+
// Import a dataset
5152

5253
$estimator->train($dataset);
5354

@@ -83,12 +84,12 @@ Interfaces: [Server](#servers)
8384
#### HTTP Routes
8485
| Method | URI | JSON Params | Description |
8586
|--|--|--|--|
86-
| POST | /model/predictions | `samples` | Return the predictions given by the model. |
87-
| POST | /model/predictions/sample | `sample` | Make a prediction on a single sample. |
88-
| POST | /model/probabilities | `samples` | Predict the probabilities of each outcome. |
89-
| POST | /model/probabilities/sample | `sample` | Return the probabilities of a single sample. |
90-
| POST | /model/scores | `samples` | Assign an anomaly score to each sample. |
91-
| POST | /model/scores/sample | `sample` | Assign an anomaly score to a single sample. |
87+
| POST | /model/predictions | `samples` | Make a set of predictions on a dataset. |
88+
| POST | /model/predictions/sample | `sample` | Make a single prediction on a sample. |
89+
| POST | /model/probabilities | `samples` | Return the joint probabilities of each sample in a dataset. |
90+
| POST | /model/probabilities/sample | `sample` | Return the joint probabilities of a single sample. |
91+
| POST | /model/scores | `samples` | Return the anomaly scores of each sample in a dataset. |
92+
| POST | /model/scores/sample | `sample` | Return the anomaly score of a single sample. |
9293

9394
#### Example
9495

@@ -139,7 +140,7 @@ $server = new RPCServer('127.0.0.1', 8888, null, [
139140

140141
---
141142
### Clients
142-
Clients allow you to communicate directly with a model server over the wire using a friendly object-oriented interface inside your PHP applications.
143+
Clients allow you to communicate directly with a model server using a friendly object-oriented interface inside your PHP applications. Under the hood, clients handle all the networking communication and content negotiation for you so you can write programs *as if* the model was directly accessible in your applications.
143144

144145
Return the predictions from the model:
145146
```php
@@ -151,6 +152,8 @@ use Rubix\Server\RPCClient;
151152

152153
$client = new RPCClient('127.0.0.1', 8888);
153154

155+
// Import a dataset
156+
154157
$predictions = $client->predict($dataset);
155158
```
156159

@@ -180,7 +183,7 @@ public scoreSample(array $sample) : array
180183
```
181184

182185
#### Async Clients
183-
Clients that implement the Async Client interface have asynchronous versions of all the command methods. All asynchronous methods return a [Promises/A+](https://promisesaplus.com/) promise that resolves to the return value of the response.
186+
Clients that implement the Async Client interface have asynchronous versions of all the standard client methods. All asynchronous methods return a [Promises/A+](https://promisesaplus.com/) object that resolves to the return value of the response.
184187

185188
```php
186189
public predictAsync(Dataset $dataset) : Promise
@@ -298,7 +301,7 @@ $middleware = new AccessLog(new Screen());
298301
### Basic Authenticator
299302
An implementation of HTTP Basic Auth as described in [RFC7617](https://tools.ietf.org/html/rfc7617).
300303

301-
> **Note**: This authorization strategy is only secure over an encrypted communication channel such as HTTPS with SSL or TLS.
304+
> **Note:** This authorization strategy is only secure over an encrypted communication channel such as HTTPS with SSL or TLS.
302305
303306
#### Parameters
304307
| # | Param | Default | Type | Description |
@@ -320,7 +323,7 @@ $middleware = new BasicAuthenticator([
320323
### Shared Token Authenticator
321324
Authenticates incoming requests using a shared key that is kept secret between the client and server. It uses the `Authorization` header with the `Bearer` prefix to indicate the shared key.
322325

323-
> **Note**: This authorization strategy is only secure over an encrypted communication channel such as HTTPS with SSL or TLS.
326+
> **Note:** This authorization strategy is only secure over an encrypted communication channel such as HTTPS with SSL or TLS.
324327
325328
#### Parameters
326329
| # | Param | Default | Type | Description |

composer.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66
"license": "MIT",
77
"readme": "README.md",
88
"keywords": [
9-
"api", "cloud", "distributed", "inference", "inference engine", "inference server",
9+
"ai", "api", "cloud", "distributed", "inference", "inference engine", "inference server",
1010
"infrastructure", "json api", "machine learning", "microservice", "ml", "ml infrastructure",
11-
"model server", "model deployment", "php", "php machine learning", "php ml", "prediction",
12-
"rest api", "rest server", "rpc client", "rpc server", "rubix", "rubix ml", "rubixml",
13-
"server"
11+
"ml server", "model server", "model deployment", "php", "pap ai", "php machine learning",
12+
"php ml", "prediction", "rest api", "rest server", "rest client", "rpc client", "rpc server",
13+
"rubix", "rubix ml", "rubixml", "server"
1414
],
1515
"authors": [
1616
{

examples/RPC/client.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@
1818

1919
$dataset = $generator->generate(10)->randomize();
2020

21-
$predictions = $client->predict($dataset);
21+
$promise1 = $client->predictAsync($dataset);
2222

23-
$probabilities = $client->proba($dataset);
23+
$promise2 = $client->probaAsync($dataset);
2424

25-
print_r($predictions);
25+
print_r($promise1->wait());
2626

27-
print_r($probabilities);
27+
print_r($promise2->wait());
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
3+
namespace Rubix\Server\Http\Controllers;
4+
5+
use Rubix\Server\Services\CommandBus;
6+
use Rubix\Server\Commands\Command;
7+
use Rubix\Server\Serializers\Serializer;
8+
use Rubix\Server\Responses\ErrorResponse;
9+
use Rubix\Server\Exceptions\ValidationException;
10+
use Psr\Http\Message\ServerRequestInterface as Request;
11+
use Psr\Http\Message\ResponseInterface as Response;
12+
use React\Http\Message\Response as ReactResponse;
13+
use Exception;
14+
15+
use const Rubix\Server\Http\HTTP_OK;
16+
17+
class CommandsController extends RPCController
18+
{
19+
/**
20+
* The command bus.
21+
*
22+
* @var \Rubix\Server\Services\CommandBus
23+
*/
24+
protected $bus;
25+
26+
/**
27+
* @param \Rubix\Server\Services\CommandBus $bus
28+
* @param \Rubix\Server\Serializers\Serializer $serializer
29+
*/
30+
public function __construct(CommandBus $bus, Serializer $serializer)
31+
{
32+
$this->bus = $bus;
33+
34+
parent::__construct($serializer);
35+
}
36+
37+
/**
38+
* Handle the request.
39+
*
40+
* @param \Psr\Http\Message\ServerRequestInterface $request
41+
* @param mixed[]|null $params
42+
* @return \Psr\Http\Message\ResponseInterface
43+
*/
44+
public function handle(Request $request, ?array $params = null) : Response
45+
{
46+
try {
47+
$payload = $request->getBody()->getContents();
48+
49+
$command = $this->serializer->unserialize($payload);
50+
51+
if (!$command instanceof Command) {
52+
throw new ValidationException('Command could not be reconstituted.');
53+
}
54+
55+
$response = $this->bus->dispatch($command);
56+
57+
$status = HTTP_OK;
58+
} catch (Exception $exception) {
59+
$response = ErrorResponse::fromException($exception);
60+
61+
$status = $exception->getCode();
62+
}
63+
64+
$data = $this->serializer->serialize($response);
65+
66+
return new ReactResponse($status, $this->serializer->headers(), $data);
67+
}
68+
}

src/Http/Controllers/RPCController.php

Lines changed: 2 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,10 @@
22

33
namespace Rubix\Server\Http\Controllers;
44

5-
use Rubix\Server\Services\CommandBus;
6-
use Rubix\Server\Commands\Command;
75
use Rubix\Server\Serializers\Serializer;
8-
use Rubix\Server\Responses\ErrorResponse;
9-
use Rubix\Server\Exceptions\ValidationException;
10-
use Psr\Http\Message\ServerRequestInterface as Request;
11-
use Psr\Http\Message\ResponseInterface as Response;
12-
use React\Http\Message\Response as ReactResponse;
13-
use Exception;
146

15-
use const Rubix\Server\Http\HTTP_OK;
16-
17-
class RPCController extends Controller
7+
abstract class RPCController extends Controller
188
{
19-
/**
20-
* The command bus.
21-
*
22-
* @var \Rubix\Server\Services\CommandBus
23-
*/
24-
protected $bus;
25-
269
/**
2710
* The message serializer.
2811
*
@@ -31,44 +14,10 @@ class RPCController extends Controller
3114
protected $serializer;
3215

3316
/**
34-
* @param \Rubix\Server\Services\CommandBus $bus
3517
* @param \Rubix\Server\Serializers\Serializer $serializer
3618
*/
37-
public function __construct(CommandBus $bus, Serializer $serializer)
19+
public function __construct(Serializer $serializer)
3820
{
39-
$this->bus = $bus;
4021
$this->serializer = $serializer;
4122
}
42-
43-
/**
44-
* Handle the request.
45-
*
46-
* @param \Psr\Http\Message\ServerRequestInterface $request
47-
* @param mixed[]|null $params
48-
* @return \Psr\Http\Message\ResponseInterface
49-
*/
50-
public function handle(Request $request, ?array $params = null) : Response
51-
{
52-
try {
53-
$payload = $request->getBody()->getContents();
54-
55-
$command = $this->serializer->unserialize($payload);
56-
57-
if (!$command instanceof Command) {
58-
throw new ValidationException('Command could not be reconstituted.');
59-
}
60-
61-
$response = $this->bus->dispatch($command);
62-
63-
$status = HTTP_OK;
64-
} catch (Exception $exception) {
65-
$response = ErrorResponse::fromException($exception);
66-
67-
$status = $exception->getCode();
68-
}
69-
70-
$data = $this->serializer->serialize($response);
71-
72-
return new ReactResponse($status, $this->serializer->headers(), $data);
73-
}
7423
}

src/Http/Middleware/Middleware.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
interface Middleware
99
{
1010
/**
11-
* Allow an instance to be called like a function.
11+
* Process the request and return a response.
1212
*
1313
* @param Request $request
1414
* @param callable $next

src/RPCServer.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
use Rubix\ML\Estimator;
77
use Rubix\Server\Services\Router;
88
use Rubix\Server\Services\CommandBus;
9-
use Rubix\Server\Http\Controllers\RPCController;
9+
use Rubix\Server\Http\Controllers\CommandsController;
1010
use Rubix\Server\Http\Middleware\Middleware;
1111
use Rubix\Server\Serializers\JSON;
1212
use Rubix\Server\Serializers\Serializer;
@@ -143,7 +143,7 @@ public function serve(Estimator $estimator) : void
143143

144144
$this->router = new Router([
145145
'/commands' => [
146-
'POST' => new RPCController($bus, $this->serializer),
146+
'POST' => new CommandsController($bus, $this->serializer),
147147
],
148148
]);
149149

src/Services/CommandBus.php

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class CommandBus
5050
*
5151
* @var callable[]
5252
*/
53-
protected $mapping;
53+
protected $handlers;
5454

5555
/**
5656
* A PSR-3 logger instance.
@@ -68,41 +68,41 @@ class CommandBus
6868
*/
6969
public static function boot(Estimator $estimator, ?LoggerInterface $logger = null) : self
7070
{
71-
$mapping = [
71+
$handlers = [
7272
Predict::class => new PredictHandler($estimator),
7373
];
7474

7575
if ($estimator instanceof Learner) {
76-
$mapping += [
76+
$handlers += [
7777
PredictSample::class => new PredictSampleHandler($estimator),
7878
];
7979
}
8080

8181
if ($estimator instanceof Probabilistic) {
82-
$mapping += [
82+
$handlers += [
8383
Proba::class => new ProbaHandler($estimator),
8484
ProbaSample::class => new ProbaSampleHandler($estimator),
8585
];
8686
}
8787

8888
if ($estimator instanceof Ranking) {
89-
$mapping += [
89+
$handlers += [
9090
Score::class => new ScoreHandler($estimator),
9191
ScoreSample::class => new ScoreSampleHandler($estimator),
9292
];
9393
}
9494

95-
return new self($mapping, $logger);
95+
return new self($handlers, $logger);
9696
}
9797

9898
/**
99-
* @param callable[] $mapping
99+
* @param callable[] $handlers
100100
* @param \Psr\Log\LoggerInterface|null $logger
101101
* @throws \Rubix\Server\Exceptions\InvalidArgumentException
102102
*/
103-
public function __construct(array $mapping, ?LoggerInterface $logger = null)
103+
public function __construct(array $handlers, ?LoggerInterface $logger = null)
104104
{
105-
foreach ($mapping as $class => $handler) {
105+
foreach ($handlers as $class => $handler) {
106106
if (!class_exists($class)) {
107107
throw new InvalidArgumentException("Class $class does not exist.");
108108
}
@@ -112,7 +112,7 @@ public function __construct(array $mapping, ?LoggerInterface $logger = null)
112112
}
113113
}
114114

115-
$this->mapping = $mapping;
115+
$this->handlers = $handlers;
116116
$this->logger = $logger;
117117
}
118118

@@ -128,11 +128,11 @@ public function dispatch(Command $command) : Response
128128
{
129129
$class = get_class($command);
130130

131-
if (empty($this->mapping[$class])) {
131+
if (empty($this->handlers[$class])) {
132132
throw new HandlerNotFound($command);
133133
}
134134

135-
$handler = $this->mapping[$class];
135+
$handler = $this->handlers[$class];
136136

137137
try {
138138
return call_user_func($handler, $command);

0 commit comments

Comments
 (0)