{"id":41404894,"url":"https://github.com/friendsofcat/laravel-api-model","last_synced_at":"2026-01-23T13:20:56.381Z","repository":{"id":78873080,"uuid":"508057079","full_name":"friendsofcat/laravel-api-model","owner":"friendsofcat","description":"Translating eloquent queries to API requests","archived":false,"fork":false,"pushed_at":"2024-01-09T19:18:08.000Z","size":117,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"main","last_synced_at":"2024-01-09T20:37:12.731Z","etag":null,"topics":["api-driver","api-model","eloquent","laravel","php"],"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/friendsofcat.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2022-06-27T20:46:01.000Z","updated_at":"2023-09-30T08:12:23.000Z","dependencies_parsed_at":"2023-03-17T14:15:33.017Z","dependency_job_id":null,"html_url":"https://github.com/friendsofcat/laravel-api-model","commit_stats":null,"previous_names":[],"tags_count":0,"template":null,"template_full_name":null,"purl":"pkg:github/friendsofcat/laravel-api-model","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/friendsofcat%2Flaravel-api-model","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/friendsofcat%2Flaravel-api-model/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/friendsofcat%2Flaravel-api-model/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/friendsofcat%2Flaravel-api-model/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/friendsofcat","download_url":"https://codeload.github.com/friendsofcat/laravel-api-model/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/friendsofcat%2Flaravel-api-model/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28693322,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-23T11:01:27.039Z","status":"ssl_error","status_checked_at":"2026-01-23T11:00:26.909Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6: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-driver","api-model","eloquent","laravel","php"],"created_at":"2026-01-23T13:20:54.860Z","updated_at":"2026-01-23T13:20:56.366Z","avatar_url":"https://github.com/friendsofcat.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# laravel-api-model\n\nAbility to use Model from third-party Laravel app via API with eloquent support.\n\u003cbr\u003e\nTransfers all model actions to API calls.\n\nGoes hand in hand with [Laravel API model server package.](https://github.com/friendsofcat/laravel-api-model-server)\n\n\n## Usage\n#### Define API database connection\n```PHP\n// config/database.php\n\n'api_connection' =\u003e [\n    'driver' =\u003e 'laravel_api_model',\n    'database' =\u003e 'YOUR_ENDPOINT_URL', // https://example.com/api/model\n    \n    // If your API doesn't require any authentication you can remove 'auth' from your config\n    'auth' =\u003e [\n        'type' =\u003e 'oauth', // package supports 'oauth' and 'passport_client_credentials'\n        'url' =\u003e 'YOUR_AUTH_URL',\n        'client_id' =\u003e '',\n        'client_secret' =\u003e '',\n    ],\n    \n    // Headers you want to append to every request (except auth requests)\n    'headers' =\u003e [\n         // ...\n    ],\n\n    'array_value_separator' =\u003e ',',\n    'max_url_length' =\u003e 2048,  // default: 2048\n],\n```\n\u003cbr\u003e\n\n#### Create API model and set connection\n```PHP\nuse FriendsOfCat\\LaravelApiModel\\Models\\ApiModel\n\nclass User extends ApiModel\n{\n    protected $connection = 'api_connection';\n    \n\n}\n```\nYou can use this model as a regular one. Important thing is to extend `ApiModel` and set api connection.\n\n\n\u003cbr\u003e\n\n#### Note some not fully supported features:\u003cbr\u003e\n- cross database relations (with usage of `whereHas(...)`, eager-loads are supported)\n- JOIN\n- upsert\n- paginator - wip\n\n\u003cbr\u003e\n\n# Supported features\n\n## Retrieving data\nYou can use complex queries (although nested logic is not currently supported by `laravel-api-model-server`) while retrieving, updating or deleting data.\n### Get method\n```PHP\nUser::isActive()\n    -\u003ewhere(function($q){\n      $q-\u003ewhere('id', '\u003e', 1)\n      -\u003eorWhere(function ($q) {\n          $q-\u003ewhereId(0)\n          -\u003eorWhereIn('created_at', [3,4,5]);\n      })\n      -\u003ewhereIn('updated_at', [1,2,3,4,5]);\n})\n-\u003eorWhere(function($q) {\n    $q-\u003ewhere('id', 3)-\u003ewhere(function($q){\n        $q-\u003ewhereDeletedAt(2)\n        -\u003eorWhereNull('type');\n    })\n    -\u003ewhere('updated_at', 'like', '%2012%');\n})\n-\u003ewhere('type', 1)\n-\u003eget()\n```\nTransforms to request (GET):\n```\nhttps:://example.com/api/model/users?filter[0:and:active:e]=1\u0026filter[0:and:id:gt]=1\u0026filter[1:and:id:e]=0\u0026filter[1:or:created_at:in]=3%2C4%2C5\u0026nested=and%2C0%3Aor%2C0%3Aor%2C2%3Aand\u0026filter[0:and:updated_at:in]=1%2C2%2C3%2C4%2C5\u0026filter[2:and:id:e]=3\u0026filter[3:and:deleted_at:e]=2\u0026filter[3:or:type:is_null]=1\u0026filter[0:and:updated_at:like]=%252012%25\u0026filter[0:and:type:e]=1\n```\nExample response data:\n\n```javascript\n[\n  {\n    \"id\": 1,\n    \"type\": 1,\n    \"created_at\": \"2012-10-13T17:55:16\",\n    \"updated_at\": \"2012-10-13T17:55:16\"\n  },\n  {\n    \"id\": 2,\n    \"type\": 1,\n    \"created_at\": \"2012-10-13T18:55:16\",\n    \"updated_at\": \"2012-10-13T18:55:16\"\n  }\n]\n```\nResult is eloquent model collection, same as using traditional, non API, approach.\n\n\u003cbr\u003e\n\n### First / Find method\n```PHP\nUser::where('id', '=', 1)-\u003efirst();\n// OR\nUser::find(1);\n```\nTransforms to request (GET):\n```\nhttps:://example.com/api/model/users?filter[and:id:e]=1\u0026limit=1\n```\nExample response data:\n\n```javascript\n[\n  {\n    \"id\": 1,\n    \"name\": \"Mark\",\n    \"created_at\": \"2012-10-13T17:55:16\",\n    \"updated_at\": \"2012-10-13T17:55:16\"\n  }\n]\n```\nResult is eloquent model, same as using traditional, non API, approach.\n\n\u003cbr\u003e\n\n### Aggregates\n```PHP\nUser::count();\nUser::avg('age');\nUser::min('age');\nUser::max('age');\n// you can use complex queries with any aggregate function\nUser::where('created_at', '\u003e', now()-\u003esubDays(7))-\u003esum('credit');\n```\nTransforms to request (GET):\n```\nhttps:://example.com/api/model/users?filter[and:created_at:gt]=2012-10-13T17:55:16\u0026queryType=sum,credit\n```\nExample response data:\n\n```javascript\n[\n  {\n    \"aggregate\": 1000\n  }\n]\n```\nEloquent expects the result to be in the format showed in an example response.\u003cbr\u003e\nReturn value is the value of `aggregate` key from the response.\n```PHP\n// Example:\n$totalCredit = User::where('created_at', '\u003e', now()-\u003esubDays(7))-\u003esum('credit');\n\n$totalCredit === 1000 // true\n```\n\u003cbr\u003e\n\n### Checking for existence\n```PHP\nUser::where('created_at', '\u003e', now()-\u003esubDays(7))-\u003eexists();\n```\nTransforms to request (GET):\n```\nhttps:://example.com/api/model/users?filter[and:created_at:gt]=2012-10-13T17:55:16\u0026queryType=exists\n```\nExample response data:\n\n```javascript\n[\n  {\n    \"exists\": true\n  }\n]\n```\nEloquent expects the result to be in the format showed in an example response.\u003cbr\u003e\nReturn value is the value of `exists` key from the response.\n```PHP\n// Example:\n$totalCredit = User::where('created_at', '\u003e', now()-\u003esubDays(7))-\u003eexists();\n\n$totalCredit === true // true\n```\n\u003cbr\u003e\n\n## Local / Global Scopes\nYou can use local or global scopes like you normally do.\n\n\u003cbr\u003e\n\n## External scopes (server-defined scope)\nCustom functionality especially useful when server does not wish to expose its underlying logic.\u003cbr\u003e\nIf the server is using `laravel-api-model-server` package, and has allowed API to use requested scope,\nit will be executed on server side.\n```PHP\nUser::externalScope('isActive')-\u003efirst()\n```\nTransforms to request (GET):\n```\nhttps:://example.com/api/model/users?filter[and:isActive:scope]=\u0026limit=1\n```\n\n### External scope with arguments:\n```PHP\nUser::externalScope('isFrom', ['New York', 'Boston'])-\u003efirst()\n```\nTransforms to request (GET):\n```\nhttps:://example.com/api/model/users?filter[and:isFrom:scope]=New+York%2CBoston\u0026limit=1\n```\nExample response data:\n\n```javascript\n[\n  {\n    \"id\": 1,\n    \"name\": \"Mark\",\n    \"created_at\": \"2012-10-13T17:55:16\",\n    \"updated_at\": \"2012-10-13T17:55:16\"\n  }\n]\n```\n\u003cbr\u003e\n\n## Eager loading of external relations\n```PHP\nUser::with([\n  'details',        // relation defined in our local model\n  'undefined',      // relation NOT defined in our local model\n  'external',       // relation defined in our local model but related to model with same API connection \n])-\u003eget()\n\n/*\nEvery relation passed down to with() is inspected prior to query execution.\n\na) If relation is not set on our model, we assume it is external and we pass it with the query to server\n   and it is excluded from default eager loading.\n\nb) If relation is defined AND has same database connection as our API model,\n   we pass it with the query to server and it is excluded from default eager loading.\n\nFrom our above example, 'undefined' and 'external' are passed down to new externalWith() method.\nOriginal with() is modified to hold only 'details' to ensure correct default eager loading.\n*/\n```\nTransforms to request (GET):\n```\nhttps:://example.com/api/model/users?include=undefined,external\n```\nExample response data:\n\n```javascript\n[\n  {\n    \"id\": 1,\n    \"type\": 1,\n    \"undefined\": {\n      \"id\": 1,\n      \"title\": \"test\"\n    },\n    \"external\": [\n      {\n        \"id\": 1,\n        \"title\": \"test\"\n      },\n      {\n        \"id\": 2,\n        \"title\": \"test\"\n      }\n    ],\n    \"created_at\": \"2012-10-13T17:55:16\",\n    \"updated_at\": \"2012-10-13T17:55:16\"\n  },\n  \n  // ...\n]\n```\n\n\nAfter receiving response, default eager loading take place, so query to receive `details` is executed.\u003cbr\u003e\u003cbr\u003e\nAs `undefined` was not defined on our end, but we receive data with key 'undefined' in response, it will be mixed with other attributes and can cause problems while saving (if `UPDATE / CREATE` is allowed in API).\u003cbr\u003e\u003cbr\u003e\nOn the other hand, `external` is defined on our end, and it is relation to another API model. This will be hydrated properly alongside other relations as proper eloquent collection in `related` bucket.\n\n\u003cbr\u003e\n\n## Creating and updating\n### Insert method\n```PHP\nUser::insert([\n    ['name' =\u003e 'Mark'],\n    ['name' =\u003e 'Jason'],\n])\n```\nTransforms to request (POST):\n\n```javascript\n// https:://example.com/api/model/users\n// --------------------------------------\n// Data:\n\n{\n  \"getId\": false,\n  \"values\": [\n    {\n      \"name\": \"Mark\",\n      \"created_at\": \"2012-10-13T17:55:16\",\n      \"updated_at\": \"2012-10-13T17:55:16\"\n    },\n    {\n      \"name\": \"Jason\",\n      \"created_at\": \"2012-10-13T17:55:16\",\n      \"updated_at\": \"2012-10-13T17:55:16\"\n    }\n  ]\n}\n\n```\nExample response data:\n\n```javascript\n{\n  \"bool\": true\n}\n```\nPossible values of `bool`:\u003cbr\u003e\n`true` =\u003e models were successfully created\u003cbr\u003e\n`false` =\u003e models were not created\u003cbr\u003e\u003cbr\u003e\nThis `Boolean` value is expected by model instance and is returned as a result of insert operation.\n\n```PHP\n// Example:\n$users = User::insert([\n    ['name' =\u003e 'Mark'],\n    ['name' =\u003e 'Jason'],\n]);\n\n$users === true // true\n```\n\u003cbr\u003e\n\n### Create method / using `save()` for creation\n```PHP\n$user = new User();\n$user-\u003ename = 'Mark';\n$user-\u003esave();\n\n// OR\n\n$user = User::create(['name' =\u003e 'Mark']);\n```\nTransforms to request (POST):\n\n```javascript\n// https:://example.com/api/model/users\n// --------------------------------------\n// Data:\n\n{\n  \"getId\": true,\n  \"values\": [\n    {\n      \"name\": \"Mark\",\n      \"created_at\": \"2012-10-13T17:55:16\",\n      \"updated_at\": \"2012-10-13T17:55:16\"\n    }\n  ]\n}\n\n```\nExample response data:\n\n```javascript\n{\n  \"id\": 1\n}\n```\nPossible values of `id`:\u003cbr\u003e\n`mixed` =\u003e primary key value of newly created instance (real column doesn't need to be called 'id')\u003cbr\u003e\n`false` =\u003e model was not created\u003cbr\u003e\n\nThe value of `id` is hydrated to your existing model instance as a value of a primary key.\n```PHP\n// Example:\n$user = new User();\n$user-\u003ename = 'Mark';\n$user-\u003esave();\n// OR\n$user = User::create(['name' =\u003e 'Mark']);\n\n$user-\u003eid === 1 // true\n```\n\u003cbr\u003e\n\n### Update method\n```PHP\nUser::where('created_at', '\u003e', now()-\u003esubDays(7))-\u003eupdate(['name' =\u003e 'Mark']);\n```\nTransforms to request (PUT):\n\n```javascript\n// https:://example.com/api/model/users\n// --------------------------------------\n// Data:\n\n{\n  \"params\": {\n    \"filter\": {\n      \"and:created_at:gt\": \"2012-10-13T17:55:16\"\n    }\n  },\n  \"data\": {\n    \"name\": \"Mark\"\n  }\n}\n\n```\nExample response data:\n\n```javascript\n42\n```\nIt returns an integer that represents the number of updated entries.\n\n```PHP\n// Example:\n$numberOfUpdatedUsers = User::where('created_at', '\u003e', now()-\u003esubDays(7))-\u003eupdate(['name' =\u003e 'Mark']);\n\n$numberOfUpdatedUsers === 42 // true\n```\n\u003cbr\u003e\n\n### Usage of `save()` for update\n```PHP\n// Example:\n$user = User::find(1);\n$user-\u003ename = 'Mark';\n$user-\u003esave();\n```\nTransforms to request (PUT):\n\n```javascript\n// https:://example.com/api/model/users\n// --------------------------------------\n// Data:\n\n{\n  \"params\": {\n    \"filter\": {\n      \"and:id:e\": 1\n    }\n  },\n  \"data\": {\n    \"name\": \"Mark\"\n  }\n}\n\n```\n## Deleting\n```PHP\n$numberOfDeletedUsers = User::where('created_at', '\u003e', now()-\u003esubDays(7))-\u003edelete();\n```\nTransforms to request (DELETE):\n\n```javascript\n// https:://example.com/api/model/users\n// --------------------------------------\n// Data:\n\n{\n  \"filter\": {\n    \"and:created_at:gt\": \"2012-10-13T17:55:16\"\n  }\n}\n\n```\nExample response data:\n\n```javascript\n42\n```\nIt returns an integer that represents the number of deleted entries.\n\n```PHP\n// Example:\n$numberOfDeletedUsers = User::where('created_at', '\u003e', now()-\u003esubDays(7))-\u003edelete();\n\n$numberOfDeletedUsers === 42 // true\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffriendsofcat%2Flaravel-api-model","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffriendsofcat%2Flaravel-api-model","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffriendsofcat%2Flaravel-api-model/lists"}