crescat-io / saloon-sdk-generator Goto Github PK
View Code? Open in Web Editor NEWGenerate Saloon SDKs from Postman Collections and OpenAPI Specifications.
License: MIT License
Generate Saloon SDKs from Postman Collections and OpenAPI Specifications.
License: MIT License
I added global require for sdk generator (i am using Laravel Herd if it makes a difference) but composer generate:stripe does t work
When the OpenAPI schema contains referenced parameters, they are not resolved and not included in the generated SDK.
Here is a test that fails to reproduce this (based on https://github.com/crescat-io/saloon-sdk-generator/blob/master/tests/Samples/spotify.yml) :
test('Resolved references in parameters', function () {
$specFile = sample_path('spotify.yml');
$parser = OpenApiParser::build($specFile);
$spec = $parser->parse();
expect($spec->endpoints)->not()->toBeNull()
->and($spec->endpoints[0]->pathParameters)->toHaveCount(1)
->and($spec->endpoints[0]->queryParameters)->toHaveCount(1);
});
For reference, here is the expected SDK (based on the source schema):
At the first attempt, I tried:
https://github.com/crescat-io/saloon-sdk-generator/blob/master/src/Parsers/OpenApiParser.php
public static function build($content): self
{
return new self(
Str::endsWith($content, '.json')
- ? Reader::readFromJsonFile(fileName: realpath($content), resolveReferences: ReferenceContext::RESOLVE_MODE_INLINE)
- : Reader::readFromYamlFile(fileName: realpath($content), resolveReferences: ReferenceContext::RESOLVE_MODE_INLINE)
+ ? Reader::readFromJsonFile(fileName: realpath($content), resolveReferences: ReferenceContext::RESOLVE_MODE_ALL)
+ : Reader::readFromYamlFile(fileName: realpath($content), resolveReferences: ReferenceContext::RESOLVE_MODE_ALL)
);
}
This amply slows down generation.
On my machine, the SmokeTest
test takes about 12 seconds before the change and times out after (60 seconds)
I also found this commit bd9d325 which changes the resolution mode from RESOLVE_MODE_ALL
to RESOLVE_MODE_INLINE
without explaining why but surely on purpose.
My second thought was to resolve references in the mapPrams
method by overriding context at that time to change its mode
:
if(is_a($parameter->schema, Reference::class)) {
$context = $parameter->schema->getContext();
$context->mode = 'ReferenceContext::RESOLVE_MODE_ALL';
$parameter->schema = $parameter->schema->resolve($context);
}
But according to the OpenAPI specification, references can be used at various locations, for example responses.
I know responses are not yet parsed, but I think it should be taken in account for the future.
As I think there are choices to make, I preferred to submit an issue first. I'll submit a PR when this discussion converges to a solution.
HAR files is for lack of a better term a JSON dump of HTTP Requests that you can generate via the DevTools and various proxy tools, useful when there is no official api documentation and you have to reverse engineer an API by doing the good old "clicking around in the user interface to trigger all possible api endpoints manually".
I am on PHP 8.3.1, when I run
composer global require crescat-io/saloon-sdk-generator
Problem 1
- illuminate/session[v10.0.0, ..., v10.39.0] require symfony/finder ^6.2 -> found symfony/finder[v6.2.0, ..., v6.4.0] but the package is fixed to v5.4.27 (lock file version) by a partial update and that version does not match. Make sure you list it as an argument for the update command.
- illuminate/http[v9.52.0, ..., v9.52.16] require illuminate/collections ^9.0 -> found illuminate/collections[v9.0.0, ..., v9.52.16] but the package is fixed to v10.39.0 (lock file version) by a partial update and that version does not match. Make sure you list it as an argument for the update command.
- crescat-io/saloon-sdk-generator v1.10.0 requires saloonphp/laravel-plugin ^3.0 -> satisfiable by saloonphp/laravel-plugin[v3.0.0, v3.1.0, v3.2.0].
- saloonphp/laravel-plugin[v3.1.0, ..., v3.2.0] require illuminate/http ^10.0 -> satisfiable by illuminate/http[v10.0.0, ..., v10.39.0].
- saloonphp/laravel-plugin v3.0.0 requires illuminate/http ^9.52 || ^10.0 -> satisfiable by illuminate/http[v9.52.0, ..., v9.52.16, v10.0.0, ..., v10.39.0].
- illuminate/http[v10.0.0, ..., v10.39.0] require illuminate/session ^10.0 -> satisfiable by illuminate/session[v10.0.0, ..., v10.39.0].
- Root composer.json requires crescat-io/saloon-sdk-generator ^1.10 -> satisfiable by crescat-io/saloon-sdk-generator[v1.10.0].
Use the option --with-all-dependencies (-W) to allow upgrades, downgrades and removals for packages currently locked to specific versions.
You can also try re-running composer require with an explicit version constraint, e.g. "composer require crescat-io/saloon-sdk-generator:*" to figure out if any version is installable, or "composer require crescat-io/saloon-sdk-generator:^2.1" if you know which you need.
can you advice please
My colleagues and I enjoy how Saloon makes API integration easier, and gives us a common well documented way of interacting with them. However, we depend on some API's that use the SOAP protocol. Would it be possible to extend the SDK generator to create Saloon SDK's a la Providr.io, and their WsdlToPhp
Using https://developers.checkmango.com/source.yaml and the command:
sdkgenerator generate:sdk /Users/james/Library/Mobile\ Documents/com~apple~CloudDocs/Downloads/checkmango-openapi-source.yaml --type=yaml --name=Checkmango --output=src --namespace=Checkmango
All I get as output is:
Call to a member function parse() on null
Should be a flag or config option that will generate Resource names based on path segments (/api/projects/10/comments/2
where --segment=4,2
would first try the 4th segment in the path, and fallback to the 2nd if it cant be found.)
Regex
Specify a regex capture group to specify the resource and class names
$uri = 'posts/25/comments/>postNewComment';
$pattern = '{(?<resourceName>\w+)/\d+/(?requestName)}';
Might be stupid and brittle though...
Prompt user for each request
Annoying, but possibly useful, maybe use laravel prompts to build a "table" interface with arrow navigation and inputs.... dunno, might be decent.
Use AI
Requires API Key for an AI service, might generate garbage, might potentially be a fallback solution when everything else fails..
Given this API: https://developers.checkmango.com/operation/operation-createexperiment
The generated request class CreateExperiment
has a bad comment:
/**
* createExperiment
*/
class CreateExperiment extends Request
{
protected Method $method = Method::POST;
public function resolveEndpoint(): string
{
return "/api/teams/{$this->team}/experiments";
}
/**
- * @param int $team The ID of the team to list experiments in.
+ * @param int $team The ID of the team to create the experiment in.
*/
public function __construct(
protected int $team,
) {
}
}
Given this endpoint https://developers.checkmango.com/group/endpoint-ingestion, the generated request class is incorrect:
<?php
namespace Checkmango\Requests\Ingestion;
use Saloon\Enums\Method;
use Saloon\Http\Request;
/**
* ingestData
*
* This endpoint handles all ingestion of data into the system, including enrolments, impressions and
* conversions.
*
* > warn
* > Participants may only be enrolled into a running experiment.
*/
class IngestData extends Request
{
protected Method $method = Method::POST;
public function resolveEndpoint(): string
{
return "/api/teams/{$this->teamId}/ingest";
}
/**
* @param int $team The ID of the team.
*/
public function __construct(
protected int $teamId,
protected int $team,
) {
}
}
Note that the __construct
generates with both teamId
and team
, but only teamId
is referenced in the API?
Hey @HelgeSverre. I'm chipping away my SDK ๐ and came across another one to discuss.
All query parameters are added as class properties but query parameters don't appear to ever have nullable set so they're always required.
I took a look at the OpenAPIParser
and the mapParams
method. It seems like in the underlying library defaults to nullable being false if there is a type vendor/cebe/php-openapi/src/spec/Schema.php:L130
despite your true
default here if it's not set:
I wonder about whether we add a mapping for the required
property of parameter to your own parameter class. This would allow us to maintain the distinction between required
and nullable
. Based on the spec, it seems that `required should default to false, unless explicitly defined in the spec, or if is a path parameter. We can then use that to determine whether query parameters are optional/required.
In terms of the Request classes, they would then have required and optional/nullable arguments, and then the defaultQuery
method could also be updated to wrapped in array_filter
to remove null query fields.
Let me know what you think!
Etsy OpenAPI: https://www.etsy.com/openapi/generated/oas/3.0.0.json
Command I use:
sdkgenerator generate:sdk etsy_open_api.json \
--type=openapi --name EtsySDK --output=app/Etsy --namespace=App\\Etsy --force
Version 1.1 of the package can generate successfully, whereas version 1.2 throws an error.
In ClassLike.php line 78:
Value 'Self' is not valid class name.
๐ Heyo! Finally got around to working on more of my banking sdk. Thought I'd make an issue for investigation instead of going on socials just for better visibility/tracking.
I'm using the OpenAPI specification files from the bank's API, for example this one. On that page you'll see a download button for the OpenAPI file that I'm using with the generator.
The generator generates all the requests, connectors, etc. correctly. The issues I'm having are that some headers and POST bodies are not being populated in the requests. I'm going to assume this is due to the OpenAPI spec file being quirky and having more complex specs maybe?
Let's take the Post Category
request for example. The generated CreateCategory
request class is bare:
Meanwhile, the Swagger editor seems to pick the header & body up correctly:
All requests in this api also require an intermediaryId
header value, but this is not picked up in any of the generation.
Command-wise, what I'm running is:
sdkgenerator generate:sdk ~/Downloads/CIBForIntermediaries.json --type=openapi --namespace=InvestecSdkPhp
Any ideas? Is the OpenAPI spec file being weird, or am I doing something wrong?
As it say in the title, is it possible to use this within a Laravel package? When creating a Laravel package there is no artisan file. And when you add one it gives an error on this line
saloon-sdk-generator/bootstrap/app.php
Line 14 in 64338f6
Given an API spec file that includes a /health
endpoint, the package is unable to generate an SDK.
In PhpNamespace.php line 267:
Name 'Health' used already as alias for Checkmango\Requests\Health\Health.
Hi @HelgeSverre! Thanks for this project. I'm just trying it out and I ran into an error when a Request class is created with a reserved word. Here, you will see an endpoint /void
which then errors when trying to create a class Void
.
Initially I replaced the RequestGenerator
with a version that would catch the exception that's thrown and then try again with a suffix, e.g. VoidRequest
.
However, that then has a problem where the same logic is required in the ResourceGenerator
.
So then I was wondering if a check for reserved words might be better done somewhere centrally, like in the NameHelper
here.
The challenge then is knowing how to adjust the class name with an appropriate suffix.
If you have advice on a route you would prefer, I'd be happy to work on a PR when I have a moment.
I tried to give the new DTO feature a spin and ran into an issue:
In DtoGenerator.php line 35:
Crescat\SaloonSdkGenerator\Generators\DtoGenerator::generateDtoClass(): Argument #2 ($schema) must be of type cebe\openapi\spec\Schema, cebe\openap
i\spec\Reference given, called in phar:///app/vendor/crescat-io/saloon-sdk-generator/builds/sdkgenerator/src/Generators/DtoGenerator.php on line 28
Script sdkgenerator generate:sdk merged.json --type=openapi --name="SaloonConnector" --output=src --namespace=ShipStream\\FedEx --force handling the generate-sdk event returned with error code 1
Let me know if you'd like to take a look at the repo but basically all it does is merge multiple OpenAPI specs into merged.json, apply some sanitization to the spec (e.g. adding tags) then run the sdkgenerator. It worked on version 1.10.0 but does not work on 1.2.0.
Side note: When using "composer require" the default version installed is 1.10, not 1.2 since 1.10 is "newer".. Took me a while to figure out why I wasn't seeing any DTO generated.. :)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.