Psr-7

Preview:

Citation preview

PSR-7A SET OF COMMON INTERFACES FOR HTTP

MESSAGESby Marco Perone / @marcoshuttle

HTTP MESSAGES

HTTP MESSAGE STRUCTURE <message line> Header: value Another­Header: value

Message body

BODYstringhandled by server and clients as a streamPHP natively represents it using streams

REQUEST MESSAGE LINE

METHOD REQUEST-TARGET HTTP/VERSION

REQUEST TARGETorigin formabsolute formauthority formasterisk form

URI

SCHEME://AUTHORITY[/PATH][?QUERYSTRING]

AUTHORITY = [USER[:PASS]@]HOST[:PORT]

RESPONSE MESSAGE LINE

HTTP/VERSION STATUS REASON

USE OF HTTP MESSAGES IN PHP

USE CASE 1USE PHP SUPERGLOBALS

Any application before frameworks

USE CASE 2CREATE NEW IMPLEMENTATION FROM

SCRATCHFrameworks define http components

Single purpose libraries (oauth-server-php)Http clients ad Guzzle and Buzz

USE CASE 3REQUIRE A SPECIFIC HTTP CLIENT/SERVER

LIBRARY PROVIDING MESSAGEIMPLEMENTATION

Silex, Stack, Drupal 8 have hard dependencies on Symfony'sHTTP kernel

Any SDK developed with Guzzle has a hard requirement onGuzzle's HTTP message implementations

USE CASE 4CREATE ADAPTERS FOR COMMON HTTP

MESSAGE IMPLEMENTATIONSProjects such as Geocoder create redundant adapters for

common libraries

PROBLEMSSuperglobals are mutable. Libraries can alter state of theapplicationUnit and integration testing difficultProjects not capable of interoperability or cross-pollinationNecessity of building a bridge layer between applicationsAny content emitted before a call to header() will resultin that a call becoming a no-op

THE SCOPE OF PSR-7

GOALSProvide the interfaces needed for describing HTTPmessagesFocus on practical applications and usabilityDefine the interfaces to model all elements of the HTTPmessage and URI specificationsEnsure that the API does not impose arbitrary limits onHTTP messagesProvide useful abstractions both for handling incomingrequests for server-side applications and for sendingoutgoing requests in HTTP clients

NON GOALSDoes not expect all HTTP client libraries or server-sideframeworks to change their interfaces to conform. It isstrictly meant for interoperabilityShould not impose implementation details

USE CASES

CLIENTSUnified message interface to use for making requests

$response = $client­>send($request);

MIDDLEWARESFunction that accepts request and response as parametersand does something with them, including delegating to the

next middleware

function ( ServerRequestInterface $request, ResponseInterface $response, callable $next = null) # do stuff here

FRAMEWORKSThey did HTTP message abstraction since a long time

PSR-7 provides a common set of interfaces

Consider Zend\Stdlib\DispatchableInterface inZend Framework 2

use Zend\Http\RequestInterface;use Zend\Http\ResponseInterface;

interface DispatchableInterface public function dispatch( RequestInterface $request, ResponseInterface $response );

PSR-7 BY EXAMPLES

INTERMEZZO: VALUE OBJECTSMessages and URIs are modeled as value objects

a change to any aspect of the message is essentially a newmessageimmutabilityensure integrity of message stateuse a base instance as prototype

MESSAGESnamespace Psr\Http\Message;

MessageInterfaceResponseInterfaceRequestInterfaceServerRequestInterface

HEADERS

// Returns null if not found:$header = $message­>getHeader('Accept');

// Test for a header:if (! $message­>hasHeader('Accept'))

// If the header has multiple values, fetch them// as an array:$values = $message­>getHeaderLines('X­Foo');

HEADERS

/* Returns the following structure: [ 'Header' => [ 'value1' 'value2' ] ]*/foreach ($message­>getAllHeaders() as $header => $values)

HEADERS

$new = $message­>withHeader('Location', 'http://example.com');

$message = $message­>withHeader('Location', 'http://example.com');

$message = $message­>withAddedHeader('X­Foo', 'bar');

$message = $message­>withoutHeader('X­Foo');

BODIEStreated as streams

StreamableInterface is used

$body = new Stream('php://temp');$body­>write('Here is the content for my message!');

$message = $message­>withBody(new Stream('php://temp'));

RESPONSESstatus codereason phrase

$status = $response­>getStatusCode();$reason = $response­>getReasonPhrase();

$response = $response­>withStatus(418, "I'm a teapot");

REQUESTSmethodrequest target

REQUEST TARGET AND URIThe request interface:

composes a UriInterface instance, which models theURI itselfprovides two methods around request-targets:getRequestTarget() andwithRequestTarget()

URI INTERFACEURI are treated as value objects

// URI parts: $scheme = $uri­>getScheme(); $userInfo = $uri­>getUserInfo(); $host = $uri­>getHost(); $port = $uri­>getPort(); $path = $uri­>getPath(); $query = $uri­>getQuery(); // the query STRING $authority = $uri­>getAuthority(); // [user­info@]host[:port]

$uri = $uri ­>withScheme('http') ­>withHost('example.com') ­>withPath('/foo/bar') ­>withQuery('?baz=bat');

CREATE REQUEST

$request = $request ­>withMethod('OPTION') ­>withUri($uri­>withPath('/api/user')) ­>withRequestTarget('*');

SERVER SIDE REQUESTSPHP's Server API does a number of things for us:

Deserialization of query string arguments ($_GET)Deserialization of urlencoded form data submitted viaPOST ($_POST)Deserialization of cookies ($_COOKIE)Identification and handling of file uploads ($_FILES)Encapsulation of CGI/SAPI parameters ($_SERVER)

SERVER SIDE REQUESTSServerRequestInterface extends the base

RequestInterface and offers features around thesevalues

$query = $request­>getQueryParams();$body = $request­>getParsedBody();$cookies = $request­>getCookieParams();$files = $request­>getFileParams();$server = $request­>getServerParams();

ATTRIBUTES

$request­>getAttribute($name, $default = null);$request­>getAttributes();$request = $request­>withAttribute($name, $value);$request = $request­>withoutAttribute();

REFERENCES

Recommended