Bruno Coelho 2354d402a8
[swift6] promote to beta and improve documentation (#19856)
* [swift6] promote to beta

* [swift6] format code

* [swift] authentication docs

* [swift] update docs

* [swift] update docs

* [swift] update docs

* [swift] update docs

* [swift] update docs

* [swift] update docs

* [swift] update docs

* [swift] update docs

* [swift] update docs

* [swift] update docs
2024-10-14 12:55:25 +01:00

14 KiB

Swift5 API client for PetstoreClient

This spec is mainly for testing Petstore server and contains fake endpoints, models. Please do not use this for any other purpose. Special characters: " \

Overview

This API client was generated by the OpenAPI Generator project. By using the openapi-spec from a remote server, you can easily generate an API client.

  • API version: 1.0.0
  • Package version:
  • Generator version: 7.10.0-SNAPSHOT
  • Build package: org.openapitools.codegen.languages.Swift5ClientCodegen

Installation

Carthage

Run carthage update

CocoaPods

Run pod install

Documentation for API Endpoints

All URIs are relative to http://petstore.swagger.io:80/v2

Class Method HTTP request Description
AnotherFakeAPI call123testSpecialTags PATCH /another-fake/dummy To test special tags
FakeAPI fakeOuterBooleanSerialize POST /fake/outer/boolean
FakeAPI fakeOuterCompositeSerialize POST /fake/outer/composite
FakeAPI fakeOuterNumberSerialize POST /fake/outer/number
FakeAPI fakeOuterStringSerialize POST /fake/outer/string
FakeAPI testBodyWithFileSchema PUT /fake/body-with-file-schema
FakeAPI testBodyWithQueryParams PUT /fake/body-with-query-params
FakeAPI testClientModel PATCH /fake To test "client" model
FakeAPI testEndpointParameters POST /fake Fake endpoint for testing various parameters 假端點 偽のエンドポイント 가짜 엔드 포인트
FakeAPI testEnumParameters GET /fake To test enum parameters
FakeAPI testGroupParameters DELETE /fake Fake endpoint to test group parameters (optional)
FakeAPI testInlineAdditionalProperties POST /fake/inline-additionalProperties test inline additionalProperties
FakeAPI testJsonFormData GET /fake/jsonFormData test json serialization of form data
FakeClassnameTags123API testClassname PATCH /fake_classname_test To test class name in snake case
PetAPI addPet POST /pet Add a new pet to the store
PetAPI deletePet DELETE /pet/{petId} Deletes a pet
PetAPI findPetsByStatus GET /pet/findByStatus Finds Pets by status
PetAPI findPetsByTags GET /pet/findByTags Finds Pets by tags
PetAPI getPetById GET /pet/{petId} Find pet by ID
PetAPI updatePet PUT /pet Update an existing pet
PetAPI updatePetWithForm POST /pet/{petId} Updates a pet in the store with form data
PetAPI uploadFile POST /pet/{petId}/uploadImage uploads an image
PetAPI uploadFileWithRequiredFile POST /fake/{petId}/uploadImageWithRequiredFile uploads an image (required)
StoreAPI deleteOrder DELETE /store/order/{order_id} Delete purchase order by ID
StoreAPI getInventory GET /store/inventory Returns pet inventories by status
StoreAPI getOrderById GET /store/order/{order_id} Find purchase order by ID
StoreAPI placeOrder POST /store/order Place an order for a pet
UserAPI createUser POST /user Create user
UserAPI createUsersWithArrayInput POST /user/createWithArray Creates list of users with given input array
UserAPI createUsersWithListInput POST /user/createWithList Creates list of users with given input array
UserAPI deleteUser DELETE /user/{username} Delete user
UserAPI getUserByName GET /user/{username} Get user by user name
UserAPI loginUser GET /user/login Logs user into the system
UserAPI logoutUser GET /user/logout Logs out current logged in user session
UserAPI updateUser PUT /user/{username} Updated user

Documentation For Models

Documentation For Authorization

Authentication schemes defined for the API:

petstore_auth

api_key

  • Type: API key
  • API key parameter name: api_key
  • Location: HTTP header

api_key_query

  • Type: API key
  • API key parameter name: api_key_query
  • Location: URL query string

http_basic_test

  • Type: HTTP basic authentication

How do I implement bearer token authentication with URLSession on the Swift 5 API client?

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

Author