Download the PHP package sanchescom/laravel-rest without Composer

On this page you can find all versions of the php package sanchescom/laravel-rest. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package laravel-rest

Laravel Rest

CI Latest Version Downloads PHP Version License

Eloquent-like models and collections for consuming REST APIs.

Define a model, point it at an endpoint, and work with remote resources the way you work with Eloquent: User::get(), User::get($id), User::post([...]), $user->put(), User::delete($id).

No request class per endpoint, no DTO per response — one model per resource, and the query builder writes the URLs. Every feature is verified against 62 real public APIs with 470 scenarios, so the awkward shapes (totals in headers, cursor pagination, errors inside HTTP 200) are documented rather than discovered in production — see Live Verification.

Table of Contents

Requirements

[!NOTE] Laravel 11 reached end of life in 2026 (no more security fixes). The package still supports and tests it, but new projects should target Laravel 12.

Installation

The service provider is registered automatically via package auto-discovery — no manual registration needed.

Quick Start

A model is a class pointed at an endpoint. Everything below runs for real against JSONPlaceholder:

Configuration

Publish the config file:

Configure one or more clients in config/rest.php:

[!NOTE] base_uri must end with a trailing slash, and endpoints must not start with one — that is how Guzzle resolves relative URIs.

Defining Models

Error Handling

Every 4xx/5xx response throws a typed exception; you never get a silent null:

Status Exception
404 Sanchescom\Rest\Exceptions\ModelNotFoundException
422 Sanchescom\Rest\Exceptions\ValidationException (->errors())
500+ Sanchescom\Rest\Exceptions\ServerException
other 4xx Sanchescom\Rest\Exceptions\RequestException

All of them extend Sanchescom\Rest\Exceptions\RestException and expose the request context: $e->uri, $e->status, $e->body.

Pagination

Server-side

paginate() requests one page and builds a LengthAwarePaginator from the response metadata; simplePaginate() returns a Paginator for APIs that do not report a total.

Tell the client where the metadata lives — a preset or explicit dot paths:

A model can override the client with protected array|string|null $pagination. Items are read through $dataKey as usual, and page parameter names follow the client's query conventions (e.g. page[number], page_size).

Iterating all pages

lazy() returns a LazyCollection that requests one page at a time (100 models per request by default) and stops on an empty page or when the pagination metadata reports no more pages — the same rules as simplePaginate(). Nothing is requested until you iterate, and iterating again repeats the requests.

Keep the chunk size at or below the API's maximum page size: without next or has_more configured, a short page ends the iteration. If the API ignores the page parameter and sends the same page again, lazy() throws a RestException instead of looping forever.

In memory

Query Builder

Filter, sort, and paginate without writing query strings by hand.

[!IMPORTANT] Post::where(...)->get() filters on the server — the conditions are compiled into the query string and the API returns only matching records. Post::get()->where(...) filters the already-loaded collection in memory — it fetches everything first. For anything beyond trivial datasets, prefer the builder form.

Other query conventions (JSON:API, Django, custom names) — the preferred way is a one-word preset or a small config array on the client; see Adapting to API Conventions:

For a truly custom query language, implement Sanchescom\Rest\Query\Grammar yourself and register the class per client ('grammar' => MyGrammar::class) or per model (protected ?string $grammar = MyGrammar::class). A grammar class always takes precedence over the 'query' config.

Adapting to API Conventions

Every REST API names its parameters differently. Some call it page_size, others call it page[size]. Some prefix descending sorts with -, others append :desc. The 'query' key in any client config covers all of these without touching the calling code. For truly exotic conventions, implement Sanchescom\Rest\Query\Grammar (or AuthInterface / ClientInterface) — but in the common case a config array is all you need.

1. Renaming Parameters

The names map translates the library's canonical parameter names (limit, offset, page, sort) to whatever the API expects. Dot notation in the value produces a nested array that Guzzle serialises as param[sub]:

2. Sort Styles

Four styles are available. Pick the one that matches your API:

dash (default) — prefix descending fields with -, comma-separate:

suffix — append a separator (default :) followed by the direction:

separate — two distinct parameters for field and direction (only the first orderBy is sent; additional calls are ignored). When sort_names is omitted, defaults are: field param sort, direction param direction:

array — an associative array keyed by field name:

3. Filter Styles

Three filter styles cover the most common conventions. The operator (third argument of where()) is an arbitrary string passed through to the API — use whatever vocabulary your API defines (gte, lte, like, in, …):

plain (default) — bare equality, operator in brackets for everything else:

brackets — JSON:API-style filter[field]:

django — Django REST Framework style with double-underscore lookups:

4. Presets

Two presets are built in. Pass a string to activate one:

5. Field Casing

The casing option normalises every field name that appears in where() and orderBy() calls before it hits the wire. Useful when your PHP code uses camelCase but the API expects snake_case:

6. Dynamic Headers

Model-level headers — always sent for every request from this model:

Per-chain withHeaders() — merges over the model-level headers; chain value wins on key conflicts:

[!NOTE] Under Rest::fake() the inline resolver ignores the options argument passed to client(), so headers are not forwarded to the fake. The fake sees bare requests with no custom headers. Similarly, the standalone ClientResolver ignores the options argument — wire headers directly into the ClientInterface instance you register instead.

7. Configuring the Errors Key

By default, ValidationException::errors() looks for the 'errors' key in the response body. Set errors_key (dot notation supported) to point at a different location:

8. PATCH Updates

By default put() sends a PUT request. Switch to PATCH per client:

9. Request Envelopes

Some APIs require the POST/PUT body to be nested under a key:

[!NOTE] $requestDataKey wraps write bodies (POST/PUT/PATCH). $dataKey unwraps read responses (GET). They are independent — you can set one without the other.

10. Standalone Resolver — Setting Query Config

Outside Laravel you can configure ConfigurableGrammar directly on ClientResolver instead of relying on the config file:

11. Putting It All Together

A realistic client config combining several conventions, plus a model that uses a write envelope:

Caching

laravel-rest can cache GET responses so that repeat reads within a TTL window cost zero HTTP round-trips. Caching is opt-in per model or per chain; write operations always pass through and automatically invalidate the model's cache on success. Both get() and getMany() are cached; write methods always go to the API.

Quick start — Laravel app

Publish the config and enable the cache store you want (any configured Laravel cache store works):

Set 'cache' => false to skip store wiring entirely (no Model::setCacheStore call is made at boot).

Then enable caching on the models you want cached:

Per-chain opt-in and opt-out

Any chain can override the model setting:

Page-flip scenario — zero HTTP on repeat

Because cache keys encode client | model | version | uri | compiled-query, every unique page is cached independently. Flipping back to a page that was already fetched costs nothing:

Write-through invalidation

Successful post, put, and delete calls bump the model's internal cache version, making all previously cached entries for that model stale. The next read transparently refetches from the API.

Cancelled writes (a creating/updating/deleting listener returning false) do not bump the version.

You can also flush explicitly at any time (O(1) version bump — does not iterate cache keys):

[!WARNING] External mutations are invisible. If another service creates, updates, or deletes records via the same API, this package has no way to know. Keep $cacheTtl short enough for your consistency requirements, or call Post::flushCache() when you know a mutation happened externally.

Fail loud — no silent cache misses

If caching is requested (via $cacheTtl or withCache()) but no store has been configured, the builder throws a RestException immediately rather than silently falling back to a live request:

Standalone use (outside Laravel)

Wire the store directly — any PSR-16 CacheInterface works:

psr/simple-cache is a suggested dependency; install it alongside whichever PSR-16 adapter you choose.

Request memoization

Identical GET requests inside one application request can hit the API once. It is off by default:

[!WARNING] Keep it off (or call Rest::flushMemo()) in long-running Artisan commands that poll an API for changes — they are one "request" for their whole run. They also keep every memoized response in memory until they finish.

Testing with fakes

Rest::fake() and caching compose correctly. The fake is the inner client; CachingClient wraps it. Use Rest::assertSentCount() to prove cache hits (only the first call is forwarded to the fake):

Relations

Three relation types, all lazy-loaded and per-instance cached on first access:

Foreign-key name defaults to camelCase class name + Id (postId for Post, userId for User). Pass the key explicitly to override: $this->hasMany(Comment::class, 'post_id').

Eager loading

Load relations for a whole result set at once instead of one request per model when a relation is first read:

with() works with get(), get($id), first(), getMany(), paginate(), simplePaginate() and every page of lazy(). Loaded relations are cached on each model, so reading $post->comments afterwards sends nothing.

By default each relation loads concurrently — one request per parent (comments?postId=1, comments?postId=2, …) or per distinct foreign key (users/7, users/8), sent together. That works with any API.

When an endpoint accepts a membership filter, mark the relation with batch() to load it in one request:

Authentication

Configure an auth block inside a client entry:

Custom drivers receive the full auth config array as the constructor argument and must implement Sanchescom\Rest\Auth\AuthInterface.

An InvalidArgumentException is thrown immediately on boot for unknown drivers or missing required keys, not at request time.

Retry

Add a retry block to a client config:

Connection errors (ConnectException) are always retried regardless of statuses. There is no circuit breaker or jitter — reach out or open a PR if you need either.

Model Events

Six hooks fire around write operations. Returning false from a creating, updating, or deleting listener cancels the operation (post/put return null; delete returns false):

Laravel event dispatcher bridge — if you set a dispatcher on the model, created, updated, and deleted also dispatch Sanchescom\Rest\Events\ModelCreated, Sanchescom\Rest\Events\ModelUpdated, and Sanchescom\Rest\Events\ModelDeleted (each carries the model as a public $model property):

Clear listeners between tests with Post::flushEventListeners().

Testing Your Application

Rest::fake() is the primary testing path. It swaps the entire HTTP layer with a fake that records every request and lets you assert against it.

RecordedRequest exposes method(), uri(), query(), and data().

Patterns in the map use Str::is() matching (wildcards with *). Responses with a 4xx/5xx status code cause the fake to throw the same typed exception as the real client would.

[!IMPORTANT] Rest uses PHPUnit's Assert internally. It is a test-context class — do not call Rest::assertSent* or Rest::recorded() in production code.

Advanced alternative: extend('mock') for full Guzzle handler control:

Usage Outside Laravel

The package works without a booted Laravel app (only paginate() and config publishing need one). Wire the resolver yourself:

Capability Matrix

See docs/capabilities.md for a full breakdown of what is supported, what is not, and how to extend it.

Every feature is also verified against real public APIs with different structures (page / offset / cursor pagination, different envelopes, filter and sort dialects, error formats) — 62 APIs and 470 scenarios, with each feature confirmed on at least three of them. The per-feature matrix and the full list of reproduced limitations live in Live Verification, regenerated with composer live:catalog && composer live:report and run nightly in CI.

Roadmap

See ROADMAP.md for planned features (server-side pagination, eager loading, multipart bodies, OAuth2, and more).

Upgrading

See UPGRADE.md for breaking-change notes between every major/minor version.

Contributing

Please read CONTRIBUTING.md for details on our code of conduct, and the process for submitting pull requests to us.

Versioning

We use SemVer for versioning. For the versions available, see the tags on this repository.

Authors

See also the list of contributors who participated in this project.

License

This project is licensed under the MIT License - see the LICENSE.md file for details.


All versions of laravel-rest with dependencies

PHP Build Version
Package Version
Requires php Version ^8.2
guzzlehttp/guzzle Version ^7.8
illuminate/container Version ^11.0|^12.0
illuminate/pagination Version ^11.0|^12.0
illuminate/support Version ^11.0|^12.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package sanchescom/laravel-rest contains the following files

Loading the files please wait ...