What is Saloon SDK Generator?
Saloon SDK Generator is a package and CLI tool that facilitates the creation of an SDK for an API using the OpenAPI Spec or Postman collection, leveraging the Saloon package. It essentially generates request classes for all the endpoints in the specification, aiming to intelligently create readable and usable names for methods, classes, variables, and properties.
Although, it doesn't generate a completely functional SDK that can be immediately used as-is. Some adjustments are necessary, hence the tagline "Simplified SDK Scaffolding". Nonetheless, it significantly cuts down the time spent on the mind-numbing grunt work involved in building out an SDK.
Why Did You Build the Package?
At Crescat, we embarked on a project utilizing Paddle. We considered using Cashier, but it turned out that cashier-paddle was built to work with "Paddle Classic", whereas the features we needed were only available in "Paddle Billing", which is the next version of their API, which did not have a PHP SDK we could use at the time.
The team at Paddle provided us with a Postman Collection JSON file. The Paddle API is not overly extensive, but it's not trivially small either, and our work was likely going to interact with many of its endpoints. This led to the decision to develop a tool for scaffolding it out.
Saloon was chosen for its extensive functionality and seamless Laravel integration, which was crucial as we primarily work with Laravel. I appreciate Saloon's Connector, Request, and Resource structure for its organizational ease and code generation capabilities.
Having used swagger-codegen in the past, I found it cumbersome due to its generation of an overwhelming number of classes, properties-as-arrays, and field validation complexities. In contrast, code crafted with Saloon is more straightforward and understandable.
How Long Did it Take to Build?
Reaching a usable level for our initial purpose with the Paddle Billing API took approximately one week, with an additional week to adapt it for OpenAPI and other intricate APIs such as Tableau, Tripletex, Stripe, etc.
For testing, it was run on a collection of real-world API specs, including both well-known ones like Stripe and Tableau, and less familiar ones, primarily Norwegian accounting systems. The latter was chosen partly due to my experience with them and their unique challenges, such as foreign names, occasional poor documentation, and extensive feature sets.
How does it work?
The SDK Generator works by parsing the API spec file to build up its own internal datastructures that represents the various API endpoints and parameters. Then it runs a code generation step where it generates PHP code for the main Saloon components like Requests
, Resource
and the main Connector
class.
How to use it in practice
Using the SDK generator is fairly straight forward.
First we need to install the package, I prefer to install it globally since it's a CLI tool:
1composer global require crescat-io/saloon-sdk-generator
Then we need an API spec file, this can be either an OpenAPI spec or a Postman collection, the package also allows you to build your own custom parsers so it can technically support any kind of format, but let's stick with OpenAPI for now, and lets try it out on the Checkmango API.
The options and arguments supported by the sdk generator is as follows:
1sdkgenerator generate:sdk API_SPEC_FILE.{json|yaml|yml}2 --type={postman|openapi}3 [--name=SDK_NAME]4 [--output=OUTPUT_PATH]5 [--namespace=Company\\Integration]6 [--force]7 [--dry]8 [--zip]
So we to run it on the Checkmango API, we use the following values:
1## Download the OpenAPI Spec2curl https://developers.checkmango.com/source.json --output checkmango.json3 4## Generate SDK5sdkgenerator generate:sdk checkmango.json --type=openapi --name=Checkmango --output=src --namespace=HelgeSverre\\Checkmango --force
Which is going to dump all of our generated code into the src/
directory.
1Generated Files 2 3Connector: 4- Created: src/Checkmango.php 5 6Base Resource: 7- Created: src/Resource.php 8 9Resources:10- Created: src/Resource/Ingestion.php11- Created: src/Resource/Events.php12- Created: src/Resource/Experiments.php13- Created: src/Resource/Variants.php14- Created: src/Resource/Participants.php15- Created: src/Resource/Users.php16- Created: src/Resource/Teams.php17- Created: src/Resource/Health.php1819Requests:20- Created: src/Requests/Ingestion/IngestData.php21- Created: src/Requests/Events/ListEvents.php22- Created: src/Requests/Events/CreateEvent.php23- Created: src/Requests/Events/GetEvent.php24- Created: src/Requests/Events/UpdateEvent.php25- Created: src/Requests/Events/DeleteEvent.php26- Created: src/Requests/Experiments/ListExperiments.php27- Created: src/Requests/Experiments/CreateExperiment.php28- Created: src/Requests/Experiments/GetExperiment.php29- Created: src/Requests/Experiments/UpdateExperiment.php30- Created: src/Requests/Experiments/DeleteExperiment.php31- Created: src/Requests/Experiments/StartExperiment.php32- Created: src/Requests/Experiments/StopExperiment.php33- Created: src/Requests/Variants/ListVariants.php34- Created: src/Requests/Variants/CreateVariant.php35- Created: src/Requests/Variants/GetVariant.php36- Created: src/Requests/Variants/UpdateVariant.php37- Created: src/Requests/Variants/DeleteVariant.php38- Created: src/Requests/Participants/ListParticipants.php39- Created: src/Requests/Participants/CreateParticipant.php40- Created: src/Requests/Participants/GetParticipant.php41- Created: src/Requests/Participants/UpdateParticipant.php42- Created: src/Requests/Participants/DeleteParticipant.php43- Created: src/Requests/Participants/ListParticipantsExperiments.php44- Created: src/Requests/Participants/GetParticipantsExperiment.php45- Created: src/Requests/Participants/UnenrolFromExperiment.php46- Created: src/Requests/Users/GetAccount.php47- Created: src/Requests/Teams/ListTeams.php48- Created: src/Requests/Teams/GetTeam.php49- Created: src/Requests/Teams/GetTeamConfig.php50- Created: src/Requests/Teams/GetCurrentTeam.php51- Created: src/Requests/Health/Health.php
What I usually do when writing SDKs like this, is to first clone the Spatie Package Skeleton, run the configure command, then move the generated SDK files into the src
directory, and clean it up from there.
The "cleanup" process varies from API to API, so i won't cover it in much detail, but the general process is as follows:
- Clone spatie skeleton repo
- Run configure to replace vendor and package names with the one I picked for the SDK. (ex:
HelgeSverre\Checkmango
) - Download the API spec and put it in the repo
- Generate the code using the same namespace as i used in the skeleton repo. (usually into a
temp
folder or directly into thesrc
folder) - Copy the generated code into the
src
folder - Remove things from the skeleton package I don't need (migrations, views etc)
- Modify the main
Connector
class to use the required Authentication method for the API (https://docs.saloon.dev/the-basics/authentication) - Run code formatting on the entire project.
- Now I can start going through all the request/resource classes to clean up the naming, typehints or whatever else to suit my preferences.
What is Your Experience?
I am Helge Sverre, formerly a lead developer and partner at a web agency and CTO at a VC-backed startup.
Currently, I am the VP of Engineering at Crescat, where we create collaborative software tailored for venues, festivals, and event professionals. In addition to this, I am involved in various projects using Livewire and have delved into AI. I have released a Laravel package, "helgesverre/receipt-scanner", which utilizes OpenAI to extract structured receipt data using OCR.
Additionally, I am developing "Mindwave", similar to "Langchain" for Laravel, but with a greater focus on integrating practical AI features. While it isn’t ready for prime time yet, there are exciting developments in the pipeline.