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

Nativephp Fetch Laravel Package

victorycodedev/nativephp-fetch

Fetch-style HTTP client for NativePHP, giving native desktop apps a simple, familiar way to make requests. Lightweight and Laravel-friendly, it aims to streamline pulling remote data into your native windows without leaving the ecosystem you already know.

View on GitHub
Deep Wiki
Context7

Getting Started

NativePHP Fetch is the HTTP client you reach for whenever your native app needs to talk to a remote API — it mirrors Laravel's Http facade closely enough that you already know 90% of it, but it adds native-friendly lifecycle events, offline/caching behaviour, and #[On] component integration.

Minimal steps

  1. Install and publish config:
composer require nativephp/fetch
php artisan vendor:publish --tag=nativephp-fetch-config
  1. Look at three places first:

    • config/nativephp-fetch.php — timeouts, base URL, caching, retry defaults.
    • The Fetch facade (use Native\Fetch\Facades\Fetch; — confirm the exact namespace with php artisan about or the package's composer.json autoload, it differs between the standalone and bundled Mobile installs).
    • The FetchRequestStarted / FetchRequestCompleted / FetchRequestFailed event classes — these are the cheapest observability you'll ever get.
  2. First use case — one request inside a NativeComponent:

use Native\Fetch\Facades\Fetch;
use Native\Fetch\Events\FetchRequestFailed;

Fetch::baseUrl('https://api.myapp.test')
    ->acceptJson()
    ->timeout(10)
    ->get('/profile')
    ->throw();

If you're wiring this into a screen, start with the global event listeners rather than sprinkling try/catch everywhere — a single FetchRequestFailed listener that pushes a toast is usually the whole error UX for a v1.

Implementation Patterns

Macros for your authenticated client. This is the headline feature and it should replace every copy-pasted header block in your codebase. Register macros in a service provider's boot():

use Native\Fetch\Facades\Fetch;

public function boot(): void
{
    Fetch::macro('api', function () {
        return Fetch::baseUrl(config('services.api.url'))
            ->withToken(Cache::get('api_token'))
            ->acceptJson()
            ->timeout(15)
            ->retry(2, 200);
    });
}

Then anywhere: Fetch::api()->get('/orders')->collect(). Because macros return a configured pending request, you can still chain per-call overrides (Fetch::api()->timeout(45)->post(...)).

Base URLs + relative paths. Set baseUrl once (config or macro) and use relative paths everywhere, including query strings — the release explicitly covers query parameters and downloads:

Fetch::baseUrl('https://cdn.myapp.test')->download('/reports/2024-05.pdf', $path);
Fetch::api()->get('/search', ['q' => 'invoice', 'page' => 2]);

Prefer a named macro over a bare Fetch::baseUrl() call at every call site; the relative-path mental model only pays off if the base is consistent.

Two-layer event handling. The v1.1.0 split is genuinely useful — use each layer for what it's good at:

  • Global Laravel listeners (Event::listen / listener classes) for cross-cutting concerns: logging, analytics, a global loading spinner counter, token-refresh-on-401.
  • #[On] in NativeComponents for local UI state: $this->loading = false, $this->error = $e->message.

A global request counter is a nice pattern for a shared progress indicator:

Event::listen(FetchRequestStarted::class, fn () => Inertia::share('fetching', true));
Event::listen(FetchRequestCompleted::class, fn () => Inertia::share('fetching', false));

Status helpers instead of magic numbers. With statusIs() and the expanded helper set, error branches read like English:

$response = Fetch::api()->post('/orders', $payload);

$response->created();              // 201
$response->unprocessableEntity();  // 422 — validation
$response->unauthorized();         // 401 — refresh token
$response->tooManyRequests();      // 429 — back off
$response->statusIs(409);          // no named helper yet, still readable

The 422 branch is the one worth standardising: return it straight to your form component and map $response->json('errors') to field errors.

Testing. Keep using Fetch::fake() — the release is explicitly backward compatible, and macros/base URLs work with fakes. Assert against the same fluent helpers so tests and production share vocabulary:

Fetch::fake(['*' => Fetch::response(['id' => 1], 201)]);

Fetch::api()->post('/orders', $payload)->assertCreated();

Gotchas and Tips

  • Base URL and absolute URLs don't always agree. If you pass a full https://... URL to a pending request that has a baseUrl, you're relying on the client's URL-joining rules. Don't mix — pick relative paths for the macro'd client, and spin up a second macro/client for third-party endpoints. Watch trailing slashes on the base (/api vs /api/) — the classic cause of //users.
  • Macros are registered per process boot. In a normal NativePHP request lifecycle that's fine, but if you register macros inside a closure that runs more than once (queued job workers, long-lived listeners) you'll hit "macro already registered". Guard with if (! Fetch::hasMacro('api')) or keep registration strictly in boot().
  • Don't double-handle errors. If a global FetchRequestFailed listener shows a toast and your component catches the exception and sets $error, the user sees it twice. Pick one owner per concern: component owns the message, global listener owns the log/telemetry.
  • Event payloads are not a response cache. The lifecycle events give you URL/method/status/duration-style metadata. Don't expect the body in FetchRequestCompleted — for response inspection use a ->then()/->tap() on the request or the #[On] handler that actually has the response.
  • Be careful logging full requests in a desktop app. Global listeners make it trivially easy to dump headers into a log file — which now sits on the end user's machine, plaintext, with their bearer token. Redact Authorization before it hits disk.
  • ->throw() vs helpers. Mixing throw() with $response->notFound() checks is contradictory: throw() raises before you ever see the response object. Use throw() at the edges (background sync), helpers in UI-facing paths where you want branching.
  • Timeouts inside macros are sticky. A macro-level timeout(15) silently overrides nothing but will surprise you when a large download times out — override per call for download()/post() with big payloads, and set a longer retry backoff for downloads.
  • Retries + non-idempotent verbs. retry() in a base macro means every POST gets retried. That's a duplicate-order bug waiting to happen. Either keep retry out of the shared macro or make a Fetch::apiSafe() variant for idempotent GETs only.
  • Debugging checklist when a request "does nothing": (1) is baseUrl set before the verb? (2) does the URL resolve as expected — log it in FetchRequestStarted; (3) is a Fetch::fake() still active from a previous test or a stray call; (4) is the failure being swallowed by a global listener that never re-throws.
  • Extension point worth knowing: the lifecycle events are the intended hook for offline-queueing and token refresh. A listener on FetchRequestFailed that checks statusIs(401), refreshes the token, and retries the request is the natural place to centralise auth — much cleaner than wrapping every call site, and it's the pattern most likely to survive future releases.
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.
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels