{"id":21023509,"url":"https://github.com/jahidulpabelislam/crud-api","last_synced_at":"2026-02-25T00:01:54.006Z","repository":{"id":98575709,"uuid":"236064982","full_name":"jahidulpabelislam/crud-api","owner":"jahidulpabelislam","description":"Simple CRUD API Framework for PHP.","archived":false,"fork":false,"pushed_at":"2026-02-19T22:07:52.000Z","size":105,"stargazers_count":0,"open_issues_count":3,"forks_count":0,"subscribers_count":1,"default_branch":"1.x","last_synced_at":"2026-02-20T02:06:54.148Z","etag":null,"topics":["api","crud","framework","php"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jahidulpabelislam.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2020-01-24T19:02:31.000Z","updated_at":"2026-01-18T14:16:12.000Z","dependencies_parsed_at":null,"dependency_job_id":"38d5eb99-2dc8-4bc3-90a5-fecb0919ecc2","html_url":"https://github.com/jahidulpabelislam/crud-api","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/jahidulpabelislam/crud-api","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jahidulpabelislam%2Fcrud-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jahidulpabelislam%2Fcrud-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jahidulpabelislam%2Fcrud-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jahidulpabelislam%2Fcrud-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jahidulpabelislam","download_url":"https://codeload.github.com/jahidulpabelislam/crud-api/tar.gz/refs/heads/1.x","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jahidulpabelislam%2Fcrud-api/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29806142,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-24T22:43:48.403Z","status":"ssl_error","status_checked_at":"2026-02-24T22:43:18.536Z","response_time":75,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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","crud","framework","php"],"created_at":"2024-11-19T11:18:27.761Z","updated_at":"2026-02-25T00:01:53.998Z","avatar_url":"https://github.com/jahidulpabelislam.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CRUD API Framework\n\n[![CodeFactor](https://www.codefactor.io/repository/github/jahidulpabelislam/crud-api/badge)](https://www.codefactor.io/repository/github/jahidulpabelislam/crud-api)\n[![Latest Stable Version](https://poser.pugx.org/jpi/crud-api/v/stable)](https://packagist.org/packages/jpi/crud-api)\n[![Total Downloads](https://poser.pugx.org/jpi/crud-api/downloads)](https://packagist.org/packages/jpi/crud-api)\n[![Latest Unstable Version](https://poser.pugx.org/jpi/crud-api/v/unstable)](https://packagist.org/packages/jpi/crud-api)\n[![Licence](https://poser.pugx.org/jpi/crud-api/license)](https://packagist.org/packages/jpi/crud-api)\n![GitHub last commit (branch)](https://img.shields.io/github/last-commit/jahidulpabelislam/crud-api/1.x.svg?label=last%20activity)\n\nA lightweight PHP framework for building RESTful CRUD APIs with built-in support for pagination, search, filtering, and authentication.\n\n## Features\n\n- **RESTful CRUD Operations**: Out-of-the-box support for List, Create, Read, Update and Delete operations\n- **Pagination**: Built-in pagination support with configurable page size\n- **Search \u0026 Filtering**: Flexible search and filter functionality for listing endpoints\n- **Sorting**: Sort results by multiple columns in ascending or descending order\n- **Field Selection**: Choose which fields to return in API responses to reduce payload size\n- **Relationship Inclusion**: Eager load related entities to avoid N+1 query problems\n- **Authentication**: Built-in authentication checks for protected endpoints\n- **JSON Responses**: Standardised JSON response format with HATEOAS links\n- **Validation**: Comprehensive data validation with detailed error messages\n- **Extensible**: Easy to extend for custom business logic\n\n## Dependencies\n\n- PHP 8.0+\n- Composer\n- [jpi/utils](https://packagist.org/packages/jpi/utils) v1\n- [jpi/orm](https://packagist.org/packages/jpi/orm) v2\n- [jpi/http](https://github.com/jahidulpabelislam/http) v1\n\n## Installation\n\nUse [Composer](https://getcomposer.org/)\n\n```bash\n$ composer require jpi/crud-api \n```\n\n## Basic Usage\n\n### 1. Create an Entity\n\n**AbstractEntity** is the base entity class that you'll need to extend, it builds on top of **jpi/orm**. See [jpi/orm](https://packagist.org/packages/jpi/orm) for more details on setting up entities.\n\n**Extra Set Up:**\n\n- `getDisplayName(): string`: Used in error messages - uses `$displayName` property if set otherwise returns the class name\n- `getPluralDisplayName(): string`: Used in error messages - simply appends an `s` to the display name (can be overridden for irregular plurals)\n- `getAPIURL()`: Returns the API URL for the entity - basic version implemented assuming the format is `/{pluralName}/{id}` - you can override if needed.\n\n### 2. Create a Controller\n\n**AbstractController** is the base controller class providing standard CRUD endpoints with authentication support. This handles the responses and delegates the business logic to the **CrudService** (see next), therefore should be rare to add much here.\n\n**Standard Actions:**\n\n- `index()`: GET - List all entities (with pagination, search, and filters)\n- `create()`: POST - Create a new entity\n- `read($id)`: GET - Retrieve a specific entity\n- `update($id)`: PUT - Update a specific entity\n- `delete($id)`: DELETE - Delete a specific entity\n\nAll you need to do is extend the abstract controller, specify the entity class \u0026 define any public actions (if any):\n\n```php\nfinal class ProjectsController extends \\JPI\\CRUD\\API\\AbstractController {\n\n    protected string $entityClass = Project::class;\n\n    // Define which actions are publicly accessible (no authentication required)\n    protected array $publicActions = [\"index\", \"read\"];\n}\n```\n\n### 3. Customise CRUD Service (Optional)\n\n**CrudService** is the service layer handling CRUD operations and data validation.\n\n**Key Features:**\n\n- Automatic request data validation\n- Support for required fields\n- Search and filter integration\n- Pagination support\n\nBy default:\n\n- paginated with 10 items per page - you can change using `$perPage` property or disable pagination setting to null\n- no columns are required - you can define using the static `$requiredColumns` property\n\n```php\nfinal class ProjectService extends \\JPI\\CRUD\\API\\CrudService {\n\n    protected bool $paginated = true;\n    protected int $perPage = 20;\n\n    protected static array $requiredColumns = [\"name\"];\n}\n```\n\nThen reference it in your entity's `crudService` property.\n\n### 4. Request Handling\n\nWe use [jpi/http](https://github.com/jahidulpabelislam/http) for the request handling, though we extend **App** \u0026 **Router** to provide built-in 404 and 405 error handlers, and easy CRUD route setup.\n\nSet up the app as per `jpi/http`:\n\n```php\n$request = \\JPI\\HTTP\\Request::fromGlobals();\n$router = new \\JPI\\CRUD\\API\\Router($request);\n$app = new \\JPI\\CRUD\\API\\App($router);\n```\n\nYou can set up CRUD routes manually or use the convenient `addCRUDRoutes()` method:\n\n```php\n// Option 1: Use addCRUDRoutes() helper (recommended)\n// This creates 5 routes:\n//   GET    /projects/      -\u003e ProjectsController::index\n//   POST   /projects/      -\u003e ProjectsController::create\n//   GET    /projects/{id}/ -\u003e ProjectsController::read\n//   PUT    /projects/{id}/ -\u003e ProjectsController::update\n//   DELETE /projects/{id}/ -\u003e ProjectsController::delete\n// Optional third parameter: route name for the read action\n$app-\u003eaddCRUDRoutes(\"/projects/\", ProjectsController::class);\n// Or with a named route: $app-\u003eaddCRUDRoutes(\"/projects/\", ProjectsController::class, \"project\");\n\n// Option 2: Define routes manually\n$app-\u003eaddRoute(\"/projects/\", \"GET\", ProjectsController::class . \"::index\", \"project\");\n$app-\u003eaddRoute(\"/projects/\", \"POST\", ProjectsController::class . \"::create\");\n$app-\u003eaddRoute(\"/projects/{id}/\", \"GET\", ProjectsController::class . \"::read\");\n$app-\u003eaddRoute(\"/projects/{id}/\", \"PUT\", ProjectsController::class . \"::update\");\n$app-\u003eaddRoute(\"/projects/{id}/\", \"DELETE\", ProjectsController::class . \"::delete\");\n```\n\nHandle the request and send the response:\n\n```php\n$response = $app-\u003ehandle();\n$response-\u003esend();\n```\n\nSee [jpi/http](https://github.com/jahidulpabelislam/http) for more details on routing, request and response handling.\n\n## API Response Format\n\n### Single Entity Response\n\n```json\n{\n    \"data\": {\n        \"id\": 1,\n        \"name\": \"Example Project\",\n        \"description\": \"A sample project\",\n        \"created_at\": \"2024-01-15 10:30:00 UTC\"\n    },\n    \"_links\": {\n        \"self\": \"https://api.example.com/projects/1/\"\n    }\n}\n```\n\n### Collection Response (Paginated)\n\n```json\n{\n    \"data\": [\n        {\n            \"id\": 1,\n            \"name\": \"Project One\",\n            \"description\": \"A sample project\",\n            \"created_at\": \"2024-01-15 10:30:00 UTC\",\n            \"_links\": {\n                \"self\": \"https://api.example.com/projects/1/\"\n            }\n        },\n        {\n            \"id\": 2,\n            \"name\": \"Project Two\",\n            \"description\": \"A sample project\",\n            \"created_at\": \"2025-01-15 10:30:00 UTC\",\n            \"_links\": {\n                \"self\": \"https://api.example.com/projects/2/\"\n            }\n        }\n    ],\n    \"_total_count\": 25,\n    \"_total_pages\": 3,\n    \"_links\": {\n        \"self\": \"https://api.example.com/projects/\",\n        \"next_page\": \"https://api.example.com/projects/?page=2\"\n    }\n}\n```\n\n**getAPIResponse** on the Entity generates the API response for the entity.\n**getAPILinks()** on the Entity returns HATEOAS links for the entity for the API response. Returns a `self` link out the box.\n\n### Error Response\n\n```json\n{\n    \"message\": \"The necessary data was not provided and/or invalid.\",\n    \"errors\": {\n        \"name\": \"`name` is required.\",\n        \"created_at\": \"`created_at` must be instance of \\\\DateTime or valid format for creation or null.\"\n    }\n}\n```\n\n## Advanced Features\n\n### Authentication\n\nThe framework checks for an `is_authenticated` request attribute. Integrate with your authentication system by setting this attribute - would recommend a custom middleware.\n\nEndpoints not listed in `$publicActions` will return a 401 response if the attribute is not set.\n\n### Search\n\nAdds search functionality on the list/index endpoint.\n\nEnable search on your entities by implementing `\\JPI\\CRUD\\API\\Entity\\SearchableInterface` and using the `\\JPI\\CRUD\\API\\Entity\\Searchable` trait. Be default all columns are searchable but likely you'd want to define this using the `searchableColumns` property on your Entity.\n\nThen a search query parameter can be used:\n\n```\nGET /projects/?search=web+development\n```\n\n### Filtering\n\nAdds equality-based filtering on the list/index endpoint.\n\nEnable filtering by implementing `\\JPI\\CRUD\\API\\Entity\\FilterableInterface` and using the `\\JPI\\CRUD\\API\\Entity\\Filterable` trait. By default all columns are filterable but likely you'd want to define this using the `filterableColumns` property on your Entity.\n\nThen filters can be added as query parameter(s):\n\n```\nGET /projects/?filters[status]=active\u0026filters[category]=web\n```\n\n### Sorting\n\nAdds sorting functionality on the list/index endpoint.\n\nEnable sorting by implementing `\\JPI\\CRUD\\API\\Entity\\SortableInterface` and using the `\\JPI\\CRUD\\API\\Entity\\Sortable` trait. By default all columns are sortable but likely you'd want to define this using the `sortableColumns` property on your Entity.\n\nThen sorting can be applied using the `sort` query parameter. Use `{column}:{direction}` syntax where direction can be `asc` or `desc`. If no direction is specified, it defaults to ascending order. Multiple sort criteria can be specified by separating them with commas:\n\n```\nGET /projects/?sort=created_at                      # Sort by created_at ascending (default)\nGET /projects/?sort=created_at:asc                  # Sort by created_at ascending (explicit)\nGET /projects/?sort=created_at:desc                 # Sort by created_at descending\nGET /projects/?sort=status:asc,created_at:desc      # Sort by status ASC, then created_at DESC\n```\n\n### Field Selection\n\nYou can choose which fields to include in the API response for list/index and read/single endpoints using the `fields` query parameter. This helps reduce payload size and improve performance by only returning the data you need.\n\nThe `id` field is always included in the response.\n\nUse comma-separated field names:\n\n```\nGET /projects/?fields=name,created_at\n```\n\n```json\n{\n    \"data\": {\n        \"id\": 1,\n        \"name\": \"Example Project\",\n        \"created_at\": \"2024-01-15 10:30:00 UTC\"\n    },\n    \"_links\": {\n        \"self\": \"https://api.example.com/projects/1/\"\n    }\n}\n```\n\n### Including Relationships\n\nYou can include related entities in API responses using the `include` query parameter. This uses eager loading to avoid N+1 query problems and efficiently load all relationships in a single or minimal number of queries.\n\nUse comma-separated relationship names that match the property names defined in your entity's data mapping:\n\n```\nGET /projects/1/?include=author,category\nGET /projects/?include=author,comments\n```\n\n**Example:** If your `Project` entity has an `author` relationship (defined as a `belongs_to` in the ORM), you can include it:\n\n```json\n{\n    \"data\": {\n        \"id\": 1,\n        \"name\": \"Example Project\",\n        \"description\": \"A sample project\",\n        \"author\": {\n            \"id\": 5,\n            \"name\": \"John Doe\",\n            \"_links\": {\n                \"self\": \"https://api.example.com/users/5/\"\n            }\n        },\n        \"created_at\": \"2024-01-15 10:30:00 UTC\"\n    },\n    \"_links\": {\n        \"self\": \"https://api.example.com/projects/1/\"\n    }\n}\n```\n\n## Support\n\nIf you found this library interesting or useful please spread the word about this library: share on your socials, star on GitHub, etc.\n\nIf you find any issues or have any feature requests, you can open a [issue](https://github.com/jahidulpabelislam/crud-api/issues) or email [me @ jahidulpabelislam.com](mailto:me@jahidulpabelislam.com) :smirk:.\n\n## Authors\n\n- [Jahidul Pabel Islam](https://jahidulpabelislam.com/) [\u003cme@jahidulpabelislam.com\u003e](mailto:me@jahidulpabelislam.com)\n\n## Licence\n\nThis module is licensed under the General Public Licence - see the [licence](LICENSE.md) file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjahidulpabelislam%2Fcrud-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjahidulpabelislam%2Fcrud-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjahidulpabelislam%2Fcrud-api/lists"}