Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Apiz Laravel Package

nahid/apiz

Nahid Apiz is a Laravel API package that speeds up REST API development with built-in versioning, response formatting, and resourceful controllers, so you can scaffold endpoints fast and keep consistent, clean JSON responses across your app.

Deep Wiki
Context7

Getting Started

Install via Composer:

composer require nahid/apiz

APIZ is a thin, opinionated wrapper around Guzzle, so the fastest path to understanding it is to read Nahid\Apiz\Apiz (the client) and Nahid\Apiz\Resource (the endpoint abstraction) in vendor/nahid/apiz/src. If you're on Laravel, the service provider and Apiz facade are auto-discovered; on standalone PHP, instantiate the client directly.

Publish the config (Laravel):

php artisan vendor:publish --provider="Nahid\Apiz\Providers\ApizServiceProvider" --tag="config"

Set a base_uri in config/apiz.php, then make your first call:

use Nahid\Apiz\Facades\Apiz;

$response = Apiz::get('/users');
$users    = $response->json();          // decoded array
$status   = $response->statusCode();

If you're not using Laravel, skip the facade and use the client object the same way. The first real use case is almost always: "I need a typed, reusable client for a third-party API instead of scattered Http:: / curl calls." Build one Resource class per API surface (users, invoices, webhooks) and inject the client.

Implementation Patterns

One Resource class per domain. Resources inherit from Nahid\Apiz\Resource and expose named methods instead of raw URLs. This is the pattern the package is designed around.

namespace App\Http\Clients\Resources;

use Nahid\Apiz\Resource;

class UsersResource extends Resource
{
    public function all(array $query = [])
    {
        return $this->get('/users', $query);
    }

    public function find(string $id)
    {
        return $this->get("/users/{$id}");
    }

    public function create(array $payload)
    {
        return $this->post('/users', $payload);
    }

    public function update(string $id, array $payload)
    {
        return $this->patch("/users/{$id}", $payload);
    }
}

Register it once on a configured client and inject that client wherever needed:

$apiz = Apiz::make()
    ->withBaseUri(config('services.example.base_url'))
    ->withHeaders(['Accept' => 'application/json'])
    ->withAuth('Bearer', config('services.example.token'));

$users = $apiz->resource(UsersResource::class);
$users->find('42');

Compose per-request metadata fluently. Headers, query, body, and auth all chain:

$response = Apiz::withHeaders(['X-Request-Id' => (string) Str::uuid()])
    ->withQuery(['page' => 2, 'per_page' => 50])
    ->withBody(['name' => 'Jane'])
    ->post('/users');

Keep auth at the client level; pass per-request only the pieces that vary.

Map responses into DTOs at the resource boundary. Don't leak ->json() arrays into controllers. Wrap them:

public function find(string $id): UserData
{
    return UserData::from($this->get("/users/{$id}")->json('data'));
}

public function all(): Collection
{
    return collect($this->get('/users')->json('data'))
        ->map(fn ($row) => UserData::from($row));
}

Use a base Resource subclass to centralize retries, timeouts, logging, and default headers. This is the intended extension point — subclass Resource and point every concrete resource at it:

abstract class BaseResource extends Resource
{
    protected function boot(): void
    {
        $this->withHeaders(['X-Client' => 'my-app'])
             ->withOptions(['timeout' => 10, 'connect_timeout' => 3]);
    }
}

Testing. Swap the Guzzle handler for a MockHandler on the configured client so resource tests never touch the network:

$apiz->withHandler(HandlerStack::create(
    new MockHandler([new Response(200, [], json_encode(['data' => ['id' => 1]]))])
));

$this->assertSame(1, $apiz->resource(UsersResource::class)->find('1')->id);

Gotchas and Tips

  • Base URI slash semantics. Guzzle resolves relative paths against base_uri. /users and users behave differently depending on whether your base URI ends in a slash. Standardize on one convention (absolute paths + base URI ending in /) and write it down.
  • Errors don't always throw. APIZ surfaces the response; it doesn't guarantee exceptions on 4xx/5xx. Either check ->statusCode() explicitly or pass ['http_errors' => true] through withOptions() — but be consistent across resources.
  • Body streams are single-shot. Guzzle stream bodies can only be read once. If you call ->body() and then ->json(), results may be surprising. Cache ->json() once and pass the array around.
  • Token handling. Never commit tokens. Read auth from config('services.*') or env and inject via withAuth(). Avoid constructing a new authenticated client per request if you can share one.
  • Not a Guzzle replacement. For concurrent requests (Pool), streamed downloads, cookies, or custom middleware stacks, reach for Guzzle directly or expose the underlying client. APIZ is for ergonomic typed access, not low-level control.
  • Debugging. Enable Guzzle's debug option or attach a history middleware via withOptions/withHandler while diagnosing timeouts — APIZ's default error surface is intentionally thin.
  • Package maturity. Small community and a Dec 2024 last release. Pin nahid/apiz, guzzlehttp/guzzle, and PHP versions in composer.json, and keep a thin internal wrapper (your BaseResource) around it so you can swap to raw Guzzle or Laravel's HTTP client later without rewriting every call site.
  • Laravel integration quirks. If you fork, rename namespaces, or override the provider/facade, update config/app.php (or bootstrap/providers.php on Laravel 11+). Re-publish config after major upgrades.
  • Logging request IDs. The most useful production habit with APIZ is adding an X-Request-Id header on every call and logging the response status + that ID from your resource layer. It turns "the API is slow" into a traceable event.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons