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

Json Builder Laravel Package

fungio/json-builder

A Laravel/PHP package for assembling JSON programmatically. It provides a fluent, chainable API to build nested arrays and objects cleanly, so you can generate structured JSON for APIs, configs, or dynamic payloads without hand-writing arrays. Keeps complex JSON construction readable and maintainabl...

View on GitHub
Deep Wiki
Context7

Getting Started

composer require fungio/json-builder

The package is a single, tiny value object. Everything you need is in src/JsonBuilder.php and its test suite — read those two files before anything else; the whole library is a few hundred lines and the test file is effectively the documentation. Ignore the README's marketing of "escaping control" until you've seen the tests, because the escaping behaviour is best understood from the assertions.

The mental model is: a builder that holds an ordered key → value map, where each value is either "escape this for me" (passed through json_encode) or "insert this verbatim" (assumed already-valid JSON). Serialization happens once at the end via getJson().

First use case — a controller returning a payload where one field is already serialized JSON (a cached fragment, a json DB column, a sub-resource another code path produced):

use Ivory\JsonBuilder\JsonBuilder;

$builder = new JsonBuilder();
$builder
    ->setValue('id', 42)                       // escaped by the builder
    ->setValue('name', 'Ada "Countess" Lovelace')
    ->setRawValue('meta', $cachedJsonFragment) // inserted as-is
;

return new Response($builder->getJson(), 200, ['Content-Type' => 'application/json']);

Verify the exact setter names against src/ before pasting into a codebase — the surface is setValue / setRawValue-shaped, and the raw variant is the reason to install this package at all.

Implementation Patterns

Wrap it, don't sprinkle it. Instantiate the builder in one presentation-layer class (a JsonPresenter, ApiResource, or a small JsonResponseFactory) so the "raw vs escaped" decision lives in exactly one place:

final class JsonResponseFactory
{
    public function create(array $data): Response
    {
        $builder = new JsonBuilder();

        foreach ($data as $key => $value) {
            if ($value instanceof RawJson) {          // your own marker value object
                $builder->setRawValue($key, (string) $value);
                continue;
            }

            $builder->setValue($key, $value);
        }

        return new Response($builder->getJson(), 200, ['Content-Type' => 'application/json']);
    }
}

The RawJson marker is the single most valuable thing you can add on top of this package — it makes "this string is trusted, pre-serialized JSON" a type rather than a convention, and it stops the setRawValue call sites from multiplying.

Composite builders for nested resources. Build child fragments independently and stitch them at the boundary. This is the pattern the library is genuinely good at, because a plain json_encode($array) cannot embed an already-rendered child without a round-trip through json_decode:

$user = (new JsonBuilder())
    ->setValue('id', $user->getId())
    ->setValue('email', $user->getEmail());

$post = (new JsonBuilder())
    ->setValue('id', $post->getId())
    ->setRawValue('author', $user->getJson())   // no decode/re-encode cycle
    ->setValue('title', $post->getTitle());

Caching pre-serialized fragments. Because getJson() returns a string, a built fragment is a natural cache value. Store the string, fetch it later, and re-embed with setRawValue — you skip json_decode → mutate → json_encode entirely on cache hits. This is the strongest day-to-day argument for the package: it turns JSON assembly into string concatenation with no intermediate PHP array.

Ordered output. PHP arrays preserve insertion order and the builder serializes in insertion order, so field order is deterministic. If a consumer (or a snapshot test) depends on key order, set fields in a fixed sequence at the factory level rather than relying on array iteration order from a DTO.

Testing. Always assert on both sides of the boundary: json_decode($builder->getJson(), true) must be an array (proves the output is valid JSON), and assert the raw string for the cases that matter (proves raw insertion didn't get re-escaped). A test that only decodes will happily pass on output where someone double-encoded a raw fragment.

Integration. In Symfony/Laravel this slots in as a plain service — it has no framework coupling. Register the JsonResponseFactory as a singleton, inject it into controllers, and keep the builder itself as a short-lived per-request object (it is stateful and mutable; do not share it).

Gotchas and Tips

  • Raw means raw. Nothing validates that a setRawValue payload is legal JSON. A null fragment, an empty string, or a PHP array passed to the raw setter will silently produce malformed output that only fails at the consumer. Validate at the boundary: json_decode($fragment) returning non-null is a cheap gate, or wrap raw values in the RawJson marker and only construct it from a getJson() call.
  • Double-encoding is the classic bug. Passing an array (or an object) to the raw setter, or passing an already-encoded JSON string to the escaped setter, both produce double-encoded fields ("{\"a\":1}"). The failure is invisible in your own tests unless you assert on the raw string.
  • Type fidelity. Numbers and booleans survive json_encode as numbers and booleans; raw fragments bypass that. A raw "1" is a string, a raw 1 is a number. If a client does strict type checks, this will bite you.
  • Unicode and slashes. For PHP 5.6-era code the default escaping of / and non-ASCII to \uXXXX applies. If your API contract expects literal UTF-8, check whether the builder lets you pass JSON_UNESCAPED_UNICODE / JSON_UNESCAPED_SLASHES; if it doesn't expose flags, you're stuck with the default and should post-process or reconsider.
  • Invalid UTF-8. json_encode returns false on malformed UTF-8 in some PHP versions and emits null in others. The builder almost certainly does not check for false before concatenating, so a single bad byte turns the whole response into garbage. Validate user-supplied strings before they hit the builder.
  • Empty structures. Decide early whether an empty result should be {} or []. An empty builder serializes as one of the two, and consumers that switch on it will break if you change your mind later. Encode the decision in the factory, not at call sites.
  • Key escaping. Field names go through escaping too. If you generate keys from user input (you shouldn't), verify they're escaped — the tests will show you.
  • Cycles and depth. Raw insertion of a builder fragment that transitively contains itself produces infinite output or a truncated string, not an exception. Keep fragment composition a DAG; don't build a related graph that loops back.
  • Extension point. The cleanest extension is a decorator around your factory, not a subclass of the builder. The builder is mutable and returns itself in some methods; subclassing it makes the fluent chain return the parent type and quietly loses your methods.
  • Maintenance risk. Zero stars, zero dependents, PHP 5.6+ target, and effectively unmaintained. Treat it as vendored glue code you understand, not a dependency you upgrade. Before adopting, compare with the one-liner it replaces: json_encode($array, JSON_UNESCAPED_UNICODE) is sufficient for most payloads — this package only earns its place when you genuinely need to embed pre-serialized fragments without a decode/re-encode cycle.
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.
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
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums