-
-
Notifications
You must be signed in to change notification settings - Fork 6.6k
To sponsor a task, simply open an issue with the details of the task (assuming no similar tasks/issues have been created by other users yet) and specify the amount of the sponsorship (e.g. USD$200).
One good way to estimate the sponsorship amount is to roughly estimate the amount of hours needed if you're the one working on this task (e.g. 10 hours) and divide that by 2 (i.e. 5 hours), and multiply that by your man-hour (e.g. USD$100), which will result in $500 for the sponsorship amount.
Here is an example of sponsorship for bug fixes, enhancements in the Rust client generator:
https://github.com/OpenAPITools/openapi-generator/issues/6178
If someone is interested in the task, they can reply to the issue and you can assign the task to those given that both parties agree on the deliverables, schedule and payment methods (e.g. PayPal, TransferWise, etc)
Thank you in advance for your sponsorship to help move the project forward.
[Optional] After you've created an issue with sponsorship, please contact team@openapitools.org so that we can prioritise accordingly.
Yes, please join our Slack workspace and here is the code of conduct covering this project including the chat room.
For patch release (e.g. 3.0.5 to 3.0.6), we plan to do it on a monthly basis.
For minor release (e.g. 3.1.6 to 3.2.0), we plan to do it on a bi-monthly basis.
For major releases (e.g. 3.3.6 to 4.0.0), we plan to do it on a yearly basis.
Patch releases will not contain breaking changes.
Minor releases will contain breaking changes (with fallbacks) so that users can easily fall back to what the generator produces before.
Major releases will contain breaking changes (without fallbacks) so that users may need to resolve conflicts/issues when upgrading to a newer version.
This project doesn't follow Semantic Versioning(which is not something we're against with) as we regularly include breaking changes with fallbacks in the minor releases. (otherwise breaking changes with or without fallbacks will take a year or so to be included in a stable major release, which is not a reasonable amount of time our users are willing to wait)
Does OpenAPI Generator support all new features in OpenAPI Specification v3.x?
No, we do not support all new features (e.g. callback, anyOf, etc) at the moment. We would definitely welcome contributions from the community to add support for these new features. Please search the issue tracker to see if anyone has opened a ticket to track the new feature. If no ticket has been opened yet, please open a new one and ideally a sample spec so that we can prioritize the feature request accordingly.
Please refer to https://github.com/OpenAPITools/openapi-generator/blob/master/docs/debugging.md
tags
basically groups endpoints into the same API class file. For example, an endpoint with the "store" tags
will be generated in the StoreApi
class file.
Ref: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#tagObject
Please refer to the "Bringing your own models" in the "Customization" guide
Please add -Dio.swagger.parser.util.RemoteUrl.trustAll=true -Dio.swagger.v3.parser.util.RemoteUrl.trustAll=true
when generating the code.
For example, to skip git_push.sh
, one can create a file named .openapi-generator-ignore
in the output directory and put git_push.sh
in that file, which just works like .gitignore.
.openapi-generator-ignore is auto-generated by default.
Or one can manually delete the file(s) after the code generation process completes.
You can use the -t
option with the customized templates. Here is an example adding header/footer to Ruby templates.
- git clone https://github.com/openapitools/openapi-generator
- cd openapi-generator
- mvn clean package
- cp -R modules/openapi-generator/src/main/resources/ruby /var/tmp/ ## copy all Ruby templates to /var/tmp/. You can also selectively copy only the templates (e.g. api.mustache) you want to customize
- Edit /var/tmp/ruby/api.mustache to add the footer/header
- Run the following command to generate the Ruby API client with customized templates:
java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generate \
-i modules/openapi-generator/src/test/resources/2_0/petstore.yaml \
-t /var/tmp/ruby
-g ruby -o /var/tmp/ruby_api_client/
Besides generating the server code as a starting point to implement the API backend, here are some use cases of the server generators:
- prototyping - one can generate the server code and have a functional API backend very quickly to try different things or features.
- mocking - easily provide an API backend for mocking based on the
examples
field defined in the response object. - migration - let's say one wants to migrate an API backend from Ruby on Rails to Java Spring. The server generator can save a lot of time in implementing and verify each endpoint in the new API backend.
Please do the following:
- Click on the failed tests and check the log to see what's causing the errors.
- If it's related to connection timeout in downloading dependencies, please restart the CI jobs (which can be done by closing and reopening the PR)
I ran the test locally and got errors (HTTP status code: 500) from the public Petstore server. Is there a way to run the Petstore server locally for testing?
Yes, please run the following commands (assuming you've docker installed):
docker pull swaggerapi/petstore
docker run -d -e SWAGGER_HOST=http://petstore.swagger.io -e SWAGGER_BASE_PATH=/v2 -p 80:8080 swaggerapi/petstore
docker ps -a
Then add the following to your local host table:
127.0.0.1 petstore.swagger.io
Please contact team@openapitools.org with the details and we'll follow up with you.
For "beta", it means the generator is usually newly-added or not that mature in terms of functionality and feature supported.
For "deprecated", it means the generator is no longer maintained due to various reasons such as languages no longer officially support (e.g. Swift 1.x). One can still use the generator or even submit PRs to improve it but users should not have any expectation in terms of the output produced by the generator.
We do not guarantee the output by the generator would work appropriately and securely. It's the responsibility of the users to evaluate and test the output to ensure it can meet their requirements.
The official definition of the primitive type can be found in https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#data-types
Primitive types are usually mapped to primitive types in the corresponding programming language and we do not recommend mapping primitive types to models (e.g. primitive type wrappers) as this does not conform to the specification.
Mustache tags such as isString
, isNumber
are for enum models only.
How can I update the samples? I couldn't find the script under ./bin/
or Windows batch files under .\bin\windows
?
As of Jun 2020, we've switched to ./bin/generate-samples.sh
for updating Petstore samples. For example, to update Ruby petstore client samples, please run ./bin/generate-samples.sh ./bin/configs/ruby*
.
./bin/configs/other/
is another folder that stores the config files for generators that are less active.
For Windows users, please run the script in Git BASH.
To test your OpenAPI/Swagger spec with the latest master to confirm whether the issue still exists, please try the following
-
Docker image for latest openapi-generator-cli:
docker pull openapitools/openapi-generator-cli:latest
-
Docker image for latest openapi-generator-online:
docker pull openapitools/openapi-generator-online:latest
-
Download the latest snapshot version of openapi-generator-cli JAR: https://oss.sonatype.org/content/repositories/snapshots/org/openapitools/openapi-generator-cli/
-
Build the project locally
git clone https://github.com/OpenAPITools/openapi-generator
cd openapi-generator
- Build the project
-
Windows:
mvnw.cmd clean install -Dmaven.test.skip=true -Dmaven.javadoc.skip=true
-
Mac/Linux:
./mvnw clean install
-
Windows:
- Run the CLI jar locally
-
Windows:
java -jar modules\openapi-generator-cli\target\openapi-generator-cli.jar generate -g ruby -i https://raw.githubusercontent.com/OpenAPITools/openapi-generator/master/modules/openapi-generator/src/test/resources/3_0/petstore.yaml -o C:\temp\ruby-client-test
-
Mac/Linux:
java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generate -g ruby -i https://raw.githubusercontent.com/OpenAPITools/openapi-generator/master/modules/openapi-generator/src/test/resources/3_0/petstore.yaml -o /var/tmp/ruby-client-test
-
Windows:
Please refer to http://rypress.com/tutorials/git/rebasing, or follow the steps below (assuming the branch for the PR is "fix_issue_9999"):
git checkout master
-
git pull upstream master
(assumingupstream
is pointing to the official repo) git checkout fix_issue_9999
git rebase master
- Resolve merge conflicts, if any, and run
git commit -a
- Rebase done (you may need to add
--force
when doinggit push
)
(To setup upstream
pointing to the official repo, please run git remote add upstream https://github.com/openapitools/openapi-generator.git
)
Please refer to https://stackoverflow.com/questions/3042437/how-to-change-the-commit-author-for-one-specific-commit or you can simply add the email address in the commit as your secondary email address in your Github account.
Yes, http://www.alexkras.com/19-git-tips-for-everyday-use/
Visit https://github.com/openapitools/openapi-generator and then click on the "Fork" button in the upper right corner. Then in your local machine, run the following (assuming your github ID is "your_user_id")
- git clone https://github.com/your_user_id/openapi-generator.git
- cd openapi-generator
- git checkout -b fix_issue9999
- make changes
- git commit -a (you may need to use
git add filename
to add new files) - git push origin fix_issue9999
- Visit https://github.com/openapitools/openapi-generator in your browser and click on the button to file a new PR based on fix_issue9999
Visit https://github.com/openapitools/openapi-generator and then click on the "Fork" button in the upper right corner. Then in your local machine, run the following (assuming your github ID is "your_user_id")
- git clone https://github.com/your_user_id/openapi-generator.git
- cd openapi-generator
- git remote add upstream https://github.com/openapitools/openapi-generator
- git checkout 4.2.x
- git pull usptream 4.2.x (ensure it has the latest change)
- git log (review the latest change to this branch)
- git checkout -b 4.2.x-enhance (create a new branch instead of modifying 4.2.x directly)
- make changes
- git commit -a (you may need to use
git add filename
to add new files) - git push origin 4.2.x-enhance
- Visit https://github.com/openapitools/openapi-generator in your browser and click on the button to file a new PR based on 4.2.x-enhance. Make sure the PR is filed against "4.2.x" branch instead of master.
- After the branch is merged, repeat step 3 & 4
Using Java API client to make request results in SSL errors due to an invalid certificate. Is there a way to bypass that?
Yes, please refer to http://stackoverflow.com/a/6055903/677735
You will need to provide customized files in Java/libraries/feign
under the resources folder and pass the location via the -t
option.
In your Gradle build script, please add the following (example):
config.templateDir = 'src/openapi-generator-templates/Java/libraries/feign
The Java SDK is also compatible with Android.
[RECOMMENDED] To generate the Java SDK with okhttp
and gson
libraries, run the following:
mvn clean package
java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generate \
-i https://raw.githubusercontent.com/OpenAPITools/openapi-generator/master/modules/openapi-generator/src/test/resources/2_0/petstore.json \
-g java --library=okhttp-gson \
-D hideGenerationTimestamp=true \
-o /var/tmp/java/okhttp-gson/
You can also generate the Java SDK with other HTTP libraries by replacing okhttp-gson
with retrofit
for example. For a list of support libraries, please run
java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar config-help -g java
To generate the Android SDK with volley
, please run
mvn clean package
java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generate \
-i https://raw.githubusercontent.com/OpenAPITools/openapi-generator/master/modules/openapi-generator/src/test/resources/2_0/petstore.json \
-g android --library=volley \
-o /var/tmp/android/volley/
We do not recommend using the default HTTP library (Apache HttpClient) with android
as it's not actively maintained.
I got the warning CSC: warning CS2002: Source file 'Api/FakeApi.cs' specified multiple times
in Xamarin. How can I resolve it?
The warning has no impact on the build process so you should be able to build the solution without issue. The warning should be addressed in the upcoming stable release of Xamarin.
Here are the steps:
git clone https://github.com/openapitools/openapi-generator.git
cd openapi-generator/samples/client/petstore/objc/default/OpenAPIClientTests
mvn integration-test
Besides default
(folder) ObjC API client, there's also core-data
for another ObjC API client with Core Data support.
Here are the steps:
git clone https://github.com/openapitools/openapi-generator.git
cd openapi-generator/samples/client/petstore/swift/default/OpenAPIClientTests
mvn integration-test
Please use swift5
generator because Swift 4.x is deprecated.
There is a new swift6
generator, that is currently in beta, try it and give us your feedback.
First you subclass RequestBuilderFactory
class BearerRequestBuilderFactory: RequestBuilderFactory {
func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type {
BearerRequestBuilder<T>.self
}
func getBuilder<T: Decodable>() -> RequestBuilder<T>.Type {
BearerDecodableRequestBuilder<T>.self
}
}
Then you subclass URLSessionRequestBuilder and URLSessionDecodableRequestBuilder
class BearerRequestBuilder<T>: URLSessionRequestBuilder<T> {
@discardableResult
override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result<Response<T>, ErrorResponse>) -> Void) -> RequestTask {
// Before making the request, we can validate if we have a bearer token to be able to make a request
BearerTokenHandler.refreshTokenIfDoesntExist {
// Here we make the request
super.execute(apiResponseQueue) { result in
switch result {
case .success:
// If we got a successful response, we send the response to the completion block
completion(result)
case let .failure(error):
// If we got a failure response, we will analyse the error to see what we should do with it
if case let ErrorResponse.error(_, data, response, error) = error {
// If the error is an ErrorResponse.error() we will analyse it to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
BearerTokenHandler.refreshTokenIfUnauthorizedRequestResponse(
data: data,
response: response,
error: error
) { wasTokenRefreshed in
if wasTokenRefreshed {
// If the token was refreshed, it's because it was a 401 error, so we refreshed the token, and we are going to retry the request by calling self.execute()
self.execute(apiResponseQueue, completion)
} else {
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
completion(result)
}
}
} else {
// If it's an unknown error, we send the response to the completion block
completion(result)
}
}
}
}
return requestTask
}
}
class BearerDecodableRequestBuilder<T: Decodable>: URLSessionDecodableRequestBuilder<T> {
@discardableResult
override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result<Response<T>, ErrorResponse>) -> Void) -> RequestTask {
// Before making the request, we can validate if we have a bearer token to be able to make a request
BearerTokenHandler.refreshTokenIfDoesntExist {
// Here we make the request
super.execute(apiResponseQueue) { result in
switch result {
case .success:
// If we got a successful response, we send the response to the completion block
completion(result)
case let .failure(error):
// If we got a failure response, we will analyse the error to see what we should do with it
if case let ErrorResponse.error(_, data, response, error) = error {
// If the error is an ErrorResponse.error() we will analyse it to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
BearerTokenHandler.refreshTokenIfUnauthorizedRequestResponse(
data: data,
response: response,
error: error
) { wasTokenRefreshed in
if wasTokenRefreshed {
// If the token was refreshed, it's because it was a 401 error, so we refreshed the token, and we are going to retry the request by calling self.execute()
self.execute(apiResponseQueue, completion)
} else {
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
completion(result)
}
}
} else {
// If it's an unknown error, we send the response to the completion block
completion(result)
}
}
}
}
return requestTask
}
}
class BearerTokenHandler {
private static var bearerToken: String? = nil
static func refreshTokenIfDoesntExist(completionHandler: @escaping () -> Void) {
if bearerToken != nil {
completionHandler()
} else {
startRefreshingToken {
completionHandler()
}
}
}
static func refreshTokenIfUnauthorizedRequestResponse(data: Data?, response: URLResponse?, error: Error?, completionHandler: @escaping (Bool) -> Void) {
if let response = response as? HTTPURLResponse, response.statusCode == 401 {
startRefreshingToken {
completionHandler(true)
}
} else {
completionHandler(false)
}
}
private static func startRefreshingToken(completionHandler: @escaping () -> Void) {
// Get a bearer token
let dummyBearerToken = "..."
bearerToken = dummyBearerToken
PetstoreClientAPI.customHeaders["Authorization"] = "Bearer \(dummyBearerToken)"
completionHandler()
}
}
Then you assign the BearerRequestBuilderFactory
to the property requestBuilderFactory
.
PetstoreClientAPI.requestBuilderFactory = BearerRequestBuilderFactory()
The name PetstoreClientAPI.requestBuilderFactory
will change depending on your project name.
Here is a working sample that put's together all of this. AppDelegate.swift BearerDecodableRequestBuilder.swift
First you subclass RequestBuilderFactory
class BearerRequestBuilderFactory: RequestBuilderFactory {
func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type {
BearerRequestBuilder<T>.self
}
func getBuilder<T: Decodable>() -> RequestBuilder<T>.Type {
BearerDecodableRequestBuilder<T>.self
}
}
Then you subclass AlamofireRequestBuilder and AlamofireDecodableRequestBuilder
class BearerRequestBuilder<T>: AlamofireRequestBuilder<T> {
override func createSessionManager() -> SessionManager {
let sessionManager = super.createSessionManager()
let bearerTokenHandler = BearerTokenHandler()
sessionManager.adapter = bearerTokenHandler
sessionManager.retrier = bearerTokenHandler
return sessionManager
}
}
class BearerDecodableRequestBuilder<T: Decodable>: AlamofireDecodableRequestBuilder<T> {
override func createSessionManager() -> SessionManager {
let sessionManager = super.createSessionManager()
let bearerTokenHandler = BearerTokenHandler()
sessionManager.adapter = bearerTokenHandler
sessionManager.retrier = bearerTokenHandler
return sessionManager
}
}
class BearerTokenHandler: RequestAdapter, RequestRetrier {
private static var bearerToken: String? = nil
func adapt(_ urlRequest: URLRequest) throws -> URLRequest {
if let bearerToken = Self.bearerToken {
var urlRequest = urlRequest
urlRequest.setValue("Bearer \(bearerToken)", forHTTPHeaderField: "Authorization")
return urlRequest
}
return urlRequest
}
func should(_: SessionManager, retry request: Request, with _: Error, completion: @escaping RequestRetryCompletion) {
if let response = request.task?.response as? HTTPURLResponse, response.statusCode == 401 {
Self.startRefreshingToken { isTokenRefreshed in
completion(isTokenRefreshed, 0.0)
}
} else {
completion(false, 0.0)
}
}
private static func startRefreshingToken(completionHandler: @escaping (Bool) -> Void) {
// Get a bearer token
let dummyBearerToken = "..."
bearerToken = dummyBearerToken
PetstoreClientAPI.customHeaders["Authorization"] = "Bearer \(dummyBearerToken)"
completionHandler(true)
}
}
Then you assign the BearerRequestBuilderFactory
to the property requestBuilderFactory
.
PetstoreClientAPI.requestBuilderFactory = BearerRequestBuilderFactory()
The name PetstoreClientAPI.requestBuilderFactory
will change depending on your project name.
Here is a working sample that put's together all of this. AppDelegate.swift BearerTokenHandler.swift
First you implement the `OpenAPIInterceptor` protocol.
public class BearerOpenAPIInterceptor: OpenAPIInterceptor { public init() {}public func intercept(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, completion: @escaping (Result<URLRequest, any Error>) -> Void) {
refreshTokenIfDoesntExist { token in
// Change the current url request
var newUrlRequest = urlRequest
newUrlRequest.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
// Change the global headers
openAPIClient.customHeaders["Authorization"] = "Bearer \(token)"
completion(.success(newUrlRequest))
}
}
public func retry(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, data: Data?, response: URLResponse, error: Error, completion: @escaping (OpenAPIInterceptorRetry) -> Void) {
// We will analyse the response to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
refreshTokenIfUnauthorizedRequestResponse(
data: data,
response: response,
error: error
) { (wasTokenRefreshed, newToken) in
if wasTokenRefreshed, let newToken = newToken {
// Change the global headers
openAPIClient.customHeaders["Authorization"] = "Bearer \(newToken)"
completion(.retry)
} else {
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
completion(.dontRetry)
}
}
}
private var bearerToken: String? = nil
func refreshTokenIfDoesntExist(completionHandler: @escaping (String) -> Void) {
if let bearerToken = bearerToken {
completionHandler(bearerToken)
} else {
startRefreshingToken { token in
completionHandler(token)
}
}
}
func refreshTokenIfUnauthorizedRequestResponse(data: Data?, response: URLResponse, error: Error, completionHandler: @escaping (Bool, String?) -> Void) {
if let response = response as? HTTPURLResponse, response.statusCode == 401 {
startRefreshingToken { token in
completionHandler(true, token)
}
} else {
completionHandler(false, nil)
}
}
private func startRefreshingToken(completionHandler: @escaping (String) -> Void) {
// Get a bearer token
let dummyBearerToken = "..."
bearerToken = dummyBearerToken
completionHandler(dummyBearerToken)
}
}
Then you assign the BearerOpenAPIInterceptor
to the property OpenAPIClient.shared.interceptor
.
OpenAPIClient.shared.interceptor = BearerOpenAPIInterceptor()
Here is a working sample that put's together all of this. AppDelegate.swift BearerTokenHandler.swift
First implement the `Alamofire` `RequestInterceptor` protocol.
class BearerTokenHandler: RequestInterceptor, @unchecked Sendable { private var bearerToken: String? = nilfunc adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
if let bearerToken = bearerToken {
var urlRequest = urlRequest
urlRequest.setValue("Bearer \(bearerToken)", forHTTPHeaderField: "Authorization")
completion(.success(urlRequest))
return
}
completion(.success(urlRequest))
}
func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) {
if let response = request.task?.response as? HTTPURLResponse, response.statusCode == 401 {
startRefreshingToken { isTokenRefreshed in
completion(.retry)
}
} else {
completion(.doNotRetryWithError(error))
}
}
private func startRefreshingToken(completionHandler: @escaping (Bool) -> Void) {
// Get a bearer token
let dummyBearerToken = "..."
bearerToken = dummyBearerToken
OpenAPIClient.shared.customHeaders["Authorization"] = "Bearer \(dummyBearerToken)"
completionHandler(true)
}
}
Then you assign the BearerTokenHandler
to the property OpenAPIClient.shared.interceptor
.
OpenAPIClient.shared.interceptor = BearerTokenHandler()
Here is a working sample that put's together all of this. AppDelegate.swift BearerTokenHandler.swift
The JSON response failed to deserialize properly into the object due to change in variable naming (snake_case to camelCase). Is there any way to keep the original naming?
Yes, please use the following option when generating TypeScript clients:
modelPropertyNaming
Naming convention for the property: 'camelCase', 'PascalCase', 'snake_case' and 'original', which keeps the original name (Default: camelCase)