Integrating Scramble with Cachet - the open source stability platform

Integrating Scramble with Cachet - the open source stability platform

February 27, 2025

On this page
Scramble PRO
Comprehensive API documentation generation for Spatie’s Laravel Data and Laravel Query Builder.

My experience of integrating Scramble into an existing codebase.

Recently, I got a chance to work on integrating Scramble with Cachet.

Cachet is an open-source stability platform. The Cachet API implements the JSON:API standard, uses Spatie’s Query Builder, and relies on Laravel Data for its implementation. This makes Scramble a perfect solution for generating API documentation that is always up-to-date.

Scramble is a modern Laravel OpenAPI (Swagger) documentation generator that doesn’t require you to write PHPDoc annotations: https://scramble.dedoc.co.

When I started working on the Cachet and Scramble integration, a few pieces were missing:

  • Manually documenting parameters not directly referenced in a controller method
  • JSON:API support
  • Grouping and sorting endpoint groups

Deploying the generated specification was also an interesting challenge. Cachet documentation lives in a separate repository, and the OpenAPI specification file is located there as well. So generating the spec via CI was going to be fun!

First steps

My first step was to install Scramble and see the initial results. Usually, API documentation is mostly ready right after installation. After installing the packages, requests and endpoints were correctly detected.

Cachet uses Laravel Data objects for requests and Query Builder for building API queries, so Scramble handled the request documentation perfectly!

Cachet API documentation

However, I noticed that responses were completely missing. Endpoint groups, as the maintainers had planned, were also missing.

The most important part, of course, was the responses. While scanning the codebase manually, it looked like these were just Laravel API responses. In reality, they were JSON:API resources from Tim MacDonald’s package. To make this work for Cachet, I needed to add JSON:API support, which had already been on my Scramble roadmap for a while.

Implementing JSON:API support

JSON:API is awesome: https://jsonapi.org/format/

It defines a solid API foundation and removes the need to make countless decisions about API structure.

Tim MacDonald’s package provides a great Laravel implementation of JSON:API, and combined with Laravel Query Builder, it’s probably the best way to build an API.

To document the Cachet API, I needed to implement support for JSON:API responses: essentially mapping JSON:API resource types to Response objects in the OpenAPI specification. For the first iteration, I focused on supporting attributes and relationships — enough to get Cachet documented.

In the future, I’ll also need to add support for documenting request parameters that are implicitly available when using JSON:API resources, but even now, the responses are communicated clearly:

JSON:API responses

Early JSON:API support is available in Scramble PRO 0.7.x.

Manual parameters documentation and groups

When I started working on Scramble integration with Cachet, there were already comments in the codebase for API documentation. While Scramble can document route parameters using PHPDoc annotations placed near their origin AST node, I realized that introducing PHP attributes would provide a better experience.

Attributes offer a simpler, more explicit way to define type, default, example, description, etc. Attributes also allow adding parameters to the documentation even if there’s no corresponding AST node in the controller method (for example, request parameters related to pagination).

With that in mind, I implemented PHP attributes for defining request parameters:

Manual parameters documentation

Cachet endpoints were also grouped and ordered in a specific way. While Scramble already supported grouping, it lacked sorting functionality. So I introduced the #[Group] attribute, which supports both sorting groups and explicitly grouping endpoints.

Parameter and group attributes are available in Scramble 0.12.x.

Introducing operation transformers API

The next discovery came when I tried to dynamically document Cachet API authentication. All of Cachet’s GET endpoints are public by design, so it made sense to automatically document this, rather than requiring maintainers to manually add @unauthenticated PHPDoc tags to each GET method.

Scramble already had an OperationExtension extension type, which allows modifying (transforming 🧠) any operation’s documentation. In OpenAPI terms, an “operation” represents a single route.

But then I realized — creating an entire class just for 3 lines of logic is terrible DX! It would be much better if you could just pass a closure to Scramble’s config and be done with it.

This sent me down a rabbit hole of rethinking the whole configuration approach! Plus, there were requests on GitHub to allow explicitly controlling the order in which extensions run — so I decided to tackle that too.

First, I renamed “operation extension” to “operation transformer” because it better describes the intent.

Then I looked for inspiration in Laravel itself. Laravel’s middleware configuration felt like a great fit:

use App\Http\Middleware\EnsureTokenIsValid;
->withMiddleware(function (Middleware $middleware) {
$middleware->append(EnsureTokenIsValid::class);
})

This is perfect for the transformers API. It lets you control order, pass closures directly, or provide multiple transformers at once.

use Dedoc\Scramble\Configuration\OperationTransformer;
public function boot()
{
Scramble::configure()
->withOperationTransformers(function (Operation $operation) {
$operation->addParameters([
new Parameter('X-Rate-Limited', 'header'),
]);
});
}

This felt great and simplified Scramble’s configuration for Cachet dramatically (that PR is still WIP).

Scramble also had a way to modify (transform 🧠) the whole OpenAPI document after generation (you can add auth requirement there, etc). But previously, you could only have one such modifier per configuration. So I introduced “document transformers” to allow defining multiple transformers (with ordering!) for the final document too.

use Dedoc\Scramble\Configuration\DocumentTransformers;
public function boot()
{
Scramble::configure()
->withDocumentTransformers(function (DocumentTransformers $transformers) {
$transformers
->prepend(AddAuthInfo::class)
->append(AddOperationAuthInfo::class);
});
}

Transformers API is available in Scramble 0.12.x.

Automating specification generation on CI

This part was both challenging and rewarding!

Cachet documentation lives in a separate repo: https://github.com/cachethq/docs. Meanwhile, the API source code lives here: https://github.com/cachethq/core.

The OpenAPI document is part of the documentation repo, but its generation happens in the cachethq/core repo.

The ideal DX here: every time core changes, the OpenAPI document in the docs repo should update automatically.

Here’s what I implemented:

  • In GitHub Actions, dedoc/scramble-pro gets installed (to provide support for the packages Cachet uses).
  • After that, the OpenAPI spec gets generated using scramble:export.
  • Then, the action clones the docs repo into a subfolder.
  • The spec file is placed in the appropriate folder inside the docs repo (docs-repository/api-reference/openapi.json).
  • Finally, the action commits and pushes changes (if any) to the docs repo.

This could still be improved! Ideally, the action would push to a dedicated branch and open a PR if one doesn’t already exist. That way, maintainers could manually review and accept changes.

You can check the PR with this action here: https://github.com/cachethq/core/pull/178

Conclusion

Integrating Scramble with Cachet was an eye-opening experience. It gave me tons of ideas for Scramble APIs — many of which I implemented and shared in this post.

You can check out the resulting Cachet API reference here: https://docs.cachethq.io/api-reference/introduction

If you need help integrating Scramble with your API, feel free to reach out: roman@dedoc.co!

Let me know if you have any questions!

Scramble PRO
Comprehensive API documentation generation for Spatie’s Laravel Data and Laravel Query Builder.