Skip to content

Commit

Permalink
feat(Responder): new response type and Responder interface
Browse files Browse the repository at this point in the history
  • Loading branch information
alexsasharegan committed Mar 18, 2018
1 parent 0e4828d commit a1c7292
Show file tree
Hide file tree
Showing 7 changed files with 413 additions and 140 deletions.
14 changes: 0 additions & 14 deletions Http_Autoloader.php

This file was deleted.

228 changes: 120 additions & 108 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,25 @@
# Http

[![Latest Stable Version](https://poser.pugx.org/alexsasharegan/http/v/stable)](https://packagist.org/packages/alexsasharegan/http)
[![Total Downloads](https://poser.pugx.org/alexsasharegan/http/downloads)](https://packagist.org/packages/alexsasharegan/http)
[![Latest Unstable Version](https://poser.pugx.org/alexsasharegan/http/v/unstable)](https://packagist.org/packages/alexsasharegan/http)
[![License](https://poser.pugx.org/alexsasharegan/http/license)](https://packagist.org/packages/alexsasharegan/http)

A lightweight, dependency free library that makes writing file-based RESTful JSON API endpoints easier in PHP.
A lightweight, dependency free library that makes writing file-based RESTful
JSON API endpoints easier in PHP.

## Setup

Clone the repo into your project. Assuming your restful endpoints live in an `/api` directory, I would recommend either making an `/api/vendor` folder or just a plain `/api/libs` folder and cloning this repo inside there.

- In your project, `require_once` the path to the `Http_Autoloader.php`.

```php
<?php

require_once 'path/to/Http_Autoloader.php';

# ...or potentially...

require_once 'project_root/dist/api/vendor/Http_lib/Http_Autoloader.php';
```sh
composer require alexsasharegan/http
```

## Instantiation

```php
<?php

$http = new Http;
$http = new Http();
```

## Properties
Expand All @@ -36,8 +28,8 @@ Properties for class `Http` represented in json:

```json
{
"request": "type: class Http\Request",
"response": "type: class Http\Response",
"request": "type: class HttpRequest",
"response": "type: class HttpResponse",
"get": "type: callable (callback handle)",
"post": "type: callable (callback handle)",
"put": "type: callable (callback handle)",
Expand All @@ -46,7 +38,8 @@ Properties for class `Http` represented in json:
}
```

Some example properties for the class `Http\Request` represented in json (they vary based on the request itself):
Some example properties for the class `Http\Request` represented in json (they
vary based on the request itself):

```json
{
Expand All @@ -60,7 +53,8 @@ Some example properties for the class `Http\Request` represented in json (they v
},
"file": "Http.test.php",
"contentType": "application/json",
"cookies": "PHPSESSID=01kf9mqndmpr8guqe6tk87nka7; _ga=GA1.1.162483231.1471457216",
"cookies":
"PHPSESSID=01kf9mqndmpr8guqe6tk87nka7; _ga=GA1.1.162483231.1471457216",
"host": "localhost",
"port": "80",
"pathInfo": "/1",
Expand All @@ -69,20 +63,26 @@ Some example properties for the class `Http\Request` represented in json (they v
"path": "/php/my_libs_tests/Http.test.php/1",
"query": "stuff=some+stuff"
},
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36"
"userAgent":
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36"
}
```

Properties for `Http\Reponse` are private. This allows the response object to manage the response data and serialize it on send.
Properties for `Http\Response` are private. This allows the response object to
manage the response data and serialize it on send.

## Methods

The `Http` class has a method available for each major HTTP verb _(get, post, put, patch, delete)_. These allow you to attach your callbacks to be run on each appropriate request method. You can pass in the string name of your callback, or write your function inline as a closure. The callback will be called with the instance of `Http`.
The `Http` class has a method available for each major HTTP verb _(get, post,
put, patch, delete)_. These allow you to attach your callbacks to be run on each
appropriate request method. You can pass in the string name of your callback, or
write your function inline as a closure. The callback will be called with the
instance of `Http`.

#### Callback Reference

```php
<?php
<?php

function myPostCallback($http) {
# code ...
Expand All @@ -95,7 +95,7 @@ $http->post('myPostCallback');
#### Inline Closure

```php
<?php
<?php

$http = new Http;
$http->post(
Expand All @@ -121,39 +121,51 @@ $myGlobalVar = [1,2,3];
->exec();
```

To get values off the parsed request body, call `Http\Request::get( string $key )`.
To get values off the parsed request body, call
`Http\Request::get( string $key )`.

When writing your callbacks, you can build up your response with two methods:

- `Http\Response::set( string $key, mixed $value )`
* `Http\Response::set( string $key, mixed $value )`

##### Parameters

##### Parameters
* **key:** the name for the value you wish to set
* **value:** the value you wish to set
* **key:** the name for the value you wish to set
* **value:** the value you wish to set

- `Http\Response::set_array( array $array )`
* `Http\Response::set_array( array $array )`

##### Parameters
* **array:** an associative array of values to set on the response
##### Parameters

The last line in your callback will be a call to `Http::send`. This exits execution completely after sending the response.
* **array:** an associative array of values to set on the response

- `Http::send( [ int $statusCode = 200, string $contentType = "application/json", string $content = '' ] )`
The last line in your callback will be a call to `Http::send`. This exits
execution completely after sending the response.

##### Parameters
* **statusCode:** a valid HTTP status code to return
* **contentType:** a valid MIME Type to set the response header
* **content:** if you set Content-Type to something other than json, you can send your custom data with this parameter. No serialization will be performed on this content.
* **_Note:_** any undefined routes will return a status code `405` with a json formatted error message
```json
{
"error": "No route has been defined for this request method."
}
```
* `Http::send( [ int $statusCode = 200, string $contentType = "application/json", string $content = '' ] )`

##### Parameters

* **statusCode:** a valid HTTP status code to return
* **contentType:** a valid MIME Type to set the response header
* **content:** if you set Content-Type to something other than json, you can
send your custom data with this parameter. No serialization will be
performed on this content.
* **_Note:_** any undefined routes will return a status code `405` with a json
formatted error message

```json
{
"error": "No route has been defined for this request method."
}
```

If you use a `try {} catch(Exception $e) {}` block in your error handling, you can call `Http::handleError( Exception $e )` in your catch block, and it will automatically reply with a `500` code and a json payload containing the error.
If you use a `try {} catch(Exception $e) {}` block in your error handling, you
can call `Http::handleError( Exception $e )` in your catch block, and it will
automatically reply with a `500` code and a json payload containing the error.

Once you have defined all your necessary HTTP method callbacks, you can let your instance of `Http` run the appropriate callback by simply calling:
Once you have defined all your necessary HTTP method callbacks, you can let your
instance of `Http` run the appropriate callback by simply calling:

```php
<?php
Expand Down Expand Up @@ -248,70 +260,70 @@ $current_http_status = Http::status();
$prev_http_status = Http::status(404);
# setting a new status will set the response code and return the old status

Http::status(Response::HTTP_NOT_FOUND);
Http::status(Status::HTTP_NOT_FOUND);
# there are a number of constants available for valid status codes
# while it can be verbose, it can add readability to your code
# here is the fully namespaced list:
Http\Response::HTTP_CONTINUE = 100;
Http\Response::HTTP_SWITCHING_PROTOCOLS = 101;
Http\Response::HTTP_PROCESSING = 102; // RFC2518
Http\Response::HTTP_OK = 200;
Http\Response::HTTP_CREATED = 201;
Http\Response::HTTP_ACCEPTED = 202;
Http\Response::HTTP_NON_AUTHORITATIVE_INFORMATION = 203;
Http\Response::HTTP_NO_CONTENT = 204;
Http\Response::HTTP_RESET_CONTENT = 205;
Http\Response::HTTP_PARTIAL_CONTENT = 206;
Http\Response::HTTP_MULTI_STATUS = 207; // RFC4918
Http\Response::HTTP_ALREADY_REPORTED = 208; // RFC5842
Http\Response::HTTP_IM_USED = 226; // RFC3229
Http\Response::HTTP_MULTIPLE_CHOICES = 300;
Http\Response::HTTP_MOVED_PERMANENTLY = 301;
Http\Response::HTTP_FOUND = 302;
Http\Response::HTTP_SEE_OTHER = 303;
Http\Response::HTTP_NOT_MODIFIED = 304;
Http\Response::HTTP_USE_PROXY = 305;
Http\Response::HTTP_RESERVED = 306;
Http\Response::HTTP_TEMPORARY_REDIRECT = 307;
Http\Response::HTTP_PERMANENTLY_REDIRECT = 308; // RFC7238
Http\Response::HTTP_BAD_REQUEST = 400;
Http\Response::HTTP_UNAUTHORIZED = 401;
Http\Response::HTTP_PAYMENT_REQUIRED = 402;
Http\Response::HTTP_FORBIDDEN = 403;
Http\Response::HTTP_NOT_FOUND = 404;
Http\Response::HTTP_METHOD_NOT_ALLOWED = 405;
Http\Response::HTTP_NOT_ACCEPTABLE = 406;
Http\Response::HTTP_PROXY_AUTHENTICATION_REQUIRED = 407;
Http\Response::HTTP_REQUEST_TIMEOUT = 408;
Http\Response::HTTP_CONFLICT = 409;
Http\Response::HTTP_GONE = 410;
Http\Response::HTTP_LENGTH_REQUIRED = 411;
Http\Response::HTTP_PRECONDITION_FAILED = 412;
Http\Response::HTTP_REQUEST_ENTITY_TOO_LARGE = 413;
Http\Response::HTTP_REQUEST_URI_TOO_LONG = 414;
Http\Response::HTTP_UNSUPPORTED_MEDIA_TYPE = 415;
Http\Response::HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
Http\Response::HTTP_EXPECTATION_FAILED = 417;
Http\Response::HTTP_I_AM_A_TEAPOT = 418; // RFC2324
Http\Response::HTTP_MISDIRECTED_REQUEST = 421; // RFC7540
Http\Response::HTTP_UNPROCESSABLE_ENTITY = 422; // RFC4918
Http\Response::HTTP_LOCKED = 423; // RFC4918
Http\Response::HTTP_FAILED_DEPENDENCY = 424; // RFC4918
Http\Response::HTTP_RESERVED_FOR_WEBDAV_ADVANCED_COLLECTIONS_EXPIRED_PROPOSAL = 425; // RFC2817
Http\Response::HTTP_UPGRADE_REQUIRED = 426; // RFC2817
Http\Response::HTTP_PRECONDITION_REQUIRED = 428; // RFC6585
Http\Response::HTTP_TOO_MANY_REQUESTS = 429; // RFC6585
Http\Response::HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431; // RFC6585
Http\Response::HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451;
Http\Response::HTTP_INTERNAL_SERVER_ERROR = 500;
Http\Response::HTTP_NOT_IMPLEMENTED = 501;
Http\Response::HTTP_BAD_GATEWAY = 502;
Http\Response::HTTP_SERVICE_UNAVAILABLE = 503;
Http\Response::HTTP_GATEWAY_TIMEOUT = 504;
Http\Response::HTTP_VERSION_NOT_SUPPORTED = 505;
Http\Response::HTTP_VARIANT_ALSO_NEGOTIATES_EXPERIMENTAL = 506; // RFC2295
Http\Response::HTTP_INSUFFICIENT_STORAGE = 507; // RFC4918
Http\Response::HTTP_LOOP_DETECTED = 508; // RFC5842
Http\Response::HTTP_NOT_EXTENDED = 510; // RFC2774
Http\Response::HTTP_NETWORK_AUTHENTICATION_REQUIRED = 511;
Http\Status::HTTP_CONTINUE = 100;
Http\Status::HTTP_SWITCHING_PROTOCOLS = 101;
Http\Status::HTTP_PROCESSING = 102; // RFC2518
Http\Status::HTTP_OK = 200;
Http\Status::HTTP_CREATED = 201;
Http\Status::HTTP_ACCEPTED = 202;
Http\Status::HTTP_NON_AUTHORITATIVE_INFORMATION = 203;
Http\Status::HTTP_NO_CONTENT = 204;
Http\Status::HTTP_RESET_CONTENT = 205;
Http\Status::HTTP_PARTIAL_CONTENT = 206;
Http\Status::HTTP_MULTI_STATUS = 207; // RFC4918
Http\Status::HTTP_ALREADY_REPORTED = 208; // RFC5842
Http\Status::HTTP_IM_USED = 226; // RFC3229
Http\Status::HTTP_MULTIPLE_CHOICES = 300;
Http\Status::HTTP_MOVED_PERMANENTLY = 301;
Http\Status::HTTP_FOUND = 302;
Http\Status::HTTP_SEE_OTHER = 303;
Http\Status::HTTP_NOT_MODIFIED = 304;
Http\Status::HTTP_USE_PROXY = 305;
Http\Status::HTTP_RESERVED = 306;
Http\Status::HTTP_TEMPORARY_REDIRECT = 307;
Http\Status::HTTP_PERMANENTLY_REDIRECT = 308; // RFC7238
Http\Status::HTTP_BAD_REQUEST = 400;
Http\Status::HTTP_UNAUTHORIZED = 401;
Http\Status::HTTP_PAYMENT_REQUIRED = 402;
Http\Status::HTTP_FORBIDDEN = 403;
Http\Status::HTTP_NOT_FOUND = 404;
Http\Status::HTTP_METHOD_NOT_ALLOWED = 405;
Http\Status::HTTP_NOT_ACCEPTABLE = 406;
Http\Status::HTTP_PROXY_AUTHENTICATION_REQUIRED = 407;
Http\Status::HTTP_REQUEST_TIMEOUT = 408;
Http\Status::HTTP_CONFLICT = 409;
Http\Status::HTTP_GONE = 410;
Http\Status::HTTP_LENGTH_REQUIRED = 411;
Http\Status::HTTP_PRECONDITION_FAILED = 412;
Http\Status::HTTP_REQUEST_ENTITY_TOO_LARGE = 413;
Http\Status::HTTP_REQUEST_URI_TOO_LONG = 414;
Http\Status::HTTP_UNSUPPORTED_MEDIA_TYPE = 415;
Http\Status::HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
Http\Status::HTTP_EXPECTATION_FAILED = 417;
Http\Status::HTTP_I_AM_A_TEAPOT = 418; // RFC2324
Http\Status::HTTP_MISDIRECTED_REQUEST = 421; // RFC7540
Http\Status::HTTP_UNPROCESSABLE_ENTITY = 422; // RFC4918
Http\Status::HTTP_LOCKED = 423; // RFC4918
Http\Status::HTTP_FAILED_DEPENDENCY = 424; // RFC4918
Http\Status::HTTP_RESERVED_FOR_WEBDAV_ADVANCED_COLLECTIONS_EXPIRED_PROPOSAL = 425; // RFC2817
Http\Status::HTTP_UPGRADE_REQUIRED = 426; // RFC2817
Http\Status::HTTP_PRECONDITION_REQUIRED = 428; // RFC6585
Http\Status::HTTP_TOO_MANY_REQUESTS = 429; // RFC6585
Http\Status::HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431; // RFC6585
Http\Status::HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451;
Http\Status::HTTP_INTERNAL_SERVER_ERROR = 500;
Http\Status::HTTP_NOT_IMPLEMENTED = 501;
Http\Status::HTTP_BAD_GATEWAY = 502;
Http\Status::HTTP_SERVICE_UNAVAILABLE = 503;
Http\Status::HTTP_GATEWAY_TIMEOUT = 504;
Http\Status::HTTP_VERSION_NOT_SUPPORTED = 505;
Http\Status::HTTP_VARIANT_ALSO_NEGOTIATES_EXPERIMENTAL = 506; // RFC2295
Http\Status::HTTP_INSUFFICIENT_STORAGE = 507; // RFC4918
Http\Status::HTTP_LOOP_DETECTED = 508; // RFC5842
Http\Status::HTTP_NOT_EXTENDED = 510; // RFC2774
Http\Status::HTTP_NETWORK_AUTHENTICATION_REQUIRED = 511;
```
39 changes: 39 additions & 0 deletions src/HtmlResponse.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace Http;

class HtmlResponse implements Responder {

protected $body;
protected $status;

/**
* @param string $data
* @param int $status
*/
public function __construct($data = '', $status = Status::HTTP_OK) {
$this->body = $data;
$this->status = (int) $status;
}

/**
* @return int
*/
public function get_status() {
return $this->status;
}

/**
* @return string
*/
public function get_content_type() {
return 'text/html';
}

/**
* @return string
*/
public function get_body() {
return $this->body;
}
}
Loading

0 comments on commit a1c7292

Please sign in to comment.