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

Lunar Api Laravel Package

dystcz/lunar-api

REST API layer for Lunar, the Laravel e-commerce platform. Exposes products, orders, customers, carts, and more through configurable JSON endpoints, with authentication, API resources, and OpenAPI-ready documentation for storefronts and integrations.

View on GitHub
Deep Wiki
Context7

Getting Started

Prerequisites: a working Lunar store (Lunar 1.x on Laravel 10/11) with products, channels, and at least one customer group seeded. This package is only the transport layer — it does not create catalogue data for you.

composer require dystcz/lunar-api
php artisan vendor:publish --tag=lunar-api-config   # tag name may differ; check the package's config/ dir
php artisan route:list --path=api

Auto-discovery registers the service provider. Confirm the route prefix and middleware in the published config/lunar-api.php — that file is your main control surface (prefix, version, middleware stack, auth guard, pagination defaults).

Look at these first, in order:

  1. config/lunar-api.php — routing, auth, pagination, and the JSON:API server name.
  2. vendor/dystcz/lunar-api/src/JsonApi/ — the resource/schema classes. This inventory tells you exactly which Lunar models are exposed (products, variants, collections, carts, cart lines, orders, customers, addresses, media) and which relationships are includeable.
  3. php artisan route:list --path=api -v — the authoritative list of endpoints and their middleware.

First use case — a product listing for a headless storefront:

curl -s 'https://shop.test/api/v1/products?include=variants,media&fields[products]=name,slug,price&page[size]=12' \
  -H 'Accept: application/vnd.api+json'

If you get products back, the stack is wired. If you get 404, the prefix is different; if 406, your Accept header is wrong.

Implementation Patterns

Consume via JSON:API conventions, not REST-by-guess. Every endpoint supports:

  • include=variants,media,prices for relationship sideloading
  • fields[products]=name,slug sparse fieldsets — cut payloads for mobile
  • filter[...] — only filters explicitly declared in the resource's filters() method work
  • sort=-created_at, page[number], page[size]

Checkout is a stateful sequence, not a single POST. The realistic flow:

  1. POST /carts → capture cart id (guest carts are keyed by an id/token — store it client-side).
  2. POST /cart-lines (or a PATCH /carts/{id} with a relationship op) with purchasable_id + quantity.
  3. PATCH /carts/{id} to attach addresses and the chosen shipping option.
  4. Payment intent / payment step using Lunar's payment driver, then the order-placement call.

Treat the cart as the source of truth and re-fetch it after every mutation rather than recomputing totals client-side — Lunar's tax and discount pipeline runs server-side.

Extend, don't fork. Create App\JsonApi\V1\Products\ProductResource extends Dystcz\LunarApi\...\ProductResource, override attributes(), filters(), or relationships(), then point the schema mapping in your config/jsonapi.php server at your class. This is the sanctioned way to add a computed attribute (e.g. in_stock) or a custom filter without touching vendor/.

Auth pattern. Register/login through your own app or the package's customer endpoints, issue a Sanctum token, and send Authorization: Bearer …. Guest→customer cart merge is your responsibility on the client side (or a small custom endpoint) — plan for it in the storefront state machine from day one.

Add non-Lunar endpoints alongside. For app-specific concerns (wishlists, reviews), add a normal Laravel controller + route under the same prefix, or register a JSON:API resource for your own model. Don't overload the Lunar resources with app logic.

Test with HTTP tests, not unit tests — the value here is the serialized contract:

$this->getJson('/api/v1/products?include=variants')
    ->assertOk()
    ->assertJsonPath('data.0.type', 'products');

Use laravel-json-api/testing assertions if available for stricter media-type and structure checks.

Gotchas and Tips

This package is marked READ ONLY — treat it as a frozen dependency. Pin the exact version in composer.json and re-run your API test suite on every Lunar minor upgrade. The API layer will lag behind Lunar model changes; budget for writing your own resource when a new Lunar feature isn't exposed.

Accept: application/vnd.api+json is mandatory. Many HTTP clients default to */* and some proxies rewrite it. If you see 406 intermittently, check the header at the edge, not in your app.

Unlisted filters return 400, not empty results. Developers routinely assume ?filter[sku]=X works out of the box. Open the resource class and add it to filters() — same for sortable().

Sparse fieldsets are lossy in surprising ways. fields[products]=name also suppresses id handling and relationship linkage in some serializers. Always request id explicitly and test your storefront with fieldsets enabled, not just the fat default response.

N+1 hides inside include. JSON:API sideloading is clean but expensive; include=variants,prices,media on a 50-item page will hammer the DB. Cache catalogue responses at the CDN/edge and keep includes minimal on listing endpoints.

Money is in minor units and currency is per-channel. Never format prices on the API side or assume a single currency — Lunar's channel/pricing model is the authority. Return raw integers to the client and format in the presentation layer.

Error handling is JSON:API-shaped. Validation failures arrive as 422 with an errors[] array keyed by source.pointer, not Laravel's flat errors object. Write one client-side error mapper and reuse it everywhere.

Middleware and CORS. Because the frontend is a separate origin, add your CORS and rate-limit middleware to the API group via config rather than editing routes/. Rate-limit cart mutations specifically — they're the abuse surface.

Debugging tips: in local dev, APP_DEBUG=true surfaces the underlying exception inside the JSON:API error object; in production you'll only get an opaque 500. When a 404 appears on a valid-looking URL, run route:list — the package's route names and prefix are versioned and differ from tutorials you'll find online.

Payment integration is the real work. The package exposes the payment endpoints; the gateway driver, webhook handling, and idempotency are yours. Build the "payment failed / cart still valid" path and test it before you test the happy path.

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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle