Update documentation for overview, getting started, messages
This commit is contained in:
parent
6395a6177c
commit
ac9f40be5f
|
|
@ -3,15 +3,14 @@ Getting Started
|
||||||
|
|
||||||
This page provides a brief introduction to WellRESTed. We'll take a tour of some of the features of WellRESTed without getting into too much depth.
|
This page provides a brief introduction to WellRESTed. We'll take a tour of some of the features of WellRESTed without getting into too much depth.
|
||||||
|
|
||||||
To start, we'll make a "`Hello, world!`_" to demonstrate the concepts of middleware and routing and show how to read variables from the request path.
|
To start, we'll make a "`Hello, world!`_" to demonstrate the concepts of handlers and routing and show how to read variables from the request path.
|
||||||
|
|
||||||
Hello, World!
|
Hello, World!
|
||||||
^^^^^^^^^^^^^
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
Let's start with a very basic "Hello, world!". Here, we will create a server. A ``WellRESTed\Server`` reads the
|
Let's start with a very basic "Hello, world!". Here, we will create a server. A ``WellRESTed\Server`` reads the incoming request from the client, dispatches a handler, and transmits a response back to the client.
|
||||||
incoming request from the client, dispatches some middleware_, and transmits a response back to the client.
|
|
||||||
|
|
||||||
Our middleware is a function that returns a response with the status code set to ``200`` and the body set to "Hello, world!".
|
Our handler will create and return a response with the status code set to ``200`` and the body set to "Hello, world!".
|
||||||
|
|
||||||
.. _`Example 1`:
|
.. _`Example 1`:
|
||||||
.. rubric:: Example 1: Simple "Hello, world!"
|
.. rubric:: Example 1: Simple "Hello, world!"
|
||||||
|
|
@ -20,31 +19,37 @@ Our middleware is a function that returns a response with the status code set to
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use Psr\Http\Server\RequestHandlerInterface;
|
||||||
|
use WellRESTed\Message\Response;
|
||||||
use WellRESTed\Message\Stream;
|
use WellRESTed\Message\Stream;
|
||||||
use WellRESTed\Server;
|
use WellRESTed\Server;
|
||||||
|
|
||||||
require_once "vendor/autoload.php";
|
require_once 'vendor/autoload.php';
|
||||||
|
|
||||||
|
// Define a handler implementing the PSR-15 RequestHandlerInterface interface.
|
||||||
|
class HelloHandler implements RequestHandlerInterface
|
||||||
|
{
|
||||||
|
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||||
|
{
|
||||||
|
$response = (new Response(200))
|
||||||
|
->withHeader('Content-type', 'text/plain')
|
||||||
|
->withBody(new Stream('Hello, world!'));
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create a new server.
|
// Create a new server.
|
||||||
$server = new Server();
|
$server = new Server();
|
||||||
|
|
||||||
// Add middleware to dispatch that will return a response.
|
// Add this handler to the server.
|
||||||
// In this case, we'll use an anonymous function.
|
$server->add(new HelloHandler());
|
||||||
$server->add(function ($request, $response, $next) {
|
|
||||||
// Update the response with the greeting, status, and content-type.
|
|
||||||
$response = $response->withStatus(200)
|
|
||||||
->withHeader("Content-type", "text/plain")
|
|
||||||
->withBody(new Stream("Hello, world!"));
|
|
||||||
// Use $next to forward the request on to the next middleware, if any.
|
|
||||||
return $next($request, $response);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Read the request sent to the server and use it to output a response.
|
// Read the request sent to the server and use it to output a response.
|
||||||
$server->respond();
|
$server->respond();
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
The middleware in this example provides a ``Stream`` as the body instead of a string. This is a feature or PSR-7 where HTTP message bodies are always represented by streams. This allows you to work with very large bodies without having to store the entire contents in memory.
|
The handler in this example provides a ``Stream`` as the body instead of a string. This is a feature or PSR-7 where HTTP message bodies are always represented by streams. This allows you to work with very large bodies without having to store the entire contents in memory.
|
||||||
|
|
||||||
WellRESTed provides ``Stream`` and ``NullStream``, but you can use any implementation of ``Psr\Http\Message\StreamInterface``.
|
WellRESTed provides ``Stream`` and ``NullStream``, but you can use any implementation of ``Psr\Http\Message\StreamInterface``.
|
||||||
|
|
||||||
|
|
@ -53,7 +58,7 @@ Routing by Path
|
||||||
|
|
||||||
This is a good start, but it provides the same response to every request. Let's provide this response only when a client sends a request to ``/hello``.
|
This is a good start, but it provides the same response to every request. Let's provide this response only when a client sends a request to ``/hello``.
|
||||||
|
|
||||||
For this, we need a router_. A router_ is a special type of middleware_ that examines the request and routes the request through to the middleware that matches.
|
For this, we need a router_. A router_ examines the request and sends the request through to the handler that mataches the request's HTTP method and path.
|
||||||
|
|
||||||
.. _`Example 2`:
|
.. _`Example 2`:
|
||||||
.. rubric:: Example 2: Routed "Hello, world!"
|
.. rubric:: Example 2: Routed "Hello, world!"
|
||||||
|
|
@ -62,26 +67,12 @@ For this, we need a router_. A router_ is a special type of middleware_ that exa
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use WellRESTed\Message\Stream;
|
// Create a new server.
|
||||||
use WellRESTed\Server;
|
|
||||||
|
|
||||||
require_once "vendor/autoload.php";
|
|
||||||
|
|
||||||
// Create a new server and use it to create a new router.
|
|
||||||
$server = new Server();
|
$server = new Server();
|
||||||
|
|
||||||
|
// Create a router to map methods and endpoints to handlers.
|
||||||
$router = $server->createRouter();
|
$router = $server->createRouter();
|
||||||
|
$router->register('GET', '/hello', new HelloHandler());
|
||||||
// Map middleware to an endpoint and method(s).
|
|
||||||
$router->register("GET", "/hello", function ($request, $response, $next) {
|
|
||||||
// Update the response with the greeting, status, and content-type.
|
|
||||||
$response = $response->withStatus(200)
|
|
||||||
->withHeader("Content-type", "text/plain")
|
|
||||||
->withBody(new Stream("Hello, world!"));
|
|
||||||
// Use $next to forward the request on to the next middleware, if any.
|
|
||||||
return $next($request, $response);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add the router to the server.
|
|
||||||
$server->add($router);
|
$server->add($router);
|
||||||
|
|
||||||
// Read the request sent to the server and use it to output a response.
|
// Read the request sent to the server and use it to output a response.
|
||||||
|
|
@ -92,8 +83,6 @@ Reading Path Variables
|
||||||
|
|
||||||
Routes can be static (like the one above that matches only ``/hello``), or they can be dynamic. Here's an example that uses a dynamic route to read a portion from the path to use as the greeting. For example, a request to ``/hello/Molly`` will respond "Hello, Molly", while a request to ``/hello/Oscar`` will respond "Hello, Oscar!"
|
Routes can be static (like the one above that matches only ``/hello``), or they can be dynamic. Here's an example that uses a dynamic route to read a portion from the path to use as the greeting. For example, a request to ``/hello/Molly`` will respond "Hello, Molly", while a request to ``/hello/Oscar`` will respond "Hello, Oscar!"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. _`Example 3`:
|
.. _`Example 3`:
|
||||||
.. rubric:: Example 3: Personalized "Hello, world!"
|
.. rubric:: Example 3: Personalized "Hello, world!"
|
||||||
|
|
||||||
|
|
@ -101,24 +90,31 @@ Routes can be static (like the one above that matches only ``/hello``), or they
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
use Psr\Http\Server\MiddlewareInterface;
|
||||||
|
use WellRESTed\Message\Response;
|
||||||
use WellRESTed\Message\Stream;
|
use WellRESTed\Message\Stream;
|
||||||
use WellRESTed\Server;
|
use WellRESTed\Server;
|
||||||
|
|
||||||
require_once "vendor/autoload.php";
|
require_once "vendor/autoload.php";
|
||||||
|
|
||||||
// Define middleware.
|
class HelloHandler implements RequestHandlerInterface
|
||||||
$hello = function ($request, $response, $next) {
|
{
|
||||||
|
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||||
|
{
|
||||||
// Check for a "name" attribute which may have been provided as a
|
// Check for a "name" attribute which may have been provided as a
|
||||||
// path variable. The second parameters allows us to set a default.
|
// path variable. Use "world" as a default.
|
||||||
$name = $request->getAttribute("name", "world");
|
$name = $request->getAttribute("name", "world");
|
||||||
|
|
||||||
// Update the response with the greeting, status, and content-type.
|
// Set the response body to the greeting and the status code to 200 OK.
|
||||||
$response = $response->withStatus(200)
|
$response = (new Response(200))
|
||||||
->withHeader("Content-type", "text/plain")
|
->withHeader("Content-type", "text/plain")
|
||||||
->withBody(new Stream("Hello, $name!"));
|
->withBody(new Stream("Hello, $name!"));
|
||||||
|
|
||||||
return $next($request, $response);
|
// Return the response.
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the server and router.
|
// Create the server and router.
|
||||||
|
|
@ -129,65 +125,88 @@ Routes can be static (like the one above that matches only ``/hello``), or they
|
||||||
$router->register("GET", "/hello", $hello);
|
$router->register("GET", "/hello", $hello);
|
||||||
// Register to match a pattern with a variable.
|
// Register to match a pattern with a variable.
|
||||||
$router->register("GET", "/hello/{name}", $hello);
|
$router->register("GET", "/hello/{name}", $hello);
|
||||||
|
|
||||||
$server->add($router);
|
$server->add($router);
|
||||||
|
|
||||||
$server->respond();
|
$server->respond();
|
||||||
|
|
||||||
Multiple Middleware
|
Middleware
|
||||||
^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^
|
||||||
|
|
||||||
One thing we haven't seen yet is how middleware work together. For the next example, we'll use an additional middleware that sets an ``X-example: hello world``.
|
In addition to handlers, WellRESTed also supports middlware. Middleware allows you to compose your application in multiple pieces. In the example, we'll use middleware to add a header to every responce, regardless of which handler is called.
|
||||||
|
|
||||||
.. code-block:: php
|
.. code-block:: php
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
use Psr\Http\Server\MiddlewareInterface;
|
||||||
|
use Psr\Http\Server\RequestHandlerInterface;
|
||||||
|
use WellRESTed\Message\Response;
|
||||||
use WellRESTed\Message\Stream;
|
use WellRESTed\Message\Stream;
|
||||||
use WellRESTed\Server;
|
use WellRESTed\Server;
|
||||||
|
|
||||||
require_once "vendor/autoload.php";
|
require_once 'vendor/autoload.php';
|
||||||
|
|
||||||
// Set the status code and provide the greeting as the response body.
|
|
||||||
$hello = function ($request, $response, $next) {
|
|
||||||
|
|
||||||
|
// Create a handler that will construct and return a response. We'll
|
||||||
|
// register this handler with a server and router below.
|
||||||
|
class HelloHandler implements RequestHandlerInterface
|
||||||
|
{
|
||||||
|
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||||
|
{
|
||||||
// Check for a "name" attribute which may have been provided as a
|
// Check for a "name" attribute which may have been provided as a
|
||||||
// path variable. Use "world" as a default.
|
// path variable. Use "world" as a default.
|
||||||
$name = $request->getAttribute("name", "world");
|
$name = $request->getAttribute("name", "world");
|
||||||
|
|
||||||
// Set the response body to the greeting and the status code to 200 OK.
|
// Set the response body to the greeting and the status code to 200 OK.
|
||||||
$response = $response->withStatus(200)
|
$response = (new Response(200))
|
||||||
->withHeader("Content-type", "text/plain")
|
->withHeader("Content-type", "text/plain")
|
||||||
->withBody(new Stream("Hello, $name!"));
|
->withBody(new Stream("Hello, $name!"));
|
||||||
|
|
||||||
// Propagate to the next middleware, if any, and return the response.
|
// Return the response.
|
||||||
return $next($request, $response);
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
};
|
// Create middleware that will add a custom header to every response.
|
||||||
|
class CustomerHeaderMiddleware implements MiddlewareInterface
|
||||||
|
{
|
||||||
|
public function process(
|
||||||
|
ServerRequestInterface $request,
|
||||||
|
RequestHandlerInterface $handler
|
||||||
|
): ResponseInterface {
|
||||||
|
|
||||||
|
// Delegate to the next handler in the chain to obtain a response.
|
||||||
|
$response = $handler->handle($request);
|
||||||
|
|
||||||
// Add a header to the response.
|
|
||||||
$headerAdder = function ($request, $response, $next) {
|
|
||||||
// Add the header.
|
// Add the header.
|
||||||
$response = $response->withHeader("X-example", "hello world");
|
$response = $response->withHeader("X-example", "hello world");
|
||||||
// Propagate to the next middleware, if any, and return the response.
|
|
||||||
return $next($request, $response);
|
// Return the altered response.
|
||||||
};
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create a server
|
// Create a server
|
||||||
$server = new Server();
|
$server = new Server();
|
||||||
|
|
||||||
// Add $headerAdder to the server first to make it the first to run.
|
// Add the header adding middleware to the server first so that it will
|
||||||
$server->add($headerAdder);
|
// forward requests on to the router.
|
||||||
|
$server->add(new CustomerHeaderMiddleware());
|
||||||
|
|
||||||
// When $headerAdder calls $next, it will dispatch the router because it is
|
// Create a router to map methods and endpoints to handlers.
|
||||||
// added to the server right after.
|
$router = $server->createRouter();
|
||||||
$server->add($server->createRouter()
|
|
||||||
->register("GET", "/hello", $hello)
|
|
||||||
->register("GET", "/hello/{name}", $hello)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Read the request from the client, dispatch middleware, and output.
|
$handler = new HelloHandler();
|
||||||
|
// Register a route to the handler without a variable in the path.
|
||||||
|
$router->register('GET', '/hello', $handler);
|
||||||
|
// Register a route that reads a "name" from the path.
|
||||||
|
// This will make the "name" request attribute available to the handler.
|
||||||
|
$router->register('GET', '/hello/{name}', $handler);
|
||||||
|
$server->add($router);
|
||||||
|
|
||||||
|
// Read the request from the client, dispatch, and output.
|
||||||
$server->respond();
|
$server->respond();
|
||||||
|
|
||||||
|
|
||||||
.. _middleware: middleware.html
|
.. _middleware: middleware.html
|
||||||
.. _router: router.html
|
.. _router: router.html
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,6 @@ The site will also provide an ``X-example: hello world`` using dedicated middlew
|
||||||
// Register a route that reads a "name" from the path.
|
// Register a route that reads a "name" from the path.
|
||||||
// This will make the "name" request attribute available to the handler.
|
// This will make the "name" request attribute available to the handler.
|
||||||
$router->register('GET', '/hello/{name}', $handler);
|
$router->register('GET', '/hello/{name}', $handler);
|
||||||
|
|
||||||
$server->add($router);
|
$server->add($router);
|
||||||
|
|
||||||
// Read the request from the client, dispatch, and output.
|
// Read the request from the client, dispatch, and output.
|
||||||
|
|
|
||||||
|
|
@ -3,33 +3,10 @@ Messages and PSR-7
|
||||||
|
|
||||||
WellRESTed uses PSR-7_ as the interfaces for HTTP messages. This section provides an introduction to working with these interfaces and the implementations provided with WellRESTed. For more information, please read PSR-7_.
|
WellRESTed uses PSR-7_ as the interfaces for HTTP messages. This section provides an introduction to working with these interfaces and the implementations provided with WellRESTed. For more information, please read PSR-7_.
|
||||||
|
|
||||||
Obtaining Instances
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
When working with middleware_, you generally will not need to create requests and responses yourself, as these are passed into the middleware when it is dispatched.
|
|
||||||
|
|
||||||
In `Getting Started`_, we saw that middleware looks like this:
|
|
||||||
|
|
||||||
.. code-block:: php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Psr\Http\Message\ServerRequestInterface $request
|
|
||||||
* @param Psr\Http\Message\ResponseInterface $response
|
|
||||||
* @param callable $next
|
|
||||||
* @return Psr\Http\Message\ResponseInterface
|
|
||||||
*/
|
|
||||||
function ($request, $response, $next) { }
|
|
||||||
|
|
||||||
When middleware is called, it receives a ``Psr\Http\Message\ServerRequestInterface`` instance representing the client's request and a ``Psr\Http\Message\ResponseInterface`` instance that serves as a starting place for the response to output to the client. These instances are created by the ``WellRESTed\Server`` when you call ``WellRESTed\Server::respond``.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
If you want to provide your own custom request and response (either to adjust the initial settings or to use a different implementation), you can do so by passing request and response instances as the first and second parameters to ``WellRESTed\Server::respond``.
|
|
||||||
|
|
||||||
Requests
|
Requests
|
||||||
--------
|
--------
|
||||||
|
|
||||||
The ``$request`` variable passed to middleware represents the request message sent by the client. Middleware can inspect this variable to read information such as the request path, method, query, headers, and body.
|
The ``$request`` variable passed to handlers and middleware represents the request message sent by the client. You can inspect this variable to read information such as the request path, method, query, headers, and body.
|
||||||
|
|
||||||
Let's start with a very simple GET request to the path ``/cats/?color=orange``.
|
Let's start with a very simple GET request to the path ``/cats/?color=orange``.
|
||||||
|
|
||||||
|
|
@ -39,12 +16,14 @@ Let's start with a very simple GET request to the path ``/cats/?color=orange``.
|
||||||
Host: example.com
|
Host: example.com
|
||||||
Cache-control: no-cache
|
Cache-control: no-cache
|
||||||
|
|
||||||
You can read information from the request in your middleware like this:
|
You can read information from the request in your handler like this:
|
||||||
|
|
||||||
.. code-block:: php
|
.. code-block:: php
|
||||||
|
|
||||||
function ($request, $response, $next) {
|
class MyHandler implements RequestHandlerInterface
|
||||||
|
{
|
||||||
|
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||||
|
{
|
||||||
$path = $request->getRequestTarget();
|
$path = $request->getRequestTarget();
|
||||||
// "/cats/?color=orange"
|
// "/cats/?color=orange"
|
||||||
|
|
||||||
|
|
@ -58,10 +37,10 @@ You can read information from the request in your middleware like this:
|
||||||
[color] => orange
|
[color] => orange
|
||||||
)
|
)
|
||||||
*/
|
*/
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
This example middleware shows that you can use:
|
This example shows that you can use:
|
||||||
|
|
||||||
- ``getRequestTarget()`` to read the path and query string for the request
|
- ``getRequestTarget()`` to read the path and query string for the request
|
||||||
- ``getMethod()`` to read the HTTP verb (e.g., GET, POST, OPTIONS, DELETE)
|
- ``getMethod()`` to read the HTTP verb (e.g., GET, POST, OPTIONS, DELETE)
|
||||||
|
|
@ -74,12 +53,14 @@ Headers
|
||||||
|
|
||||||
The request above also included a ``Cache-control: no-cache`` header. You can read this header a number of ways. The simplest way is with the ``getHeaderLine($name)`` method.
|
The request above also included a ``Cache-control: no-cache`` header. You can read this header a number of ways. The simplest way is with the ``getHeaderLine($name)`` method.
|
||||||
|
|
||||||
Call ``getHeaderLine($name)`` and pass the case-insensitive name of a header. The method will return the value for the header, or an empty string.
|
Call ``getHeaderLine($name)`` and pass the case-insensitive name of a header. The method will return the value for the header, or an empty string if the header is not present.
|
||||||
|
|
||||||
.. code-block:: php
|
.. code-block:: php
|
||||||
|
|
||||||
function ($request, $response, $next) {
|
class MyHandler implements RequestHandlerInterface
|
||||||
|
{
|
||||||
|
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||||
|
{
|
||||||
// This message contains a "Cache-control: no-cache" header.
|
// This message contains a "Cache-control: no-cache" header.
|
||||||
$cacheControl = $request->getHeaderLine("cache-control");
|
$cacheControl = $request->getHeaderLine("cache-control");
|
||||||
// "no-cache"
|
// "no-cache"
|
||||||
|
|
@ -87,7 +68,7 @@ Call ``getHeaderLine($name)`` and pass the case-insensitive name of a header. Th
|
||||||
// This message does not contain any authorization headers.
|
// This message does not contain any authorization headers.
|
||||||
$authorization = $request->getHeaderLine("authorization");
|
$authorization = $request->getHeaderLine("authorization");
|
||||||
// ""
|
// ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
@ -125,8 +106,10 @@ We can read the parsed body like this:
|
||||||
|
|
||||||
.. code-block:: php
|
.. code-block:: php
|
||||||
|
|
||||||
function ($request, $response, $next) {
|
class MyHandler implements RequestHandlerInterface
|
||||||
|
{
|
||||||
|
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||||
|
{
|
||||||
$cat = $request->getParsedBody();
|
$cat = $request->getParsedBody();
|
||||||
/*
|
/*
|
||||||
Array
|
Array
|
||||||
|
|
@ -135,7 +118,7 @@ We can read the parsed body like this:
|
||||||
[color] => calico
|
[color] => calico
|
||||||
)
|
)
|
||||||
*/
|
*/
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Body Stream
|
Body Stream
|
||||||
|
|
@ -157,12 +140,18 @@ Using a JSON representation of our cat, we can make a request like this:
|
||||||
"color": "Calico"
|
"color": "Calico"
|
||||||
}
|
}
|
||||||
|
|
||||||
We can read and parse the JSON body, and even provide it **as** the parsedBody for later middleware like this:
|
We can read and parse the JSON body, and even provide it **as** the parsedBody for later middleware or handler like this:
|
||||||
|
|
||||||
.. code-block:: php
|
.. code-block:: php
|
||||||
|
|
||||||
function ($request, $response, $next) {
|
class JsonParser implements MiddlewareInterface
|
||||||
|
{
|
||||||
|
public function process(
|
||||||
|
ServerRequestInterface $request,
|
||||||
|
RequestHandlerInterface $handler
|
||||||
|
): ResponseInterface
|
||||||
|
{
|
||||||
|
// Parse the body.
|
||||||
$cat = json_decode((string) $request->getBody());
|
$cat = json_decode((string) $request->getBody());
|
||||||
/*
|
/*
|
||||||
stdClass Object
|
stdClass Object
|
||||||
|
|
@ -171,32 +160,30 @@ We can read and parse the JSON body, and even provide it **as** the parsedBody f
|
||||||
[color] => calico
|
[color] => calico
|
||||||
)
|
)
|
||||||
*/
|
*/
|
||||||
|
// Add the parsed JSON to the request.
|
||||||
$request = $request->withParsedBody($cat);
|
$request = $request->withParsedBody($cat);
|
||||||
|
// Send the request to the next handler.
|
||||||
|
return $handler->handle($request);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Because the entity body of a request or response can be very large, PSR-7_ represents bodies as streams using the ``Psr\Htt\Message\StreamInterface`` (see PSR-7_ Section 1.3).
|
Because the entity body of a request or response can be very large, PSR-7_ represents bodies as streams using the ``Psr\Htt\Message\StreamInterface`` (see PSR-7_ Section 1.3).
|
||||||
|
|
||||||
The JSON example cast the stream to a string, but we can also do things like copy the stream to a local file:
|
The JSON example casts the stream to a string, but we can also do things like copy the stream to a local file:
|
||||||
|
|
||||||
.. code-block:: php
|
.. code-block:: php
|
||||||
|
|
||||||
function ($request, $response, $next) {
|
|
||||||
|
|
||||||
// Store the body to a temp file.
|
// Store the body to a temp file.
|
||||||
$chunkSize = 2048; // Number of bytes to read at once.
|
$chunkSize = 2048; // Number of bytes to read at once.
|
||||||
$localPath = tempnam(sys_get_temp_dir(), "body");
|
$localPath = tempnam(sys_get_temp_dir(), "body");
|
||||||
$h = fopen($localPath, "wb");
|
$h = fopen($localPath, "wb");
|
||||||
$body = $rqst->getBody();
|
$body = $request->getBody();
|
||||||
while (!$body->eof()) {
|
while (!$body->eof()) {
|
||||||
fwrite($h, $body->read($chunkSize));
|
fwrite($h, $body->read($chunkSize));
|
||||||
}
|
}
|
||||||
fclose($h);
|
fclose($h);
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
^^^^^^^^^^
|
^^^^^^^^^^
|
||||||
|
|
||||||
|
|
@ -237,30 +224,27 @@ For a request to ``/cats/Rufus``:
|
||||||
|
|
||||||
.. code-block:: php
|
.. code-block:: php
|
||||||
|
|
||||||
function ($request, $response, $next) {
|
|
||||||
|
|
||||||
$name = $request->getAttribute("name");
|
$name = $request->getAttribute("name");
|
||||||
// "Rufus"
|
// "Rufus"
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
When calling ``getAttribute``, you can optionally provide a default value as the second argument. The value of this argument will be returned if the request has no attribute with that name.
|
When calling ``getAttribute``, you can optionally provide a default value as the second argument. The value of this argument will be returned if the request has no attribute with that name.
|
||||||
|
|
||||||
.. code-block:: php
|
.. code-block:: php
|
||||||
|
|
||||||
function ($request, $response, $next) {
|
|
||||||
|
|
||||||
// Request has no attribute "dog"
|
// Request has no attribute "dog"
|
||||||
$name = $request->getAttribute("dog", "Bear");
|
$name = $request->getAttribute("dog", "Bear");
|
||||||
// "Bear"
|
// "Bear"
|
||||||
|
|
||||||
}
|
Middleware can also use attributes as a way to provide extra information to subsequent handlers. For example, an authorization middleware could obtain an object representing a user and store is as the "user" attribute which later middleware could read.
|
||||||
|
|
||||||
Middleware can also use attributes as a way to provide extra information to subsequent middleware. For example, an authorization middleware could obtain an object representing a user and store is as the "user" attribute which later middleware could read.
|
|
||||||
|
|
||||||
.. code-block:: php
|
.. code-block:: php
|
||||||
|
|
||||||
$auth = function ($request, $response, $next) {
|
class AuthorizationMiddleware implements MiddlewareInterface
|
||||||
|
{
|
||||||
|
public function process(
|
||||||
|
ServerRequestInterface $request,
|
||||||
|
RequestHandlerInterface $handler
|
||||||
|
): ResponseInterface
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$user = readUserFromCredentials($request);
|
$user = readUserFromCredentials($request);
|
||||||
|
|
@ -273,71 +257,31 @@ Middleware can also use attributes as a way to provide extra information to subs
|
||||||
// Store this as an attribute.
|
// Store this as an attribute.
|
||||||
$request = $request->withAttribute("user", $user);
|
$request = $request->withAttribute("user", $user);
|
||||||
|
|
||||||
// Call $next, passing the request with the added attribute.
|
// Call the next handler, passing the request with the added attribute.
|
||||||
return $next($request, $response);
|
// Send the request to the next handler.
|
||||||
|
return $handler->handle($request);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$subsequent = function ($request, $response, $next) {
|
class SecureHandler implements RequestHandlerInterface
|
||||||
|
{
|
||||||
|
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||||
|
{
|
||||||
// Read the "user" attribute added by a previous middleware.
|
// Read the "user" attribute added by a previous middleware.
|
||||||
$user = $request->getAttribute("user");
|
$user = $request->getAttribute("user");
|
||||||
|
|
||||||
// Do something with $user
|
// Do something with $user ...
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$server = new \WellRESTed\Server();
|
$server = new \WellRESTed\Server();
|
||||||
$server->add($auth);
|
$server->add(new AuthorizationMiddleware());
|
||||||
$server->add($subsequent); // Must be added AFTER $auth to get "user"
|
$server->add(new SecureHandler()); // Must be added AFTER authorization to get "user"
|
||||||
$server->respond();
|
$server->respond();
|
||||||
|
|
||||||
Finally, attributes provide a nice way to provide a `dependency injection`_ container for to your middleware.
|
|
||||||
|
|
||||||
Responses
|
Responses
|
||||||
---------
|
---------
|
||||||
|
|
||||||
Initial Response
|
|
||||||
^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
When you call ``WellRESTed\Server::respond``, the server creates a "blank" response instance to pass to dispatched middleware. This response will have a ``500 Internal Server Error`` status, no headers, and an empty body.
|
|
||||||
|
|
||||||
You may wish to start each request-response cycle with a response with a different initial state, for example to include a custom header with all responses or to assume success and only change the status code on a failure (or non-``200`` success). Here are two ways to provide this starting response:
|
|
||||||
|
|
||||||
Provide middleware as the first middleware that set the default conditions.
|
|
||||||
|
|
||||||
.. code-block:: php
|
|
||||||
|
|
||||||
$initialResponsePrep = function ($rqst, $resp, $next) {
|
|
||||||
// Set initial response and forward to subsequent middleware.
|
|
||||||
$resp = $resp
|
|
||||||
->withStatus(200)
|
|
||||||
->withHeader("X-powered-by", "My Super Cool API v1.0.2")
|
|
||||||
return $next($rqst, $resp);
|
|
||||||
};
|
|
||||||
|
|
||||||
$server = new \WellRESTed\Server();
|
|
||||||
$server->add($initialResponsePrep);
|
|
||||||
// ...add other middleware...
|
|
||||||
$server->respond();
|
|
||||||
|
|
||||||
Alternatively, instantiate a response and provide it to ``WellRESTed\Server::respond``.
|
|
||||||
|
|
||||||
.. code-block:: php
|
|
||||||
|
|
||||||
// Create an initial response. This can be any instance implementing
|
|
||||||
// Psr\Http\Message\ResponseInterface.
|
|
||||||
$response = new \WellRESTed\Message\Response(200, [
|
|
||||||
"X-powered-by" => ["My Super Cool API v1.0.2"]]);
|
|
||||||
|
|
||||||
$server = new \WellRESTed\Server();
|
|
||||||
// ...add middleware middleware...
|
|
||||||
// Pass the response to respond()
|
|
||||||
$server->respond(null, $response);
|
|
||||||
|
|
||||||
Modifying
|
|
||||||
^^^^^^^^^
|
|
||||||
|
|
||||||
PSR-7_ messages are immutable, so you will not be able to alter values of response properties. Instead, ``with*`` methods provide ways to get a copy of the current message with updated properties. For example, ``ResponseInterface::withStatus`` returns a copy of the original response with the status changed.
|
PSR-7_ messages are immutable, so you will not be able to alter values of response properties. Instead, ``with*`` methods provide ways to get a copy of the current message with updated properties. For example, ``ResponseInterface::withStatus`` returns a copy of the original response with the status changed.
|
||||||
|
|
||||||
.. code-block:: php
|
.. code-block:: php
|
||||||
|
|
@ -360,7 +304,7 @@ Chain multiple ``with`` methods together fluently:
|
||||||
.. code-block:: php
|
.. code-block:: php
|
||||||
|
|
||||||
// Get a new response with updated status, headers, and body.
|
// Get a new response with updated status, headers, and body.
|
||||||
$response = $response
|
$response = (new Response())
|
||||||
->withStatus(200)
|
->withStatus(200)
|
||||||
->withHeader("Content-type", "text/plain")
|
->withHeader("Content-type", "text/plain")
|
||||||
->withBody(new \WellRESTed\Message\Stream("Hello, world!);
|
->withBody(new \WellRESTed\Message\Stream("Hello, world!);
|
||||||
|
|
@ -455,8 +399,6 @@ When you pass a string to the constructor, the Stream instance uses `php://temp`
|
||||||
|
|
||||||
.. code-block:: php
|
.. code-block:: php
|
||||||
|
|
||||||
function ($rqst, $resp, $next) {
|
|
||||||
|
|
||||||
// Pass the beginning of the contents to the constructor as a string.
|
// Pass the beginning of the contents to the constructor as a string.
|
||||||
$body = new \WellRESTed\Message\Stream("Hello ");
|
$body = new \WellRESTed\Message\Stream("Hello ");
|
||||||
|
|
||||||
|
|
@ -464,21 +406,14 @@ When you pass a string to the constructor, the Stream instance uses `php://temp`
|
||||||
$body->write("world!");
|
$body->write("world!");
|
||||||
|
|
||||||
// Set the body and status code.
|
// Set the body and status code.
|
||||||
$resp = $resp
|
$response = (new Response())
|
||||||
->withStatus(200)
|
->withStatus(200)
|
||||||
->withBody($body);
|
->withBody($body);
|
||||||
|
|
||||||
// Forward to the next middleware.
|
|
||||||
return $next($rqst, $resp);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
To respond with the contents of an existing file, use ``fopen`` to open the file with read access and pass the pointer to the constructor.
|
To respond with the contents of an existing file, use ``fopen`` to open the file with read access and pass the pointer to the constructor.
|
||||||
|
|
||||||
.. code-block:: php
|
.. code-block:: php
|
||||||
|
|
||||||
function ($rqst, $resp, $next) {
|
|
||||||
|
|
||||||
// Open the file with read access.
|
// Open the file with read access.
|
||||||
$resource = fopen("/home/user/some/file", "rb");
|
$resource = fopen("/home/user/some/file", "rb");
|
||||||
|
|
||||||
|
|
@ -486,15 +421,10 @@ To respond with the contents of an existing file, use ``fopen`` to open the file
|
||||||
$body = new \WellRESTed\Message\Stream($resource);
|
$body = new \WellRESTed\Message\Stream($resource);
|
||||||
|
|
||||||
// Set the body and status code.
|
// Set the body and status code.
|
||||||
$resp = $resp
|
$response = (new Response())
|
||||||
->withStatus(200)
|
->withStatus(200)
|
||||||
->withBody($body);
|
->withBody($body);
|
||||||
|
|
||||||
// Forward to the next middleware.
|
|
||||||
return $next($rqst, $resp);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
NullStream
|
NullStream
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
|
@ -502,18 +432,10 @@ Each PSR-7_ message MUST have a body, so there's no ``withoutBody`` method. You
|
||||||
|
|
||||||
.. code-block:: php
|
.. code-block:: php
|
||||||
|
|
||||||
function ($rqst, $resp, $next) {
|
$response = (new Response())
|
||||||
|
->withStatus(200)
|
||||||
// Set the body and status code.
|
|
||||||
$resp = $resp
|
|
||||||
->withStatus(304)
|
|
||||||
->withBody(new \WellRESTed\Message\NullStream());
|
->withBody(new \WellRESTed\Message\NullStream());
|
||||||
|
|
||||||
// Forward to the next middleware.
|
|
||||||
return $next($rqst, $resp);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.. _HTTP Status Code Registry: http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
|
.. _HTTP Status Code Registry: http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
|
||||||
.. _PSR-7: http://www.php-fig.org/psr/psr-7/
|
.. _PSR-7: http://www.php-fig.org/psr/psr-7/
|
||||||
.. _Getting Started: getting-started.html
|
.. _Getting Started: getting-started.html
|
||||||
|
|
|
||||||
|
|
@ -10,14 +10,14 @@ The recommended method for installing WellRESTed is to use the PHP dependency ma
|
||||||
|
|
||||||
{
|
{
|
||||||
"require": {
|
"require": {
|
||||||
"wellrested/wellrested": "~3.0"
|
"wellrested/wellrested": "~3.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Requirements
|
Requirements
|
||||||
^^^^^^^^^^^^
|
^^^^^^^^^^^^
|
||||||
|
|
||||||
- PHP 5.4.0
|
- PHP 7.0
|
||||||
|
|
||||||
License
|
License
|
||||||
^^^^^^^
|
^^^^^^^
|
||||||
|
|
@ -26,7 +26,7 @@ Licensed using the `MIT license <http://opensource.org/licenses/MIT>`_.
|
||||||
|
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2015 PJ Dietz
|
Copyright (c) 2018 PJ Dietz
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue