{"id":22021592,"url":"https://github.com/lamansky/api","last_synced_at":"2026-04-19T14:03:45.929Z","repository":{"id":57010853,"uuid":"106265207","full_name":"lamansky/api","owner":"lamansky","description":"Lets you create REST APIs using PHP classes to represent API endpoints.","archived":false,"fork":false,"pushed_at":"2021-06-06T22:16:18.000Z","size":16,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-28T16:45:22.454Z","etag":null,"topics":["api","php","rest-api"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lamansky.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"license.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-10-09T09:44:56.000Z","updated_at":"2021-06-06T22:16:21.000Z","dependencies_parsed_at":"2022-08-21T15:10:18.935Z","dependency_job_id":null,"html_url":"https://github.com/lamansky/api","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lamansky%2Fapi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lamansky%2Fapi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lamansky%2Fapi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lamansky%2Fapi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lamansky","download_url":"https://codeload.github.com/lamansky/api/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245085098,"owners_count":20558332,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","php","rest-api"],"created_at":"2024-11-30T06:13:10.063Z","updated_at":"2026-04-19T14:03:45.888Z","avatar_url":"https://github.com/lamansky.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Lamansky/Api\n\nLets you create REST APIs using PHP classes to represent API endpoints.\n\n## Installation\n\nWith [Composer](http://getcomposer.org) installed on your computer and initialized for your project, run this command in your project’s root directory:\n\n```bash\ncomposer require lamansky/api\n```\n\nRequires PHP 7.4 or above.\n\n## Usage Tutorial\n\n### Introduction\n\nAn 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.\n\n|                      | GET | POST | PUT | DELETE |\n|---------------------:|:---:|:----:|:---:|:------:|\n| `CollectionEndpoint` | ✔   | ✔    |     |        |\n| `ItemEndpoint`       | ✔   |      | ✔   | ✔      |\n| `ReadOnlyEndpoint`   | ✔   |      |     |        ||\n\nEach REST command is implemented as a public method of the endpoint controller:\n\n```php\n\u003c?php\nuse Lamansky\\Api\\ReadOnlyEndpoint;\nuse Lamansky\\Api\\Responder;\n\nclass HelloWorldEndpoint implements ReadOnlyEndpoint {\n    public function getRoutePattern() : string {\n        return '/hello-world/';\n    }\n\n    public function get() : Responder {\n        return new Responder(Responder::OK, 'text/plain', 'Hello world!');\n    }\n}\n```\n\nEach REST method returns a `Responder` object. (The `Responder` class also has several subclasses you can use, such as `JsonResponder`, `FileResponder`, and `DeferredResponder`.)\n\nOnce you have your endpoints ready, add them to an API object:\n\n```php\n\u003c?php\nuse Lamansky\\Api\\Api;\n\n$api = new Api('/api');\n$api-\u003eregisterEndpoint(new HelloWorldEndpoint());\n$api-\u003egetResponder()-\u003esendResponseAndDie();\n```\n\nYou’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:\n\n```\nRewriteEngine on\nRewriteCond %{REQUEST_FILENAME} !-f\nRewriteRule . index.php [L]\n```\n\nYou 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/`.\n\n### URL Variables\n\nSo 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?\n\n```php\n\u003c?php\nuse Lamansky\\Api\\ItemEndpoint;\nuse Lamansky\\Api\\Responder;\n\nclass ExampleItemEndpoint implements ItemEndpoint {\n    public function getRoutePattern() : string {\n        return '/example-item/[i:id]/';\n    }\n\n    public function get(int $id=null) : Responder {\n        return new Responder(Responder::OK, 'text/plain', (string)$id);\n    }\n\n    public function put(int $id=null) : Responder {\n        return new Responder(Responder::NOT_IMPLEMENTED);\n    }\n\n    public function delete(int $id=null) : Responder {\n        return new Responder(Responder::NOT_IMPLEMENTED);\n    }\n}\n```\n\nIn 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.\n\nThe Lamansky/Api library uses [AltoRouter](http://altorouter.com/) to handle route mapping. For more information on the `[i:id]` syntax, please refer to that library’s [route mapping documentation](http://altorouter.com/usage/mapping-routes.html).\n\n### GET/POST Variables\n\nAny variables sent via a JSON POST request, or via a GET query-string variable, are automatically accessible to your methods as variables.\n\n```php\npublic function post(string $title=null, string $content=null, id $category_id=null) : Responder {\n    // Save item and return a Responder\n}\n```\n\nNotice 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.\n\n### JSON Views\n\nIf you are constructing a JSON API, consider using a `JsonView` class to convert your models to JSON:\n\n```php\n\u003c?php\nuse Lamansky\\Api\\CollectionEndpoint;\nuse Lamansky\\Api\\ItemEndpoint;\nuse Lamansky\\Api\\Responder;\nuse Lamansky\\Api\\JsonView;\n\nclass BlogPostJsonView extends JsonView {\n    public function render($blog_post) : array {\n        return ['id' =\u003e $blog_post-\u003eid, 'title' =\u003e $blog_post-\u003etitle, 'content' =\u003e $blog_post-\u003econtent];\n    }\n}\n\nclass BlogPostItemEndpoint implements ItemEndpoint {\n    public function getRoutePattern() : string {\n        return '/post/[i:id]/';\n    }\n\n    public function get(int $id=null) : Responder {\n        // TODO: Use the ID to get the BlogPost object from your database\n        return (new BlogPostJsonView())-\u003esingle($blog_post);\n    }\n\n    public function put(int $id=null) : Responder { return new Responder(Responder::NOT_IMPLEMENTED); }\n    public function delete(int $id=null) : Responder { return new Responder(Responder::NOT_IMPLEMENTED); }\n}\n\nclass BlogPostCollectionEndpoint implements CollectionEndpoint {\n    public function getRoutePattern() : string {\n        return '/post/';\n    }\n\n    public function get() : Responder {\n        // TODO: Get all the BlogPost objects in an array\n        return (new BlogPostJsonView())-\u003emultiple($blog_posts);\n    }\n\n    public function post(int $id=null) : Responder { return new Responder(Responder::NOT_IMPLEMENTED); }\n}\n```\n\n### Complete Example\n\n```php\n\u003c?php\nuse Lamansky\\Api\\Api;\nuse Lamansky\\Api\\ItemEndpoint;\nuse Lamansky\\Api\\Responder;\nuse Lamansky\\Api\\JsonResponder;\nuse Lamansky\\Api\\JsonView;\n\nclass TestItemEndpoint implements ItemEndpoint {\n    public function getRoutePattern() : string {\n        return '/test/[i:id]/';\n    }\n\n    public function get(int $id=null) : Responder {\n        if ($id \u003c 1) return new Responder(Responder::NOT_FOUND);\n        $test = new Test($id);\n        return (new TestJsonView())-\u003esingle($test);\n    }\n\n    public function put(int $id=null) : Responder {\n        return new Responder(Responder::NOT_IMPLEMENTED);\n    }\n\n    public function delete(int $id=null) : Responder {\n        return new Responder(Responder::FORBIDDEN);\n    }\n}\n\nclass Test {\n    public $id;\n\n    public function __construct(int $id) {\n        $this-\u003eid = $id;\n    }\n}\n\nclass TestJsonView extends JsonView {\n    public function render($test) : array {\n        return ['id' =\u003e $test-\u003eid];\n    }\n}\n\n$api = new Api('/api');\n$api-\u003eregisterEndpoint(new TestItemEndpoint());\n$api-\u003egetResponder()-\u003esendResponseAndDie();\n```\n\nA GET request to `http://localhost/api/test/1/` will produce:\n\n```json\n{\n    \"id\": 1\n}\n```\n\n## Version Migration Guide\n\nHere are backward-incompatible changes you need to know about.\n\n### 1.x ⇒ 2.x\n\n* The minimum supported PHP version is now 7.4 (instead of 7.1).\n* The [darsyn/ip](https://github.com/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()-\u003egetIp()` 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`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flamansky%2Fapi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flamansky%2Fapi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flamansky%2Fapi/lists"}