{"id":24564886,"url":"https://github.com/cairnswm/gapi","last_synced_at":"2025-09-01T16:46:13.122Z","repository":{"id":116068851,"uuid":"165527421","full_name":"cairnswm/gapi","owner":"cairnswm","description":"API for any tables in a mySQL database. Written in PHP. Fully configurable supporting pre and post-modification of data before being sent to mySQL.","archived":false,"fork":false,"pushed_at":"2024-01-20T17:20:29.000Z","size":285,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-17T01:44:34.841Z","etag":null,"topics":["configurable","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":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cairnswm.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","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}},"created_at":"2019-01-13T16:24:16.000Z","updated_at":"2022-04-10T01:53:45.000Z","dependencies_parsed_at":"2024-01-20T18:52:23.633Z","dependency_job_id":null,"html_url":"https://github.com/cairnswm/gapi","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/cairnswm/gapi","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cairnswm%2Fgapi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cairnswm%2Fgapi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cairnswm%2Fgapi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cairnswm%2Fgapi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cairnswm","download_url":"https://codeload.github.com/cairnswm/gapi/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cairnswm%2Fgapi/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273158302,"owners_count":25055859,"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","status":"online","status_checked_at":"2025-09-01T02:00:09.058Z","response_time":120,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["configurable","php","rest-api"],"created_at":"2025-01-23T11:29:49.058Z","updated_at":"2025-09-01T16:46:13.066Z","avatar_url":"https://github.com/cairnswm.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# gapi\n\nGeneric API - PHP\n\n// Based on https://www.leaseweb.com/labs/2015/10/creating-a-simple-rest-api-in-php/\n\n# Concept\n\nMany systems are built with an API backend. Building an API can be a lot of work so this project is built to make it a lot quicker and easier to build a RESTful API against a mySQL database. The project allows the configuration of the api to control which tables and which fields can be accessed through the API.\n\nA RESTful API can also manage business logic. Simple business logic can added through various callbacks (not yet implemented)\n\n# The Idea\n\nWhen I created this PHP project the idea was to create an as simple as possible way of adding a REST API on top of any existing mySQL database. The original concept had the following goals:\n1. Create a standard REST API that can connect to any table in the database (Done)\n2. Make the API Configurable so through configuration the list of tables can be set, and the fields that can be seen, updated, deleted (Done)\n3. Add Call backs for Pre/POST functionality (Allows additional security) (Done)\n4. Auto Document the API with the correct Call (Needs to be redone)\n5. Modify Get to include Paging (Pagination: Done, use offset and limit)\n6. Add a Search option that does standard get with parameters. (Can be Post or Get)\n7. _Modify Get to include Sorting option (TODO)_\n8. Use prepared statements to prevent SQL Injection (Done)\n\n# Demos\n\nCreate Demo database and Demo config (TODO)\nCreate example Javascript files to demo the API (TODO)\n\n# Future\n\nOnce I got the basic library working I identified the following additional functionalities to add:\n1. Allow calls to load child objects as Collections within the JSON (Done)\n1.a. String Selects also support subkeys (Done)\n2. Consider modifying POST to update records as well if id is sent in the path (Done)\n2. Consider modifying DELETE to update bulk delete if a search collection is included (and no ID is sent) (Done)\n3. Records can be Deleted based on a search collection being sent instead of an id (See below for a seach collection format) (Done)\n4. _Bulk insert using a collection of records as part of POST (TODO)_\n5. _Bulk update using search collection (TODO)_\n6. _Manage security using an Auth library and tokens (TODO)_\n7. _Create an array of fields that may be used in a search collection, eg so only indexed fields can be searched (TODO)_\n8. _Modifiy the documentation to be valid swagger format :O (TODO)_\n9. Triggers - before and after (Done)\n\n# Known issues\n\nThe documentation option is not valid anymore due to options being added to manage CORS. Will be moved to new functionality, possibly called if a get is made to an imaginary table called swagger (TODO)\n\n# Installation\n\nCopy the api.php and apicore.php to your server directory. Open the api.php file and set the Database Connection values (server, username, password, schema). Also copy gapi_document.php to enable the auto documentation of your API through the OPTIONS method. If this file is excluded the API will be kept private and an error will be thrown instead of documentation being displayed.\n\n# Usage\n\nModify the Config structure (api.php) with the details of your tables\n\n```PHP\n$config = Array(\n\t\"database\" =\u003e Array(\"server\" =\u003e 'localhost',\n\t\t\t\t\t\"username\" =\u003e 'username',\n\t\t\t\t\t\"password\" =\u003e 'password',\n\t\t\t\t\t\"database\" =\u003e 'schema'),\n    \"messages\" =\u003e Array(\n\t\t\t\t\t\"key\" =\u003e \"id\",  \u003c=== Define the key field for the table in the database\n\t\t\t\t\t\"select\" =\u003e Array(\"chatid\",\"username\",\"message\",\"createddate\"), \u003c=== Limit which fields acan be selected\n\t\t\t\t\t\"update\" =\u003e Array(\"message\"), \u003c=== Limit which fields can be updated\n\t\t\t\t\t\"delete\" =\u003e true,  \u003c=== Allow deletions\n\t\t\t\t\t\"create\" =\u003e Array(\"chatid\",\"username\",\"message\")  \u003c=== Limit which fields can be detailed when new record is created (note id in this case is auto)\n\t\t\t\t),\n    \"user\" =\u003e Array(\n\t\t\t\t\t\"key\" =\u003e \"id\",\n\t\t\t\t\t\"select\" =\u003e Array(\"id\",\"username\",\"fullname\"),\n\t\t\t\t\t\"afterselect\" =\u003e \"functionName\", \u003c=== Creates a trigger that is called after any select passing the results, returns a modified results object \n\t\t\t\t\t\"update\" =\u003e Array(\"fullname\"),\n\t\t\t\t\t\"delete\" =\u003e false, \u003c=== Prevent API from deleting\n\t\t\t\t\t\"create\" =\u003e false  \u003c=== Prevent API from creating records,\n\t\t\t\t\t\"order\" =\u003e \"fullname asc\", \u003c=== Allows setting a default order for GET\n\t\t\t\t\t\"subkeys\" =\u003e Array( \u003c== sub takes eg /company/23/employees [Read Only]\n\t\t\t\t\t\t\"property\" =\u003e Array( \u003c== sub name for url\n\t\t\t\t\t\t\t\"key\" =\u003e \"user_id\", \u003c== key value in child table\n\t\t\t\t\t\t\t\"tablename\" =\u003e \"member\", \u003c== child table name - if not same as name\u003e\n\t\t\t\t\t\t\t\"select\" =\u003e array(\"id\", \"user_id\", \"app_id\", \"role\") \u003c== fields to return in select array\n\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t\t),\n\t\"chats\" =\u003e Array(\n\t\t\t\t\t\"tablename\" =\u003e \"chat\",   \u003c=== Note renaming of table - API converts incoming 'chats' to the correct table name chat\n\t\t\t\t\t\"key\" =\u003e \"id\",\n\t\t\t\t\t\"select\" =\u003e Array(\"id\",\"name\"),\n\t\t\t\t\t\"update\" =\u003e false, \u003c=== Prevent API from updating records\n\t\t\t\t\t\"delete\" =\u003e false,\n\t\t\t\t\t\"create\" =\u003e false\n\t)\n);\n```\n\nNote select can also be set to false to prevent selecting of records (eg a monitoring end point where the systems should only be able to create new records)\n\nUsing the API to interact with the Database\n\n```HTTP\nGET http://\u003cserver\u003e/\u003cproject\u003e/api.php/\u003ctablename\u003e \u003c== Returns all records in table\nGET http://\u003cserver\u003e/\u003cproject\u003e/api.php/\u003ctablename\u003e/count \u003c== Returns count of records in table\nGET http://\u003cserver\u003e/\u003cproject\u003e/api.php/\u003ctablename\u003e/\u003cid\u003e \u003c== Returns single record on ID (note use of Key to define ID field in the config)\nGET http://\u003cserver\u003e/\u003cproject\u003e/api.php/\u003ctablename\u003e?offset=\u003cnumber\u003e\u0026limit=\u003cnumber\u003e \u003c== Returns records in table starting from Offset and returning Limit rows\n\nPOST http://\u003cserver\u003e/\u003cproject\u003e/api.php/\u003ctablename\u003e \u003c== creates new record - note fields to be included in formdata - returns new record key\n\nPUT http://\u003cserver\u003e/\u003cproject\u003e/api.php/\u003ctablename\u003e/\u003cid\u003e \u003c== creates new record - note fields to be included in formdata - note the call must use x-www-form-urlencoded\n\nDELETE http://\u003cserver\u003e/\u003cproject\u003e/api.php/\u003ctablename\u003e/\u003cid\u003e \u003c== Deletes record based on id\nDELETE http://\u003cserver\u003e/\u003cproject\u003e/api.php/\u003ctablename\u003e/ \u003c== Deletes record based on where collection\n```\n\n# Triggers\n\nafterselect \u003c== called after GET and search has retrieieved data, passes the result set and expects modified result set returned\nbeforeinsert, afterinsert\nbeforeupdate, afterupdate\nbeforedelete, afterdelete\n\nbefore* \u003c== called before action is taken, passes the details recieved by the api (eg Table and query params or post data), expects the same returned\n\tcan be used to do validation checks (eg does the id being referenced exist)\nafter* \u003c= called with details recieved by API and result of statement, no return value expected \n\tcan be used for Cascade events\n\n# Search\n\nSearches are done using Post:\n\n```HTTP\nPOST http://\u003cserver\u003e/\u003cproject\u003e/api.php/\u003ctablename\u003e/search \u003c== execute search - note fields to be included in json body -- All fields added as AND\n```\n\n```json\n{\n\"field\": [\"user_id\", \"description\"],\n\"op\": [\"in\",\"like\"],\n\"value\": [[14,27], \"%test%\"]\n}\n```\n\nSending a DELETE without an id in the path will execute a \"delete .. where ...\" using the same structure as for search\n\n\n## Tenancy\n\nuse beforeSelect option to set multitenancy parameters\n\n```\nfunction beforeSelect($config, $info)\n{\n\tglobal$defaultwhere, $defaultparams, $defaultsss;\n\t// set the default where clause values\n\t// Allows for support Tenancy queries etc\n\t$info[\"where\"] = \"firstname=?\";\n\t$info[\"sss\"] = \"s\";\n\t$info[\"params\"] = [\"William\"];\n\t$info[\"order\"] = \"fullname desc\"; // Allows changing order by\n\t\n\treturn $config;\n}\n```\n\n## Sample Database included\n\nWorld Database:\nhttps://dev.mysql.com/doc/index-other.html\n\n## Suggestions\n\n1. Change the Config to allow more options\n```\n\"person\" =\u003e array(\n\t\"tablename\" =\u003e \"user\",\n\t\"key\" =\u003e \"id\",\n\t\"select\" = array(\n\t\t\"fields\" =\u003e array(\"id\",\"name\"),\n\t\t\"before\" =\u003e \"beforeSelect\",  // Can be used to validate user authorization\n\t\t\"after\" =\u003e \"afterSelect\",\n\t\t\"where\" =\u003e \"tenant_id=?\",\n\t\t\"sss\" =\u003e \"s\",\n\t\t\"params\" =\u003e [$tenant_id]\n\t)\n)\n```\n\n## Trigger functions\n\n- beforeSelect($config, $info)\n- afterSelect($result);\n\n- beforeUpdate($info);\n- afterUpdate($result, $info);\n\n- beforeInsert($info);\n- afterInsert($result, $info);\n\n- beforeDelete($info);\n- afterDelete($result, $info);","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcairnswm%2Fgapi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcairnswm%2Fgapi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcairnswm%2Fgapi/lists"}