Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[swift] add option for non public api #4556

Merged
merged 7 commits into from
Nov 25, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bin/swift4-petstore-all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
./bin/swift4-petstore-rxswift.sh
./bin/swift4-petstore-objcCompatible.sh
./bin/swift4-petstore-unwrapRequired.sh
./bin/swift4-petstore-nonPublicApi.sh
7 changes: 7 additions & 0 deletions bin/swift4-petstore-nonPublicApi.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"podSummary": "PetstoreClient",
"podHomepage": "https://github.com/openapitools/openapi-generator",
"podAuthors": "",
"projectName": "PetstoreClient",
"nonPublicApi": true
}
42 changes: 42 additions & 0 deletions bin/swift4-petstore-nonPublicApi.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/bin/sh

SCRIPT="$0"
echo "# START SCRIPT: $SCRIPT"

while [ -h "$SCRIPT" ] ; do
ls=`ls -ld "$SCRIPT"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
SCRIPT="$link"
else
SCRIPT=`dirname "$SCRIPT"`/"$link"
fi
done

if [ ! -d "${APP_DIR}" ]; then
APP_DIR=`dirname "$SCRIPT"`/..
APP_DIR=`cd "${APP_DIR}"; pwd`
fi

executable="./modules/openapi-generator-cli/target/openapi-generator-cli.jar"

if [ ! -f "$executable" ]
then
mvn -B clean package
fi

# if you've executed sbt assembly previously it will use that instead.
export JAVA_OPTS="${JAVA_OPTS} -Xmx1024M -DloggerPath=conf/log4j.properties"
ags="generate -t modules/openapi-generator/src/main/resources/swift4 -i modules/openapi-generator/src/test/resources/2_0/swift/petstore-with-fake-endpoints-models-for-testing.yaml -g swift4 -c ./bin/swift4-petstore-nonPublicApi.json -o samples/client/petstore/swift4/nonPublicApi --generate-alias-as-model $@"

java $JAVA_OPTS -jar $executable $ags

if type "xcodegen" > /dev/null 2>&1; then
cd samples/client/petstore/swift4/nonPublicApi
xcodegen generate
fi

if type "swiftlint" > /dev/null 2>&1; then
cd samples/client/petstore/swift4/nonPublicApi
swiftlint autocorrect
fi
1 change: 1 addition & 0 deletions docs/generators/swift4.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ sidebar_label: swift4
|prependFormOrBodyParameters|Add form or body parameters to the beginning of the parameter list.| |false|
|projectName|Project name in Xcode| |null|
|responseAs|Optionally use libraries to manage response. Currently PromiseKit, RxSwift are available.| |null|
|nonPublicApi|Generates code with reduced access modifiers; allows embedding elsewhere without exposing non-public API calls to consumers.(default: false)| |null|
|unwrapRequired|Treat 'required' properties in response as non-optional (which would crash the app if api returns null as opposed to required option specified in json schema| |null|
|objcCompatible|Add additional properties and methods for Objective-C compatibility (default: false)| |null|
|podSource|Source information used for Podspec| |null|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public class Swift4Codegen extends DefaultCodegen implements CodegenConfig {
protected static final String LIBRARY_RX_SWIFT = "RxSwift";
protected static final String[] RESPONSE_LIBRARIES = {LIBRARY_PROMISE_KIT, LIBRARY_RX_SWIFT};
protected String projectName = "OpenAPIClient";
protected boolean nonPublicApi = false;
protected boolean unwrapRequired;
protected boolean objcCompatible = false;
protected boolean lenientTypeCast = false;
Expand Down Expand Up @@ -208,6 +209,9 @@ public Swift4Codegen() {
"Optionally use libraries to manage response. Currently "
+ StringUtils.join(RESPONSE_LIBRARIES, ", ")
+ " are available."));
cliOptions.add(new CliOption(CodegenConstants.NON_PUBLIC_API,
CodegenConstants.NON_PUBLIC_API_DESC
+ "(default: false)"));
cliOptions.add(new CliOption(UNWRAP_REQUIRED,
"Treat 'required' properties in response as non-optional "
+ "(which would crash the app if api returns null as opposed "
Expand Down Expand Up @@ -329,6 +333,14 @@ public void processOpts() {
}
sourceFolder = projectName + File.separator + sourceFolder;

// Setup nonPublicApi option, which generates code with reduced access
// modifiers; allows embedding elsewhere without exposing non-public API calls
// to consumers
if (additionalProperties.containsKey(CodegenConstants.NON_PUBLIC_API)) {
setNonPublicApi(convertPropertyToBooleanAndWriteBack(CodegenConstants.NON_PUBLIC_API));
}
additionalProperties.put(CodegenConstants.NON_PUBLIC_API, nonPublicApi);

// Setup unwrapRequired option, which makes all the
// properties with "required" non-optional
if (additionalProperties.containsKey(UNWRAP_REQUIRED)) {
Expand Down Expand Up @@ -714,6 +726,10 @@ public void setProjectName(String projectName) {
this.projectName = projectName;
}

public void setNonPublicApi(boolean nonPublicApi) {
this.nonPublicApi = nonPublicApi;
}

public void setUnwrapRequired(boolean unwrapRequired) {
this.unwrapRequired = unwrapRequired;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

import Foundation

public struct APIHelper {
public static func rejectNil(_ source: [String:Any?]) -> [String:Any]? {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} struct APIHelper {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} static func rejectNil(_ source: [String:Any?]) -> [String:Any]? {
let destination = source.reduce(into: [String: Any]()) { (result, item) in
if let value = item.value {
result[item.key] = value
Expand All @@ -20,7 +20,7 @@ public struct APIHelper {
return destination
}

public static func rejectNilHeaders(_ source: [String:Any?]) -> [String:String] {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} static func rejectNilHeaders(_ source: [String:Any?]) -> [String:String] {
return source.reduce(into: [String: String]()) { (result, item) in
if let collection = item.value as? Array<Any?> {
result[item.key] = collection.filter({ $0 != nil }).map{ "\($0!)" }.joined(separator: ",")
Expand All @@ -30,7 +30,7 @@ public struct APIHelper {
}
}

public static func convertBoolToString(_ source: [String: Any]?) -> [String:Any]? {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} static func convertBoolToString(_ source: [String: Any]?) -> [String:Any]? {
guard let source = source else {
return nil
}
Expand All @@ -45,14 +45,14 @@ public struct APIHelper {
})
}

public static func mapValueToPathItem(_ source: Any) -> Any {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} static func mapValueToPathItem(_ source: Any) -> Any {
if let collection = source as? Array<Any?> {
return collection.filter({ $0 != nil }).map({"\($0!)"}).joined(separator: ",")
}
return source
}

public static func mapValuesToQueryItems(_ source: [String:Any?]) -> [URLQueryItem]? {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} static func mapValuesToQueryItems(_ source: [String:Any?]) -> [URLQueryItem]? {
let destination = source.filter({ $0.value != nil}).reduce(into: [URLQueryItem]()) { (result, item) in
if let collection = item.value as? Array<Any?> {
let value = collection.filter({ $0 != nil }).map({"\($0!)"}).joined(separator: ",")
Expand Down
34 changes: 17 additions & 17 deletions modules/openapi-generator/src/main/resources/swift4/APIs.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,25 @@

import Foundation

open class {{projectName}}API {
public static var basePath = "{{{basePath}}}"
public static var credential: URLCredential?
public static var customHeaders: [String:String] = [:]
public static var requestBuilderFactory: RequestBuilderFactory = AlamofireRequestBuilderFactory()
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class {{projectName}}API {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} static var basePath = "{{{basePath}}}"
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} static var credential: URLCredential?
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} static var customHeaders: [String:String] = [:]
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} static var requestBuilderFactory: RequestBuilderFactory = AlamofireRequestBuilderFactory()
}

open class RequestBuilder<T> {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class RequestBuilder<T> {
var credential: URLCredential?
var headers: [String:String]
public let parameters: [String:Any]?
public let isBody: Bool
public let method: String
public let URLString: String
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} let parameters: [String:Any]?
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} let isBody: Bool
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} let method: String
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} let URLString: String

/// Optional block to obtain a reference to the request's progress instance when available.
public var onProgressReady: ((Progress) -> ())?
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var onProgressReady: ((Progress) -> ())?

required public init(method: String, URLString: String, parameters: [String:Any]?, isBody: Bool, headers: [String:String] = [:]) {
required {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} init(method: String, URLString: String, parameters: [String:Any]?, isBody: Bool, headers: [String:String] = [:]) {
self.method = method
self.URLString = URLString
self.parameters = parameters
Expand All @@ -34,28 +34,28 @@ open class RequestBuilder<T> {
addHeaders({{projectName}}API.customHeaders)
}

open func addHeaders(_ aHeaders:[String:String]) {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} func addHeaders(_ aHeaders:[String:String]) {
for (header, value) in aHeaders {
headers[header] = value
}
}

open func execute(_ completion: @escaping (_ response: Response<T>?, _ error: Error?) -> Void) { }
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} func execute(_ completion: @escaping (_ response: Response<T>?, _ error: Error?) -> Void) { }

public func addHeader(name: String, value: String) -> Self {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} func addHeader(name: String, value: String) -> Self {
if !value.isEmpty {
headers[name] = value
}
return self
}

open func addCredential() -> Self {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} func addCredential() -> Self {
self.credential = {{projectName}}API.credential
return self
}
}

public protocol RequestBuilderFactory {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} protocol RequestBuilderFactory {
func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type
func getBuilder<T:Decodable>() -> RequestBuilder<T>.Type
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ private struct SynchronizedDictionary<K: Hashable, V> {
target: nil
)

public subscript(key: K) -> V? {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} subscript(key: K) -> V? {
get {
var value: V?

Expand All @@ -49,16 +49,16 @@ private struct SynchronizedDictionary<K: Hashable, V> {
// Store manager to retain its reference
private var managerStore = SynchronizedDictionary<String, Alamofire.SessionManager>()

open class AlamofireRequestBuilder<T>: RequestBuilder<T> {
required public init(method: String, URLString: String, parameters: [String : Any]?, isBody: Bool, headers: [String : String] = [:]) {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class AlamofireRequestBuilder<T>: RequestBuilder<T> {
required {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} init(method: String, URLString: String, parameters: [String : Any]?, isBody: Bool, headers: [String : String] = [:]) {
super.init(method: method, URLString: URLString, parameters: parameters, isBody: isBody, headers: headers)
}

/**
May be overridden by a subclass if you want to control the session
configuration.
*/
open func createSessionManager() -> Alamofire.SessionManager {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} func createSessionManager() -> Alamofire.SessionManager {
let configuration = URLSessionConfiguration.default
configuration.httpAdditionalHeaders = buildHeaders()
return Alamofire.SessionManager(configuration: configuration)
Expand All @@ -67,7 +67,7 @@ open class AlamofireRequestBuilder<T>: RequestBuilder<T> {
/**
May be overridden by a subclass if you want to custom request constructor.
*/
open func createURLRequest() -> URLRequest? {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} func createURLRequest() -> URLRequest? {
let encoding: ParameterEncoding = isBody ? JSONDataEncoding() : URLEncoding()
guard let originalRequest = try? URLRequest(url: URLString, method: HTTPMethod(rawValue: method)!, headers: buildHeaders()) else { return nil }
return try? encoding.encode(originalRequest, with: parameters)
Expand All @@ -80,19 +80,19 @@ open class AlamofireRequestBuilder<T>: RequestBuilder<T> {
Return nil to use the default behavior (inferring the Content-Type from
the file extension). Return the desired Content-Type otherwise.
*/
open func contentTypeForFormPart(fileURL: URL) -> String? {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} func contentTypeForFormPart(fileURL: URL) -> String? {
return nil
}

/**
May be overridden by a subclass if you want to control the request
configuration (e.g. to override the cache policy).
*/
open func makeRequest(manager: SessionManager, method: HTTPMethod, encoding: ParameterEncoding, headers: [String:String]) -> DataRequest {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} func makeRequest(manager: SessionManager, method: HTTPMethod, encoding: ParameterEncoding, headers: [String:String]) -> DataRequest {
return manager.request(URLString, method: method, parameters: parameters, encoding: encoding, headers: headers)
}

override open func execute(_ completion: @escaping (_ response: Response<T>?, _ error: Error?) -> Void) {
override {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} func execute(_ completion: @escaping (_ response: Response<T>?, _ error: Error?) -> Void) {
let managerId:String = UUID().uuidString
// Create a new manager for each request to customize its request header
let manager = createSessionManager()
Expand Down Expand Up @@ -268,7 +268,7 @@ open class AlamofireRequestBuilder<T>: RequestBuilder<T> {
}
}

open func buildHeaders() -> [String: String] {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} func buildHeaders() -> [String: String] {
var httpHeaders = SessionManager.defaultHTTPHeaders
for (key, value) in self.headers {
httpHeaders[key] = value
Expand Down Expand Up @@ -337,14 +337,14 @@ fileprivate enum DownloadException : Error {
case requestMissingURL
}

public enum AlamofireDecodableRequestBuilderError: Error {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum AlamofireDecodableRequestBuilderError: Error {
case emptyDataResponse
case nilHTTPResponse
case jsonDecoding(DecodingError)
case generalError(Error)
}

open class AlamofireDecodableRequestBuilder<T:Decodable>: AlamofireRequestBuilder<T> {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class AlamofireDecodableRequestBuilder<T:Decodable>: AlamofireRequestBuilder<T> {

override fileprivate func processRequest(request: DataRequest, _ managerId: String, _ completion: @escaping (_ response: Response<T>?, _ error: Error?) -> Void) {
if let credential = self.credential {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@

import Foundation

public typealias EncodeResult = (data: Data?, error: Error?)
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} typealias EncodeResult = (data: Data?, error: Error?)

open class CodableHelper {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class CodableHelper {

public static var dateformatter: DateFormatter?
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} static var dateformatter: DateFormatter?

open class func decode<T>(_ type: T.Type, from data: Data) -> (decodableObj: T?, error: Error?) where T : Decodable {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class func decode<T>(_ type: T.Type, from data: Data) -> (decodableObj: T?, error: Error?) where T : Decodable {
var returnedDecodable: T? = nil
var returnedError: Error? = nil

Expand All @@ -39,7 +39,7 @@ open class CodableHelper {
return (returnedDecodable, returnedError)
}

open class func encode<T>(_ value: T, prettyPrint: Bool = false) -> EncodeResult where T : Encodable {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class func encode<T>(_ value: T, prettyPrint: Bool = false) -> EncodeResult where T : Encodable {
var returnedData: Data?
var returnedError: Error? = nil

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@

import Foundation

open class Configuration {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class Configuration {

// This value is used to configure the date formatter that is used to serialize dates into JSON format.
// You must set it prior to encoding any dates, and it will only be read once.
public static var dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} static var dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"

}
Loading