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

Spaces Api Laravel Package

sociallydev/spaces-api

Laravel integration for DigitalOcean Spaces object storage. Provides a simple, configuration-driven API for uploading, retrieving, and managing files in S3-compatible Spaces buckets, making cloud file storage easy in PHP applications.

Deep Wiki
Context7

Getting Started

  1. Install and configure. composer require sociallydev/spaces-api. Add credentials to config/services.php (or a dedicated config/spaces.php): key, secret, region (nyc3, ams3, sgp1, fra1, …), bucket, and the endpoint (https://{region}.digitaloceanspaces.com). Keep them in .env — never inline them.
  2. Look at the source before the README. The package is small and thin. Read the constructor and the handful of public methods first; that tells you more than the docs about how it encodes keys, whether it sets Content-Type/ACL, and whether it returns URLs or raw responses.
  3. Bind it once. Register a singleton in a service provider so you're not constructing a client per request:
    $this->app->singleton(Spaces::class, fn () => new Spaces(
        config('services.spaces.key'),
        config('services.spaces.secret'),
        config('services.spaces.region'),
    ));
    
  4. First use case: user avatar upload. Take $request->file('avatar'), generate a collision-proof key (avatars/{uuid}.{ext}), upload the file contents, and store the returned public URL on the user record. This exercises the three things you'll do every day — write an object, derive a URL, delete the old one.

Implementation Patterns

  • Wrap it, don't scatter it. Put uploads behind a small StorageService (or a Filesystem-like interface) that takes a key + contents + visibility and returns a URL. When you eventually migrate to the native Flysystem S3 adapter — or to R2/B2 — you change one class, not forty call sites.
  • Two clients for two buckets. Most apps need a public bucket (avatars, marketing assets) and a private one (exports, invoices). Register a named singleton per bucket/visibility rather than passing public-read around ad hoc.
  • Upload from a stream for anything user-sized. For files over a few MB, pass a stream or fopen($path, 'r') instead of file_get_contents(). Loading a 200 MB export into memory is the most common way this package shows up in an OOM trace.
  • Queue the write. Storage::put() in the request cycle is fine for a 50 KB avatar; for anything larger, dispatch a job, store the key immediately, and let the UI poll or sign a temporary URL. Keeps p95 request latency flat.
  • Derive URLs from config, not from the client. Build https://{bucket}.{region}.digitaloceanspaces.com/{key} yourself (and optionally prefix a CDN hostname). This decouples your templates from the package's URL method and lets you flip to the CDN edge without touching the wrapper.
  • Namespace keys deliberately. {type}/{tenant-or-user}/{ulid}.{ext} gives you prefix listing, easy bulk deletes per tenant, and no collisions. Never trust the client-supplied filename.
  • Use prefixes for lifecycle operations. delete per key for one-offs; list-by-prefix + batch delete for "delete this user's data" GDPR flows. Wrap that in a transaction-adjacent service, and log the keys before deleting.
  • Fake it in tests. Bind an in-memory fake implementing your StorageService interface in the test container. Don't hit Spaces from the test suite; if you must, gate it behind a @group integration test with real credentials in CI secrets.

Gotchas and Tips

  • Region/endpoint drift is the #1 first-day error. nyc3 credentials against ams3 endpoints fail with opaque 403s, not a clear "wrong region." Validate region against the endpoint hostname at boot.
  • Content-Type is not inferred for you. If you upload image bytes without it, browsers will download the file instead of rendering it. Set it explicitly from $file->getMimeType() or mime_content_type().
  • ACL semantics differ from S3. Spaces is S3-compatible but not S3-identical — bucket-level public access plus per-object public-read is the reliable combination; don't assume every canned ACL or bucket policy works. Test the actual object URL in an incognito window after every upload.
  • Cache headers matter more than the upload. Spaces serves through a CDN; if you don't set Cache-Control on upload, versioned keys (avatar/{uuid}) are your only cache-busting lever. Prefer immutable, UUID-named keys over overwriting the same key.
  • Package age and maintenance. Last release was Dec 2023. Pin the version, check it against your PHP and Laravel versions, and confirm it isn't silently abandoned. Because it's a thin wrapper over the S3 API, the escape hatch is cheap: league/flysystem-aws-s3-v3 with a custom endpoint gives you the same bucket with multipart uploads, presigned URLs, and Laravel's Storage facade — worth knowing before you build deep.
  • Secrets and config:cache. Read all credentials through config(), never env() at runtime, or you'll break after php artisan config:cache in production.
  • Error handling is on you. The wrapper surfaces HTTP/Guzzle errors; catch them at your service boundary and translate to domain exceptions so a Spaces 503 doesn't become a 500 on your signup form. Add a retry with backoff on uploads.
  • Listing is not free. If the package doesn't paginate, listing a large bucket will burn memory. Check the method signature; prefer prefix-scoped listings and short result sets.
  • Extension points to watch: any method that accepts a raw request/options array is your hook for Content-Disposition, Cache-Control, and x-amz-acl. If the package doesn't expose them, you'll be forking or dropping to the S3 client — decide early which side of that line you're on.
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.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
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
cgv/localized-resource