Networking

SAPURLSession


SAPURLSession is an HTTP networking library. The SAPURLSession component provides an API around the native URLSession, which is similar to the URLSession data task convenience methods. The SAPURLSession component can be used to communicate with an HTTP server. It also provides support for modifying the HTTP request before it is sent, and the HTTP response prior to being returned to the caller. You can register multiple request and response observers to support various scenarios, like authentication, for example.

The primary usage scenario and workflow for this component is that the application:

  1. Creates an SAPURLSession instance
  2. Uses other SDK components to register observers, to handle authentication, for example.
  3. Passes the configured SAPURLSession to SDK components that require HTTP communication, but do not handle aspects such as authentication. In addition, the application can also exchange HTTP messages with this component if required.

Note: The SAPURLSession component does not replace URLSession, but adds additional functionality to it. To use it efficiently, first familiarize yourself with the URLSession API.

Note: The streamTask APIs are not supported through SAPURLSession.

For additional information, see: Using URL Session.

Usage

To use the SAPURLSession component:

  1. Create an SAPURLSession instance.
  2. Exchange HTTP messages with an HTTP server.
  3. Use observers to modify the HTTP request or the response.

Create an SAPURLSession

You have different options to create an SAPURLSession instance. The simplest way is to initialize it using defaults.

let sapSession = SAPURLSession()

Note: When using the default initializer, the SAPURLSession initializes the underlying URLSession with the following parameters:

  • configuration: URLSessionConfiguration.default
  • delegate: nil
  • delegateQueue: nil

You can provide your own URLSessionConfiguration object to configure the SAPURLSession for your needs. This allows tweaking the connectivity of your app on the networking layer, including network timeouts, supported TLS version, etc. You can also use this to indicate the desired quality of service for your app (or parts of the network traffic of your app) in your enterprise WiFi network and prioritize network traffic across your apps and networks in a Fastlane enabled infrastructure.

If you need to be informed about URLSession events, implement the SAPURLSessionDelegate APIs, and pass this delegate as a parameter. You can register this delegate also to obtain the backing URLSessionTask once it is initialized.

let sapSession = SAPURLSession(delegate: self)

Exchange HTTP messages

Once you have created an SAPURLSession you can use it to exchange messages. Depending on your use case, you can either directly use this session or pass it to other SDK components that require an SAPURLSession instance for communication.

The SAPURLSession class exposes methods for sending short requests to the server, and it supports the downloading and uploading of large payloads as well

Sending short requests

To send short requests to the server, use the func dataTask(with:completionHandler:) method to instantiate an SAPURLSessionTask instance. You must start the task by calling its resume() method.

let sapSession = SAPURLSession()
let url = URL(string: "<#URL String#>")!

let task = sapSession.dataTask(with: url) { data, response, error in
  if let httpResponse = response as? HTTPURLResponse {
    // process response, inspect error message
  }
}
task.resume()

Downloading

You can download large amounts of data using the func dataTask(with:receivedResponseHandler:receivedDataHandler:completionHandler:). The downloaded data is retrieved in batches via the receivedDataHandler handler.

let sapSession = SAPURLSession()
let url = URL(string: "<#URL String#>")!
let request = URLRequest(url: url)

let dataTask = sapSession.dataTask(with: request, receivedResponseHandler: { response in
  // process response
}, receivedDataHandler: { data in
  // process data batches
}) { error in
  // error handling
}
dataTask.resume()

Uploading

To upload larger amounts of data to a server, use the func uploadTask(withStreamedRequest:needNewBodyStream:completionHandler:) as follows:

let sapSession = SAPURLSession()

let url = URL(string: "<#URL String#>")!
var request = URLRequest(url: url)
request.httpMethod = SAPURLSession.HTTPMethod.put

let uploadTask = sapSession.uploadTask(withStreamedRequest: request, needNewBodyStream: {
  return InputStream(fileAtPath: path)
}) { data, response, error in
  // error handling, response processing
  if let httpResponse = response as? HTTPURLResponse {
    // process response
  }
}
uploadTask.resume()

Using Observers

You can use observers to modify the HTTP requests before they are sent, and to modify the HTTP responses after they have been received. For that you can register the SAPURLSessionObserving implementations on the SAPURLSession, so that the registered observers are called each time this session is used to exchange HTTP messages:

class MySAPURLSessionObserver: SAPURLSessionObserving {
  func sapURLSession(_ session: SAPURLSession, task: SAPURLSessionTask, willSend request: URLRequest, completionHandler: @escaping (SAPURLSession.RequestDisposition) -> Void) -> Void {
    var updatedRequest = request
    updatedRequest.addValue("MyHeaderValue", forHTTPHeaderField: "MyHeaderKey")
    completionHandler(.allow(updatedRequest))
  }

  func func sapURLSession(_ session: SAPURLSession, dataTask: SAPURLSessionTask, didReceive response: URLResponse, completionHandler: @escaping (SAPURLSession.ResponseDisposition) -> Void) {
    completionHandler(.allow(response))
  }
}

let sapSession = SAPURLSession()
let observer = MySAPURLSessionObserver()
sapSession.register(observer)

Note: When implementing the SAPURLSessionObserving protocol you have the option to implement only the methods you want to use. This is possible because all of them have default implementation via protocol extension. The compiler will not signal errors if you have a typo in the method implementation! Because there is a default implementation, it will call the one that matches. The best way to implement these methods is to use Xcode’s code completion.

The observers have all of the delegate methods (except URLSessionStreamDelegate) on them, with completion handler. See the API documentation for further information.

The registered observers are called in the registration order. They contain asynchronous methods, which means that their completionHandler must be called. The SAPURLSessionDelegate is called after the observers.

When a delegate with completionHandler is called, the SAPURLSession will start to call the observers in the registration order. This iteration continues until one of the observer responds with a non-default value (such as an error response or authentication challenge response). After a non-default response from an observer, the iteration is stopped, and the rest of the observers, including the delegate (SAPURLSessionDelegate), will not be called.

The registered observer can be called multiple times during a single request. This is because of the possibility of one observer starting an internal request. Use the SAPURLSession.context to mark your requests or find a different way to identify whether or not your observer has to run for the given iteration. (The SAPURLSession.context is a simple [String: Any] dictionary.)

Calling the completionHandler

There are different dispositions for different observer methods with which the completionHandler must be called. See the API documentation for more information.

  • SAPURLSession.RequestDisposition
  • SAPURLSession.ResponseDisposition
  • SAPURLSession.CancellableDisposition
  • SAPURLSession.DataDisposition
  • SAPURLSession.AuthChallengeDisposition
  • SAPURLSession.HTTPRedirectDisposition
  • SAPURLSession.InputStreamDisposition
  • SAPURLSession.CacheResponseDisposition
  • SAPURLSession.DelayedRequestDisposition

Authentication challenge

The existing SAPURLSession implementation augments URLSession. URLSession provides the means for basic authentication, therefore the SDK does not expose any new functionality (API, observers, etc.).

To receive authentication challenges, clients must pass in an SAPURLSessionDelegate when initializing the SAPURLSession.

let sapSession = SAPURLSession(delegate: self)

The provided delegate implements the func sapURLSession(session:dataTask:didReceive:completionHandler:) delegate method, and handles the challenge accordingly.

For more information about this delegate, please see the Apple Reference: https://developer.apple.com/reference/foundation/urlsessiontaskdelegate/1411595-urlsession

Basic Authentication

The credential is based on username/password in the func sapURLSession(session:dataTask:didReceive:completionHandler:) delegate method.

This example creates a URLCredential from a username and password:

let urlCredential = URLCredential(user: "<#Username#>", password: "<#Password#>", persistence: .none)

Certificate Authentication

The credential is based on a certificate in the func sapURLSession(session:dataTask:didReceive:completionHandler:) delegate method.

This example creates a URLCredential from a PKCS#12 file:

let path = Bundle.main.path(forResource: <#Filename#>, ofType: "p12")!
let data = NSData(contentsOfFile:path)! as Data
var items: CFArray?
let certOptions:NSDictionary = [kSecImportExportPassphrase as NSString:<#password#> as NSString]
var urlCredential: URLCredential!
var securityError = errSecSuccess
securityError = SecPKCS12Import(data as NSData, certOptions, &items)
switch securityError {
case errSecDecode:
  // Either the PKCS#12 formatted blob can't be read or it is malformed.
case errSecAuthFailed:
  // An incorrect password was passed, or data in the container got damaged.
default:
  let certItems = (items! as Array)
  let dict = certItems.first! as! Dictionary<String, AnyObject>
  let certChain = dict[kSecImportItemCertChain as String] as? Array<SecTrust>
  let identity = dict[kSecImportItemIdentity as String] as! SecIdentity?
  urlCredential = URLCredential(identity: identity!, certificates: certChain!, persistence: URLCredential.Persistence.forSession)
}
return urlCredential

Communicating with SAPcpms services

SAPcpms services need a X-SMP-APPID header for the requests, which sets up the session to identify the app that is connecting to SAPcpms. In addition, an optional device ID can also be sent in a X-SMP-DEVICEID header. These headers can be set using SAPcpmsObserver.

The code sample below demonstrates how to register the observer to an SAPURLSession instance.

let applicationID = <#Application ID#>
let deviceID = <#Device ID#>
let applicationVersion = <#Application version#>

let sapcpmsObserver = SAPcpmsObserver(applicationID: applicationID, deviceID: deviceID, applicationVersion: applicationVersion)

sapSession.register(sapcpmsObserver)

CSRF protection of SAPcpms services

Note: If you want to use CSRF protection for your application, you must first enable this feature in the SAP Cloud Platform Mobile Services cockpit. See: Defining Applications.

If the CSRF protection is enabled on SAPcpms, you need to send a X-CSRF-Token header for the modifying HTTP requests. The CSRFTokenObserver can automatically handle this for every request.

Basic usage

The code sample below demonstrates how to register the observer to an SAPURLSession instance if you have one root URL for every CSRF token request. The rootUrl parameter is the URL from which the CSRF token will be requested.

let urlSession: SAPURLSession = <#SAPURLSession instance#>
let rootUrl: URL = <#your root URL#>

let csrfTokenObserver = CSRFTokenObserver(rootUrl: rootUrl)
urlSession.register(csrfTokenObserver)

Advanced usage

If you have multiple CSRF protected backends and these backends accept different CSRF tokens, you must implement the CSRFTokenURLProviding protocol to provide a CSRF URL for different request URLs. For token storing, the CSRFTokenStoring protocol is used.

class myCSRFTokenURLProvider: CSRFTokenURLProviding {
  func csrfTokenURL(for: URL) -> URL {
    // TODO: implement custom logic to create token URL from the request URL
    return <#token URL#>
  }
}

public class myCSRFTokenStore: CSRFTokenStoring {
  /// Stores the CSRF token for the given URL.
  public func store(token: String, for url: URL) {
    // TODO: implement
  }

  /// Retrieves the CSRF token for the given URL.
  public func token(for url: URL) -> String? {
    // TODO: implement
    return <#token URL#>
  }

  /// Deletes the CSRF token for the given URL.
  public func deleteToken(for url: URL) {
    // TODO: implement
  }
}

let csrfTokenObserver = CSRFTokenObserver(tokenUrlProvider: myCSRFTokenURLProvider, tokenStore: myCSRFTokenStore)
urlSession.register(csrfTokenObserver)

For more information on how this protection works, see: Using Custom Header Protection

NetworkActivityIndicatorController

Controls whether the Network Activity Indicator should be showed or hidden. When you use NetworkActivityIndicatorObserver, never modify the NetworkActivityIndicatorController directly, but use the observer class instead. The component uses an internal counter. When this counter has a positive value, the indicator is visible.

NetworkActivityIndicatorObserver

Shows and hides the Network Activity Indicator automatically based on the states of requests in the URLSession. It presents the indicator when a request starts, and hides it when the request finished. The state of the ActivityIndicator is shared among all the URLSession and observer instances. The observer uses the NetworkActivityIndicatorController to control the presentation of the indicator. When you use this observer, never modify the Network Activity Indicator directly, but use the NetworkActivityIndicatorController instead.

For example:

let indicatorObserver = NetworkActivityIndicatorObserver()
sapURLSession.register(indicatorObserver)

Add correlation ID to requests

Correlation IDs are used to identify and track requests on the server side. Adding CorrelationObserver to an SAPURLSession will automatically generate a unique correlation ID and add it to each request. In case the SAPURLSessionTask is resent, the same correlation ID will be used. The code sample below demonstrates how to register the observer to an SAPURLSession instance.

let correlationObserver = CorrelationObserver()
sapURLSession.register(correlationObserver)

Detect blocked users

You can block users using SAP Cloud Platform Mobile Services if you don’t want them to have further access to your resources. To be able to detect such action in your application, use the SAPcpmsUserBlockedObserver.

let blockDetectionObserver = SAPcpmsUserBlockedObserver { error in
  // This block of code is invoked when a blocked response is detected.
  // The error is a `SAPcpmsUserBlockedError` describing the specific case.
  <#Notify the user about the blocking and run some clean-up code.#>
}
sapURLSession.register(blockDetectionObserver)

Add Accept-Language header to requests

Adding LanguageObserver to an SAPURLSession will automatically set the Accept-Language headers to each HTTP request. By default it uses the device language, but you can also force a language by adding the language parameter to the initializer.

let urlSession: SAPURLSession = <#SAPURLSession instance#>

let languageObserver = LanguageObserver()
urlSession.register(languageObserver)

Clear all authentication credentials

There are several steps required to remove all authentication credentials.

After onboarding remove cookies from HTTPCookieStorage and remove all cached responses from URLCache

sapURLSession.configuration.urlCache?.removeAllCachedResponses()
sapURLSession.configuration.httpCookieStorage?.removeCookies(since: .distantPast)

Credential store

Remove all keys with the prefix of the authentication process.

Web Content Based CPms Destinations

This section highlights how each iOS web view can be used with SAP CPms destinations that contain web-based contents (e.g. an HTML web page). SAPURLSession provides the following APIs for this purpose:

public func configure(_ request: URLRequest, completionHandler: @escaping (URLRequest?, Error?) -> Void)
public func configure(_ webView: WKWebView, completionHandler: @escaping (Error?) -> Void)
public func configure(_ cookieStore: HTTPCookieStorage, completionHandler: @escaping (Error?) -> Void)
public func configure(_ cookieStore: WKHTTPCookieStore, completionHandler: @escaping (Error?) -> Void)
public func close(completionHandler: @escaping () -> Void)

A convenience API is also available on WKWebView:

public func configure(with urlSession: SAPURLSession, completionHandler: @escaping () -> Void)

WKWebView

WKWebView supports both custom cookie configuration and loading URL requests.

Customizing cookies can be useful for web session management. The code snippet below shows how to do this using the convenience API.

let sapURLSession = SAPURLSession()
let webView = WKWebView(frame: .zero)
webView.configure(from: sapURLSession) {
  // cookies have been set
}

Configuring a URLRequest instance should be used at all times because CPms destinations require special headers in the requests.

let sapURLSession = SAPURLSession()
sapURLSession.configure(request) { newRequest, error in
    switch (newRequest, error) {
    case (nil, let error?):
        // error handling
    case (let newRequest?, nil):
        // load newRequest
    default:
        fatalError("Invalid state!")
    }
}

ASWebAuthenticationSession, SFSafariViewController

Neither ASWebAuthenticationSession nor SFSafariViewController were designed to be customized. Both of these web views support loading URLs – not URLRequests. Manual cookie configuration is a bit tricky as well. Both web views use the shared cookie storage, which leads to the conclusion that if cookie management is a requirement, the shared store should be configured. Use the corresponding configure(_:) API for this purpose. After a web session is over (the web view is closed), the original cookies should be reset for security reasons: use the close(completionHandler:) API in this case.

SFAuthenticationSession, UIWebView

Both UIWebView and SFAuthenticationSession are removed.

Using Combine DataTaskPublisher in SAPURLSession

Similar to URLSession, SAPURLSession offers a Combine publisher, SAPURLSession.DataTaskPublisher, which publishes the results of fetching data from a URL or URLRequest. You create this publisher with the method dataTaskPublisher(for:).

 public func dataTaskPublisher(for urlRequest: URLRequest) -> DataTaskPublisher
 public func dataTaskPublisher(for url: URL) -> DataTaskPublisher

When the task completes, it publishes either:

  • A tuple that contains the fetched data and a URLResponse, if the task succeeds.

  • An error, if the task fails.

Unlike the completion handler passed to dataTask(with:completionHandler:), the types received by your code aren’t optionals, since the publisher has already unwrapped the data or error.

When using SAPURLSession’s completion handler-based code, you need to do all your work in the handler closure: error-handling, data parsing, and so on. When you instead use the data task publisher, you can move many of these responsibilities to Combine operators.

When a data task completes successfully, it delivers a block of raw Data to your app. Most apps need to convert this data to their own types. Combine provides operators to perform these conversions, allowing you to declare a chain of processing operations.

The data task publisher produces a tuple that contains a Data and a URLResponse. You can use the map(:) operator to convert the contents of this tuple to another type. If you want to inspect the response before inspecing the data, use tryMap(:) and throw an error if the response is unacceptable.

To convert raw data to your own types that conform to the Decodable protocol, use Combine’s decode(type:decoder:) operator.

Once we’ve created a publisher, we can then attach subscriptions to it, for example by using the sink API — which lets us pass a closure to be called whenever a new value was received, as well as one that’ll be called once the publisher was completed:

The following example combines both these operators to parse JSON data from a URL endpoint into a custom User type:

 struct User: Codable {
    let name: String
    let userID: String
}
let url = URL(string: "https://example.com/endpoint")!
let sapurlSession = SAPURLSession()
cancellable = sapurlSession
    .dataTaskPublisher(for: url)
    .tryMap() { element -> Data in
        guard let httpResponse = element.response as? HTTPURLResponse,
            httpResponse.statusCode == 200 else {
                throw URLError(.badServerResponse)
            }
        return element.data
        }
    .decode(type: User.self, decoder: JSONDecoder())
    .sink(receiveCompletion: { print ("Received completion: \($0).") },
          receiveValue: { user in print ("Received user: \(user).")})

Also the observers that you attach for SAPURLSession will also get called during its course, when dataTaskPublisher is used.

Additional Information

SAPURLSession component Logger ID

This component uses the following name prefix for logging: ‘SAP.Foundation.SAPURLSession’

  • This class represents a client that can be used to communicate with an HTTP server. It wraps the native URLSession.

    You have different options to create a SAPURLSession instance. The simplest way is to initialize it using defaults.

    let urlSession = SAPURLSession()
    

    Note: When using the default initializer, the SAPURLSession initilizes the underlying URLSession with the following parameters:

    • configuration: URLSessionConfiguration.default
    • delegate: nil
    • delegateQueue: nil

    If you need to be informed about URLSession events, implement the SAPURLSessionDelegate APIs, and pass this delegate as a parameter. You can register this delegate also to obtain the backing URLSessionTask once its initialized.

    let urlSession = SAPURLSession(delegate: self)
    

    Once you have created an SAPURLSession you can use it to exchange messages. Depending on your use case you can either directly use this session or pass it to other SDK components that require an SAPURLSession instance for communication.

    The SAPURLSession class exposes methods for sending short requests to the server, and it supports downloading and uploading of large payloads as well.

    See more

    Declaration

    Swift

    public class SAPURLSession
  • This class is a wrapper class on top of URLSessionTask.

    See more

    Declaration

    Swift

    public class SAPURLSessionTask
  • CorrelationObserver

    Generates and adds a unique identifier to the requests of a SAPURLSessionTask. In case the task will resend the same correlationID will be used. The correlationID will be logged out to the logs with Logger under the component SAP.Foundation.SAPURLSession.CorrelationObserver‘ The code snippet below demonstrates how to use it:

    let correlationObserver = CorrelationObserver()
    sapURLSession.register(correlationObserver)
    
    See more

    Declaration

    Swift

    open class CorrelationObserver : SAPURLSessionObserving
  • This observer is responsible to set the required X-CSRF-Token header for communication with services exposed by SAPcpms. To enable this functionality you need to register this observer to an SAPURLSession instance. For token storing the CSRFTokenStoring protocol is used.

    This is an example for a basic usage of this observer if you have one root URL for every CSRF token request: The rootUrl parameter is the URL from which the CSRF token will be requested.

    let urlSession: SAPURLSession = <#SAPURLSession instance#>
    let rootUrl: URL = <#your root URL#>
    
    let csrfTokenObserver = CSRFTokenObserver(rootUrl: rootUrl)
    urlSession.register(csrfTokenObserver)
    
    

    If you have multiple CSRF protected backends and these backends accept different CSRF tokens you must implement CSRFTokenURLProviding protocol to provide CSRF URL for different request URL’s. For token storing the CSRFTokenStoring protocol is used.

    class myCSRFTokenURLProvider: CSRFTokenURLProviding {        
        func csrfTokenURL(for: URL) -> URL {
            // implement custom logic to create token URL from the request URL
            // ...
            return <#token URL#>
        }
    }
    
    let csrfTokenObserver = CSRFTokenObserver(tokenUrlProvider: myCSRFTokenURLProvider, tokenStore: myCSRFTokenStore)
    urlSession.register(csrfTokenObserver)
    
    
    See more

    Declaration

    Swift

    public class CSRFTokenObserver : SAPURLSessionObserving
  • This observer is responsible to set the Accept-Language headers to each HTTP request of the SAPURLSession.

    To enable this functionality you need to register this observer to an SAPURLSession instance.

    This is an example for a typical usage of the observer:

    let urlSession: SAPURLSession = <#SAPURLSession instance#>
    
    let languageObserver = LanguageObserver()
    urlSession.register(languageObserver)
    
    See more

    Declaration

    Swift

    open class LanguageObserver : SAPURLSessionObserving
  • NetworkActivityIndicatorObserver

    Shows and hides the Network Activity Indicator automatically, based on the states of requests in the SAPURLSession. It presents the indicator when a request starts and hides it when the request finished. The state of the ActivityIndicator is shared among all the SAPURLSession and SAPURLSessionObserving instances. The observer uses the NetworkActivityIndicatorController to control the presentation of the indicator. When you use this observer never modify the Network Activity Indicator directly but use the NetworkActivityIndicatorController.

    The code snippet below demonstrates how to use it:

    let indicatorObserver = NetworkActivityIndicatorObserver()
    sapURLSession.register(indicatorObserver)
    
    See more

    Declaration

    Swift

    open class NetworkActivityIndicatorObserver
  • This observer is responsible to set required headers for communication with services exposed by SAPcpms. This includes the X-SMP-APPID and X-SMP-DEVICEID header fields, which are added to each HTTP request of the SAPURLSession.

    To enable this functionality you need to register this observer to an SAPURLSession instance.

    This is an example for a typical usage of the observer:

    let urlSession: SAPURLSession = <#SAPURLSession instance#>
    let applicationID: String = <#application_ID#>
    let deviceID: String? = <#device_ID#>
    let applicationVersion: String? = <#application_Version#>
    
    let observer = SAPcpmsObserver(applicationID: applicationID, deviceID: deviceID, applicationVersion: applicationVersion)
    urlSession.register(observer)
    
    See more

    Declaration

    Swift

    public class SAPcpmsObserver : SAPURLSessionObserving
  • Use this observer to detect user blocked errors from SAPcpms. When a blocked response is detected, the provided handler is called with the specific blocking case - see SAPcpmsUserBlockedError for more information. The observer is in silent mode after this detection and will remain in this mode until a non-blocking response is detected. The observer will not call the provided handler while in silent mode. All requests that are detected as blocking ones will result in the appropriate SAPcpmsUserBlockedError error.

    See more

    Declaration

    Swift

    open class SAPcpmsUserBlockedObserver : SAPURLSessionObserving
  • Set of errors to signal the blocked user.

    • traffic: traffic is blocked
    • trafficAndRegistration: traffic and registration both blocked
    • registration: registration blocked
    See more

    Declaration

    Swift

    public enum SAPcpmsUserBlockedError : Error
  • NetworkActivityIndicatorController

    Controls whether the Network Activity Indicator should be showed or hidden. When you use NetworkActivityIndicatorObserver, never modify the Network Activity Indicator directly - use this class instead. The component uses a counter internally. When this counter has a positive value the indicator is visible.

    See more

    Declaration

    Swift

    public class NetworkActivityIndicatorController
  • The SAP implemented HTTPCookieStorage which can be used with instances of SAPURLSession. The store can be initialized with a CodableStoring instance which makes it capable to persist cookies between application runs. This implementation won’t share the non-session cookies among the other SAPHTTPCookieStorage instances.

    Example:

    let sessionConfiguration = URLSessionConfiguration.default
    sessionConfiguration.httpCookieStorage = sapCookieStorage
    let sapUrlSession = SAPURLSession(configuration: sessionConfiguration)
    
    See more

    Declaration

    Swift

    public class SAPHTTPCookieStorage : HTTPCookieStorage
  • The SAPURLSessionDelegate protocol describes the methods that SAPURLSession objects call on their delegates to handle session- and task-level events.

    See more

    Declaration

    Swift

    public protocol SAPURLSessionDelegate : AnyObject
  • Defines a protocol which is capable of storing CSRF tokens.

    See more

    Declaration

    Swift

    public protocol CSRFTokenStoring
  • Defines a protocol which is capable of providing CSRF URL for every request URL.

    See more

    Declaration

    Swift

    public protocol CSRFTokenURLProviding