Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

11 Commits

Repository files navigation

Lamansky/Api

Lets you create REST APIs using PHP classes to represent API endpoints.

Installation

With Composer installed on your computer and initialized for your project, run this command in your project’s root directory:

composer require lamansky/api

Requires PHP 7.4 or above.

Usage Tutorial

Introduction

An endpoint is a URL (or URL pattern) that can receive REST commands. Every endpoint in your API will be represented by a PHP class. This PHP class implements an Endpoint interface appropriate to the types of REST commands it can accept.

GETPOSTPUTDELETE
CollectionEndpoint
ItemEndpoint
ReadOnlyEndpoint

Each REST command is implemented as a public method of the endpoint controller:

<?phpuseLamansky\Api\ReadOnlyEndpoint;
useLamansky\Api\Responder;
class HelloWorldEndpoint implements ReadOnlyEndpoint {
publicfunctiongetRoutePattern() : string {
return'/hello-world/';
}
publicfunctionget() : Responder {
returnnewResponder(Responder::OK, 'text/plain', 'Hello world!');
}
}

Each REST method returns a Responder object. (The Responder class also has several subclasses you can use, such as JsonResponder, FileResponder, and DeferredResponder.)

Once you have your endpoints ready, add them to an API object:

<?phpuseLamansky\Api\Api;
$api = newApi('/api');
$api->registerEndpoint(newHelloWorldEndpoint());
$api->getResponder()->sendResponseAndDie();

You’ll also need to make sure that the server is routing all requests to the above file. Assuming this file is named index.php and you’re running Apache, you would create an .htaccess file like this:

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . index.php [L]

You now have a working API! If your site is running on localhost, then the API will output Hello world! when you send a GET command to http://localhost/api/hello-world/.

URL Variables

So far we’ve seen how to create an endpoint with a static URL. But what if we need to manipulate an item with a given ID?

<?phpuseLamansky\Api\ItemEndpoint;
useLamansky\Api\Responder;
class ExampleItemEndpoint implements ItemEndpoint {
publicfunctiongetRoutePattern() : string {
return'/example-item/[i:id]/';
}
publicfunctionget(int$id=null) : Responder {
returnnewResponder(Responder::OK, 'text/plain', (string)$id);
}
publicfunctionput(int$id=null) : Responder {
returnnewResponder(Responder::NOT_IMPLEMENTED);
}
publicfunctiondelete(int$id=null) : Responder {
returnnewResponder(Responder::NOT_IMPLEMENTED);
}
}

In our route pattern string, we’ve added a handler for an integer named id. This is then automatically mapped to the $id variable in our REST-verb methods.

The Lamansky/Api library uses AltoRouter to handle route mapping. For more information on the [i:id] syntax, please refer to that library’s route mapping documentation.

GET/POST Variables

Any variables sent via a JSON POST request, or via a GET query-string variable, are automatically accessible to your methods as variables.

publicfunctionpost(string$title=null, string$content=null, id$category_id=null) : Responder {
// Save item and return a Responder
}

Notice that the $category_id parameter follows the PHP convention of underscored variable names. However, JSON tends to use camel-case keys, and GET variables tend to be lowercase. This is not a problem: the library will look for categoryId or categoryid in POST/GET and automatically map them to the $category_id variable.

JSON Views

If you are constructing a JSON API, consider using a JsonView class to convert your models to JSON:

<?phpuseLamansky\Api\CollectionEndpoint;
useLamansky\Api\ItemEndpoint;
useLamansky\Api\Responder;
useLamansky\Api\JsonView;
class BlogPostJsonView extends JsonView {
publicfunctionrender($blog_post) : array {
return ['id' => $blog_post->id, 'title' => $blog_post->title, 'content' => $blog_post->content];
}
}
class BlogPostItemEndpoint implements ItemEndpoint {
publicfunctiongetRoutePattern() : string {
return'/post/[i:id]/';
}
publicfunctionget(int$id=null) : Responder {
// TODO: Use the ID to get the BlogPost object from your databasereturn (newBlogPostJsonView())->single($blog_post);
}
publicfunctionput(int$id=null) : Responder { returnnewResponder(Responder::NOT_IMPLEMENTED); }
publicfunctiondelete(int$id=null) : Responder { returnnewResponder(Responder::NOT_IMPLEMENTED); }
}
class BlogPostCollectionEndpoint implements CollectionEndpoint {
publicfunctiongetRoutePattern() : string {
return'/post/';
}
publicfunctionget() : Responder {
// TODO: Get all the BlogPost objects in an arrayreturn (newBlogPostJsonView())->multiple($blog_posts);
}
publicfunctionpost(int$id=null) : Responder { returnnewResponder(Responder::NOT_IMPLEMENTED); }
}

Complete Example

<?phpuseLamansky\Api\Api;
useLamansky\Api\ItemEndpoint;
useLamansky\Api\Responder;
useLamansky\Api\JsonResponder;
useLamansky\Api\JsonView;
class TestItemEndpoint implements ItemEndpoint {
publicfunctiongetRoutePattern() : string {
return'/test/[i:id]/';
}
publicfunctionget(int$id=null) : Responder {
if ($id < 1) returnnewResponder(Responder::NOT_FOUND);
$test = newTest($id);
return (newTestJsonView())->single($test);
}
publicfunctionput(int$id=null) : Responder {
returnnewResponder(Responder::NOT_IMPLEMENTED);
}
publicfunctiondelete(int$id=null) : Responder {
returnnewResponder(Responder::FORBIDDEN);
}
}
class Test {
public$id;
publicfunction__construct(int$id) {
$this->id = $id;
}
}
class TestJsonView extends JsonView {
publicfunctionrender($test) : array {
return ['id' => $test->id];
}
}
$api = newApi('/api');
$api->registerEndpoint(newTestItemEndpoint());
$api->getResponder()->sendResponseAndDie();

A GET request to http://localhost/api/test/1/ will produce:

{
"id": 1
}

Version Migration Guide

Here are backward-incompatible changes you need to know about.

1.x ⇒ 2.x

  • The minimum supported PHP version is now 7.4 (instead of 7.1).
  • The darsyn/ip dependency has been updated to version 4.x, which may introduce some backward-incompatible changes for those who relied on the public API of the Darsyn\IP\IP object formerly returned by the Client::instance()->getIp() method. This method now returns a Lamansky\Api\IpAddress object which wraps around the darsyn/ip library and will serve as a buffer against further backward-incompatible changes from that dependency. If you were previously using the Darsyn\IP\Doctrine\IpType Doctrine2 type, consider replacing it with the compatibility wrapper Lamansky\Api\Doctrine\IpAddressType.

About

Lets you create REST APIs using PHP classes to represent API endpoints.

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages