highsidelabs / saloon-sdk-generator
Simplified SDK Scaffolding for Saloon
Installs: 13 155
Dependents: 2
Suggesters: 0
Security: 0
Stars: 2
Watchers: 0
Forks: 19
Open Issues: 2
Type:project
Requires
- php: ^8.2
- ext-zip: *
- cebe/php-openapi: ^1.7
- laravel-zero/phar-updater: ^1.3
- nette/php-generator: ^4.0
- nunomaduro/termwind: ^2.0.1
- saloonphp/laravel-plugin: ^3.0
- saloonphp/saloon: ^3.0
Requires (Dev)
- laravel-zero/framework: ^11.0.1
- laravel/pint: ^1.8
- mockery/mockery: ^1.5.1
- pestphp/pest: ^2.5
This package is auto-updated.
Last update: 2024-12-04 17:00:25 UTC
README
TODO:
- Move response schemas to the OpenApi responses section, then parse them from there
- Do the same with request schemas?
- Remove OpenApiReference checks from parser?
Saloon SDK Generator - Simplified SDK Scaffolding ๐
Introducing the Saloon SDK Generator โ your tool for quickly creating the basic structure of PHP SDKs using the powerful Saloon package.
Please note: This tool helps you set up the foundation for your SDK, but it might not create a complete, ready-to-use solution. ๐ ๏ธ
Whether you're using Postman Collection JSON files (v2.1) or OpenAPI specifications, the Saloon SDK Generator simplifies the process of generating PHP SDKs. It provides you with a starting point to build the initial framework for your API interactions.
Keep in mind that the generated code might not be perfect for every situation. Think of it as a speedy way to scaffold your SDK structure. While you might need to customize it for specific cases, the Saloon SDK Generator saves you time by eliminating the need to create boilerplate code from scratch.
Your journey to crafting a tailored SDK starts here โ with the Saloon SDK Generator. ๐
Installation
You can install this package using Composer:
composer global require crescat-io/saloon-sdk-generator
Usage
To generate the PHP SDK from an API specification file, run the following command:
sdkgenerator generate:sdk API_SPEC_FILE.{json|yaml|yml} --type={postman|openapi} [--name=SDK_NAME] [--output=OUTPUT_PATH] [--namespace=Company\\Integration] [--force] [--dry] [--zip]
Replace the placeholders with the appropriate values:
API_SPEC_FILE
: Path to the API specification file (JSON or YAML format).--type
: Specify the type of API specification (postman
oropenapi
).--name
: (Optional) Specify the name of the generated SDK (default: Unnamed).--namespace
: (Optional) Specify the root namespace for the SDK (default:App\\Sdk
).--output
: (Optional) Specify the output path where the generated code will be created (default: ./Generated).--force
: (Optional) Force overwriting existing files.--dry
: (Optional) Perform a dry run. It will not save generated files, only show a list of them.--zip
: (Optional) Use this flag to generate a zip archive containing all the generated files.
Note: Due to PHP using Backslashes \
, when specifying the --namespace
, you need to escape any backslashes like
so:
sdkgenerator generate:sdk ./tests/Samples/paddle.json --force --type=postman --name=Paddle --output ./paddle-sdk/src --namespace=Your\\Sdk\\Namespace # <-- Note the "\\"
Using the Code Generator and Parser Programmatically
- Configure Your Generator:
Configure the CodeGenerator
with the desired settings:
$generator = new CodeGenerator( namespace: "App\Sdk", baseFilesNamespace: "App\Sdk\Base", namespaceSuffixes: [ 'resource' => 'Resource', 'request' => 'Request', 'dto' => 'Dto', ], connectorName: 'MySDK', // Replace with your desired SDK name outputFolder: './Generated', // Replace with your desired output folder ignoredParams: [ 'query' => ['after', 'order_by', 'per_page'], 'body' => [], 'header' => [], ], );
- Parse and Generate:
Parse your API specification file and generate the SDK classes:
$inputPath = 'path/to/api_spec_file.json'; // Replace with your API specification file path $type = 'postman'; // Replace with your API specification type $result = $generator->run(Factory::parse($type, $inputPath));
- Use Generated Results:
You can access the generated classes and perform actions with them:
// Generated Connector Class echo "Generated Connector Class: " . Utils::formatNamespaceAndClass($result->connectorClass) . "\n"; // Generated Base Resource Class echo "Generated Base Resource Class: " . Utils::formatNamespaceAndClass($result->resourceBaseClass) . "\n"; // Generated Resource Classes foreach ($result->resourceClasses as $resourceClass) { echo "Generated Resource Class: " . Utils::formatNamespaceAndClass($resourceClass) . "\n"; } // Generated Request Classes foreach ($result->requestClasses as $requestClass) { echo "Generated Request Class: " . Utils::formatNamespaceAndClass($requestClass) . "\n"; }
How It Works
The Saloon SDK Generator automates the creation of PHP SDKs by following these steps:
1. Parsing API Specifications
The parser reads and understands different API specification formats, including Postman Collection JSON (v2.1), OpenAPI specifications, and custom formats. When executed, it:
- Takes an input file.
- Converts the contents into an internal format called
ApiSpecification
. - This format provides a comprehensive view of the API, which the SDK generator uses.
2. Auto-generating SDK Components
This component automatically generates essential SDK components based on parsed specifications:
- Request classes
- Resource classes
- Data Transfer Objects (DTOs)
- Connectors
- Foundational resource class
3. Configurable Generators
The Saloon SDK Generator is modular, allowing you to replace default generators with custom ones to tailor the SDK generation to your needs. The following generators can be customized:
BaseResourceGenerator
BaseRequestGenerator
BaseResponseGenerator
BaseDtoGenerator
ConnectorGenerator
DtoGenerator
RequestGenerator
ResourceGenerator
SupportingFilesGenerator
Core Data Structures
These foundational structures form the basis of the generated SDK output:
1. ApiSpecification
- Represents the entire API specification.
- Contains metadata like name, description, base URL, and endpoints catalog.
2. Config
- Central repository for SDK generator configurations.
- Defines namespaces, component suffixes, and other parameters.
- Customizable for specific requirements.
3. Endpoint
- Describes individual API endpoints.
- Includes method types, path segments, and related parameters.
4. GeneratedCode
- Captures the complete generated SDK code.
- Encompasses PHP files for request classes, resource classes, DTOs, connectors, and foundational resource class.
5. Parameter
- Describes parameters associated with API endpoints.
- Includes attributes like type, name, and nullability.
Building a Custom Parser
If you're working with an API specification format that isn't natively supported by the Saloon SDK Generator, you can build a custom parser to integrate it. Here's how you can do it:
- Create Your Custom Parser:
Start by creating a custom parser class that implements the Crescat\SaloonSdkGenerator\Contracts\Parser
interface.
There are two ways to initialize a Parser. The first one is through the constructor, which will receive the filePath
specified when running sdkgenerator generate:sdk {FILE_PATH}
.
Example:
<?php namespace YourNamespace\CustomParser; use Crescat\SaloonSdkGenerator\Contracts\Parser; use Crescat\SaloonSdkGenerator\Data\Generator\Endpoint; use Crescat\SaloonSdkGenerator\Data\Generator\ApiSpecification; use Crescat\SaloonSdkGenerator\Data\Generator\Parameter; class CustomParser implements Parser { public function __construct(protected $filePath) {} public function parse(): ApiSpecification { // TODO: Implement parseTheContents($this->filepath) // Implement a parser that will return an ApiSpecification object: return new ApiSpecification( name: 'Custom API', description: 'A custom API specification', baseUrl: 'https://api.example.com', endpoints: [ new Endpoint( name: 'GetUserInfo', method: 'GET', pathSegments: ['users', '{user_id}'], description: 'Get user information by ID', queryParameters: [ new Parameter('string', false, 'user_id', 'User ID'), ], ), new Endpoint( name: 'CreateUser', method: 'POST', pathSegments: ['users'], description: 'Create a new user', bodyParameters: [ new Parameter('string', false, 'username', 'Username'), new Parameter('string', false, 'email', 'Email'), ], ) ], ); } }
Or, if you need to pre-process the file, either over the network or run third party code that is not suitable for the
constructor, you may add a build
method, which will be called instead.
Example from the OpenApiParser:
public static function build($content): static { // Call file readers depending on the filetype provided (supports JSON and YAML) return new static( Str::endsWith($content, '.json') ? Reader::readFromJsonFile(fileName: realpath($content), resolveReferences: ReferenceContext::RESOLVE_MODE_ALL) : Reader::readFromYamlFile(fileName: realpath($content), resolveReferences: ReferenceContext::RESOLVE_MODE_ALL) ); }
- Register Your Custom Parser:
To make your custom parser available in the SDK Generator, you need to register it using the Factory
class's registerParser
method.
use Crescat\SaloonSdkGenerator\Factory; use YourNamespace\CustomParser; // Replace with the actual namespace of your custom parser // Register your custom parser Factory::registerParser('custom', CustomParser::class);
- Use Your Custom Parser:
Once registered, you can use your custom parser just like any other built-in parser. Specify 'custom'
as the --type
option when generating the SDK, and the SDK Generator will use your custom parser to process the API specification.
sdkgenerator generate:sdk API_SPEC_FILE.xxx --type=custom
Replace API_SPEC_FILE.xxx
with the path to your custom API specification file.
Now your custom parser is seamlessly integrated into the Saloon SDK Generator, allowing you to generate SDKs from API specifications in your custom format.
Swapping Out Default Code Generators
The Saloon SDK Generator is built with flexibility in mind. If you need to customize the generation process for any component of the SDK, you can easily swap out any of the default generators with your own custom implementation.
Implementing a Custom Generator
To create a custom generator:
-
Create a new class that implements the
Crescat\SaloonSdkGenerator\Contracts\Generator
interface.This interface requires two methods:
- A constructor that accepts a
Config
object. - A
generate
method that returns either a singlePhpFile
or an array ofPhpFile
objects.
- A constructor that accepts a
Example:
namespace YourNamespace; use Crescat\SaloonSdkGenerator\Contracts\Generator; use Crescat\SaloonSdkGenerator\Data\Generator\ApiSpecification; use Crescat\SaloonSdkGenerator\Data\Generator\Config; use Nette\PhpGenerator\PhpFile; class CustomRequestGenerator implements Generator { public function __construct(Config $config) { // Initialize your generator with the configuration } public function generate(ApiSpecification $specification): PhpFile|array { // Your custom generation logic here } }
Using Your Custom Generator
Once you've created your custom generator, you can use it by passing an instance of it when creating
the CodeGenerator
:
$customRequestGenerator = new CustomRequestGenerator($config); $codeGenerator = new CodeGenerator( config: $config, requestGenerator: $customRequestGenerator // ... you can pass other custom generators as needed ); $result = $codeGenerator->run($specification);
By providing your custom generator as an argument to the CodeGenerator
, it will be used in place of the default one.
This allows for extensive customization of the SDK generation process to suit your specific needs.
Tested with Real API Specifications Samples
To showcase the capabilities of the Saloon SDK Generator and to ensure its compatibility with real-world API specifications, we have tested it with the following API specs.
- Paddle (Not publicly available)
- Stripe ( Postman)
- Tableau ( Postman)
- OpenAI (Postman)
- Fiken (OpenApi)
- GoCardless (OpenApi)
- Tripletex (OpenApi)
Generate SDKs
To generate SDKs from the provided API specs, you can run the following composer scripts:
composer generate:paddle composer generate:stripe composer generate:tableau composer generate:openai composer generate:fiken composer generate:gocardless composer generate:tripletex
Generate Zip Archives
If you prefer, (and partially to show that it can do it), you can also generate zip archives of the SDKs:
composer generate:zip:paddle composer generate:zip:stripe composer generate:zip:tableau composer generate:zip:openai composer generate:zip:fiken composer generate:zip:gocardless composer generate:zip:tripletex
Feel free to experiment with these commands to see how the Saloon SDK Generator transforms API specifications into PHP SDKs. While these tests provide valuable insights, keep in mind that compatibility may vary depending on the complexity of your specific API specification.
Reporting Incompatibilities
We understand that compatibility issues may arise when using the Saloon SDK Generator with various API specifications. While we welcome reports about these incompatibilities, it's important to note that this tool was initially developed for our internal use and has been open-sourced to share with the community.
If you encounter issues or incompatibilities while generating SDKs from your API specifications, we encourage you to report them on our GitHub Issue Tracker. Your feedback is valuable and can help us improve the tool over time.
However, please understand that due to the nature of the project and our own priorities, we may not always be able to implement immediate fixes for reported issues.
We appreciate your understanding and your interest in using the Saloon SDK Generator. Your contributions, feedback, and reports will contribute to the ongoing development and improvement of this tool for the broader community.
Links and References
- Postman Collection Format
- Postman Collection Format Schema
- Importing and Exporting Data in Postman
- OpenAPI Specification
Building binary
To build the binary for distribution on Packagist, run the following command:
php ./builds/sdkgenerator app:build sdkgenerator --build-version=1.0
Or use the composer script:
composer build
TODOs
- Create configuration (sdkgenerator --config=sdkgenerator.php/json) file that allows you to override behaviour like:
- what body format to use by default or fallback on
- how to handle Pagination
- if JSON bodies with null values should be removed
- failure handling (AlwaysThrowOnErrors, custom exception classes, or custom method)
- etc... (feel free to add suggestions)
- Configurable Conflict Resolver
- (overwrite (same as --force),
- new (parse code and only add code that is "new", aka new params, new methods),
- prompt user for each conflict (like git in interactive mode)
- etc...
- When no body can be parsed for POST requests, it should warn the user and add a TODO in the generated code.
- Support older swagger API specification
- Generate tests for all endpoints using Request mocking (see)
- Inject "path" variable in the resource constructor via the connector for clean chaining
- example:
$sdk->resource(userId: 1)->deleteUser();
- example:
Contributing
Contributions to this package are welcome! If you find any issues or want to suggest improvements, please submit a pull request or open an issue in the Issue Tracker.
Credits
This package is built on the shoulders of giants, special thanks to the following people for their open source work that helps us all build better software! โค๏ธ
Built by Crescat
Crescat.io is a collaborative software designed for venues, festivals, and event professionals.
With a comprehensive suite of features such as day sheets, checklists, reporting, and crew member booking, Crescat simplifies event management. Professionals in the live event industry trust Crescat to streamline their workflows, reducing the need for multiple tools and outdated spreadsheets.
Troubleshooting:
Fixing command not found
errors
You most likely don't have the composer vendor/bin
folder in your $PATH
# Default config file paths # Zsh: ~/.zshrc # Bash: ~/.bashrc or ~/.bash_profile # Fish: ~/.config/fish/config.fish # Replace 'YOUR_USERNAME' with your actual username # Example: '/Users/john/.composer/vendor/bin' # Zsh echo 'export PATH="/Users/YOUR_USERNAME/.composer/vendor/bin:$PATH"' >> ~/.zshrc source ~/.zshrc # Bash echo 'export PATH="/Users/YOUR_USERNAME/.composer/vendor/bin:$PATH"' >> ~/.bashrc source ~/.bashrc # Fish echo 'set -gx PATH "/Users/YOUR_USERNAME/.composer/vendor/bin" $PATH' >> ~/.config/fish/config.fish source ~/.config/fish/config.fish
License
The MIT License (MIT). Please see License File for more information.