{"id":19622178,"url":"https://github.com/commercetools/commercetools-ios-sdk","last_synced_at":"2025-07-23T17:36:13.145Z","repository":{"id":49725182,"uuid":"55976787","full_name":"commercetools/commercetools-ios-sdk","owner":"commercetools","description":"The e-commerce iOS SDK from commercetools.","archived":false,"fork":false,"pushed_at":"2022-02-04T15:42:44.000Z","size":684,"stargazers_count":21,"open_issues_count":3,"forks_count":10,"subscribers_count":83,"default_branch":"master","last_synced_at":"2025-07-18T05:09:09.272Z","etag":null,"topics":["audit-sdk"],"latest_commit_sha":null,"homepage":"https://docs.commercetools.com/sdk/swift-sdk","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/commercetools.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-04-11T13:57:03.000Z","updated_at":"2024-05-02T11:57:42.000Z","dependencies_parsed_at":"2022-09-12T23:21:46.774Z","dependency_job_id":null,"html_url":"https://github.com/commercetools/commercetools-ios-sdk","commit_stats":null,"previous_names":[],"tags_count":37,"template":false,"template_full_name":null,"purl":"pkg:github/commercetools/commercetools-ios-sdk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/commercetools%2Fcommercetools-ios-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/commercetools%2Fcommercetools-ios-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/commercetools%2Fcommercetools-ios-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/commercetools%2Fcommercetools-ios-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/commercetools","download_url":"https://codeload.github.com/commercetools/commercetools-ios-sdk/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/commercetools%2Fcommercetools-ios-sdk/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266720905,"owners_count":23974060,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-23T02:00:09.312Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["audit-sdk"],"created_at":"2024-11-11T11:26:28.046Z","updated_at":"2025-07-23T17:36:13.120Z","avatar_url":"https://github.com/commercetools.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Commercetools Swift SDK\n\n\u003cimg src=\"https://user-images.githubusercontent.com/14024032/60341258-32f83f80-99ae-11e9-86c0-1eb52f201a0d.png\" height=\"80\" /\u003e\n\n\u003cp\u003e\n\u003ca href=\"https://travis-ci.com/commercetools/commercetools-ios-sdk\" target=\"_blank\"\u003e\n\u003cimg src=\"https://travis-ci.com/commercetools/commercetools-ios-sdk.svg?branch=master\"\u003e\n\u003c/a\u003e\n\u003ca href=\"http://cocoadocs.org/docsets/Commercetools\" target=\"_blank\"\u003e\n\u003cimg src=\"https://img.shields.io/cocoapods/v/Commercetools.svg\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://developer.apple.com/swift/\" target=\"_blank\"\u003e\n\u003cimg src=\"https://img.shields.io/badge/Swift-5.1-orange.svg?style=flat\" alt=\"Swift 5.1\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://developer.apple.com/swift/\" target=\"_blank\"\u003e\n\u003cimg src=\"https://img.shields.io/badge/Platforms-iOS%20%7C%20macOS%20%7C%20watchOS%20%7C%20tvOS%20%7C%20Linux-4E4E4E.svg?colorA=EF5138\" alt=\"Platforms iOS | macOS | watchOS | tvOS | Linux\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://github.com/apple/swift-package-manager\" target=\"_blank\"\u003e\n\u003cimg src=\"https://img.shields.io/badge/SPM-compatible-brightgreen.svg?style=flat\u0026colorB=64A5DE\" alt=\"SPM compatible\"\u003e\n\u003c/a\u003e\n\u003ca href=\"LICENSE\" target=\"_blank\"\u003e\n\u003cimg src=\"https://img.shields.io/badge/License-Apache%202-blue.svg\"\u003e\n\u003c/a\u003e\n\u003c/p\u003e\n\n## Installation\n\n### Requirements\n\n- iOS 10.0+ / macOS 10.10+ / tvOS 9.0+ / watchOS 2.0+\n- Xcode 11.0+\n- Swift 5.1+\n\n### CocoaPods\n\n[CocoaPods](http://cocoapods.org) is a dependency manager for Cocoa projects. You can install it with the following command:\n\n```bash\n$ gem install cocoapods\n```\n\n\u003e CocoaPods 1.2.1+ is required to build CommercetoolsSDK 0.7+.\n\nTo integrate CommercetoolsSDK into your Xcode project using CocoaPods, specify it in your `Podfile`:\n\n```ruby\nsource 'https://github.com/CocoaPods/Specs.git'\nplatform :ios, '10.0'\nuse_frameworks!\n\npod 'Commercetools', '~\u003e 0.12'\n```\n\nThen, run the following command:\n\n```bash\n$ pod install\n```\n\n## Getting Started\n\nThe Commercetools SDK uses a `.plist` configuration file named `CommercetoolsConfig.plist` to gather all information needed to communicate with the commercetools platform.\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003c!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"\u003e\n\u003cplist version=\"1.0\"\u003e\n\u003cdict\u003e\n\t\u003ckey\u003eprojectKey\u003c/key\u003e\n\t\u003cstring\u003eYour Project Key\u003c/string\u003e\n\t\u003ckey\u003eclientId\u003c/key\u003e\n\t\u003cstring\u003eYour Client ID\u003c/string\u003e\n\t\u003ckey\u003eclientSecret\u003c/key\u003e\n\t\u003cstring\u003eYour Client Secret\u003c/string\u003e\n\t\u003ckey\u003escope\u003c/key\u003e\n\t\u003cstring\u003eYour Client Scope\u003c/string\u003e\n\t\u003ckey\u003eauthUrl\u003c/key\u003e\n\t\u003cstring\u003eAuthorization Url/\u003c/string\u003e\n\t\u003ckey\u003eapiUrl\u003c/key\u003e\n\t\u003cstring\u003eAPI Url\u003c/string\u003e\n\t\u003ckey\u003emachineLearningApiUrl\u003c/key\u003e\n    \u003cstring\u003eMachine Learning API\u003c/string\u003e\n\t\u003ckey\u003eanonymousSession\u003c/key\u003e\n    \u003ctrue/\u003e\n    \u003ckey\u003ekeychainAccessGroupName\u003c/key\u003e\n    \u003cstring\u003eAB123CDEF.yourKeychainGroup\u003c/string\u003e\n    \u003ckey\u003eshareWatchSession\u003c/key\u003e\n    \u003ctrue/\u003e\n    \u003ckey\u003eemergencyContactInfo\u003c/key\u003e\n    \u003cstring\u003eyou@yourdomain.com\u003c/string\u003e\n    \u003ckey\u003estoreKey\u003c/key\u003e\n    \u003cstring\u003eyour-global-store-key\u003c/string\u003e\n\u003c/dict\u003e\n\u003c/plist\u003e \n```\n\nAlternatively, you can specify a path to different `.plist` file containing these properties.\n\nYou can also download the configuration `.plist` for your client from the Merchant Center [API Clients](https://docs.commercetools.com/merchant-center/api-clients) section, at the time of creation, by selecting the iOS template from the drop down menu.\n\nBefore using any methods from the Commercetools SDK, please make sure you have previously set the desired configuration.\n```swift\nimport Commercetools\n\n// Default configuration initializer reads from CommercetoolsConfig.plist file from your app bundle\nif let configuration = Config() {\n    \n    // You can also specify custom logging level\n    // configuration.logLevel = .error\n    \n    // Or completely disable all log messages from Commercetools SDK\n    // configuration.loggingEnabled = false\n    \n    // Finally, you need set your configuration before using the SDK\n    Commercetools.config = configuration\n    \n} else {\n    // There are some errors in your .plist file, check log messages for more information\n}\n```\n\n## Authenticated and Anonymous Usage\n\nEndpoints from the Commercetools services can be consumed without Checkout (`PlainToken`), with Guest Checkout (`AnonymousToken`) or with a logged in customer (`CustomerToken`). According to the configuration, all interactions with the Commercetools platform will be performed with a `PlainToken` or a `AnonymousToken` per default.\n\nIf at some point you wish to login the user, that can be achieved using `loginUser` method:\n\n```swift\nlet username = \"swift.sdk.test.user@commercetools.com\"\nlet password = \"password\"\n\nCommercetools.loginCustomer(username, password: password, completionHandler: { result in\n    if let error = result.errors?.first as? CTError, case .accessTokenRetrievalFailed(let reason) = error {\n        // Handle error, and possibly get some more information from reason.message\n    }\n})\n```\n\nSimilarly, after logging out, all further interactions continue to use new anonymous user token.\n\n```swift\nCommercetools.logoutCustomer()\n```\n\nAccess and refresh tokens are being preserved across app launches. In order to inspect whether it's currently handling authenticated or anonymous user, `authState` property should be used:\n\n```swift\nif Commercetools.authState == .plainToken {\n    // Present login form or other logic\n}\n```\nIn order for your app to support anonymous session, you should set the `anonymousSession` bool property in your configuration `.plist` file to `true`. Additionally, it is possible to override this setting, and also provide optional custom `anonymous_id` (for metrics and tracking purposes) by invoking:\n```swift\nCommercetools.obtainAnonymousToken(usingSession: true, anonymousId: \"some-custom-id\", completionHandler: { error in\n    if error == nil {\n        // It is possible for token retrieval to fail, e.g custom token ID has already been taken,\n        // in which case reason.message from the returned CTError instance is set to the anonymousId is already in use.\n    }\n})\n```\nWhen an anonymous sessions ends with a sign up or a login, carts and orders are migrated to the customer, and `CustomerSignInResult` is returned, providing access to both customer profile, and the currently active cart. For the login operation, you can define how to migrate line items from the currently active cart, by explicitly specifying one of two `AnonymousCartSignInMode` values: `.mergeWithExistingCustomerCart` or `.useAsNewActiveCustomerCart`.\n\n## In-Store Customers\n\nWhen using stores, a customer can either register globally, or have a registration specific to a store. In the latter case, to login customer in a store, a `storeKey` parameter needs to be set:\n\n```swift\nlet username = \"swift.sdk.test.in.store.user@commercetools.com\"\nlet password = \"password\"\n\nCommercetools.loginCustomer(username, password: password, storeKey: \"store-key\", completionHandler: { result in\n    if let error = result.errors?.first as? CTError {\n        // Handle error, and possibly get some more information from reason.message\n    }\n})\n```\n\nIf the app is only going to work with a specific store, it is recommended that the global store key is set as a part of the configuration `.plist` file. That way, the SDK will use the `storeKey` for all subsequent requests, for store-specific endpoints.\n\n## External OAuth tokens\n\nCommercetools platform and the SDK provides the ability to use external OAuth tokens. In order to set a token from your app, use `Commercetools.externalToken` property. Once set, this token will be used for all platform requests from the SDK. In order to stop using external token, simply set this value to `nil`.\n\nWhen using an external token, it is important to handle expired and invalid token scenarios manually. Completion handler will provide a `CTError` with additional information, and the client should decide whether a token needs to be refreshed, or a recovery is not possible (e.g deleted account).\n\nTo get more information on setting up and using external OAuth with commercetools platform, please refer to [this page](https://docs.commercetools.com/http-api-authorization#requesting-an-access-token-using-an-external-oauth-server-beta).\n\n## Using the SDK in App Extensions\n\nIf your app has extensions, and you want to use Commercetools SDK in those extensions, we recommend enabling keychain sharing. By allowing keychain sharing, and setting the appropriate access group name in the configuration `.plist`, the SDK will save all tokens in the shared keychain. Be sure to include _App ID Prefix / Team ID_ in the access group name.\nAs a result, you can use all endpoints with the same authorization state and tokens in both your app and any extension. The same goes for multiple apps from your development team using keychain sharing.\n\n## Using the SDK on watchOS\n\nSince the keychain on Apple Watch contains a distinct set of entries from the keychain on the paired iPhone, sharing the same customer session between iOS and watchOS is not possible by setting the `keychainAccessGroupName` in the configuration `.plist`. Instead, the Commercetools SDK uses WatchConnectivity to transfer access tokens from an iPhone to an Apple Watch, where they are also stored securely in the watchOS keychain. The only step you have to take to opt in, is to set the `shareWatchSession` configuration property to `true`.\n\nA common way for users to log in on Apple Watch is via the iPhone app. The watchOS SDK will post a notification when the access tokens have been received from the iOS app, so you can check the new `authState` and perform UI changes accordingly.\n```swift\nNotificationCenter.default.addObserver(self, selector: #selector(checkAuthState), name: Notification.Name.WatchSynchronization.DidReceiveTokens, object: nil)\n\nfunc checkAuthState() {\n    if Commercetools.authState == .customerToken {\n        // The customer is logged in, present the appropriate screen\n    } else {\n        // The customer is not logged in, present the login message if needed \n    }\n}\n```\n\n## Consuming Commercetools Endpoints\n\nConsuming and managing resources provided through available endpoints is very easy for any of the available endpoint classes.\n\nDepending on the capabilities of the resource, you can retrieve by specific UUID, use more detailed query options, and also perform create or update operations.\n\nAll of these functionalities are provided by static methods for any specific supported endpoint. For an example, you can create shopping cart using provided `Cart` class:\n```swift\nvar cartDraft = CartDraft(currency: \"EUR\")\n\nCart.create(cartDraft, result: { result in\n\tif let cart = result.model, result.isSuccess {\n\t\t// Do any work with created `Cart` instance, i.e:\n\t\tif cart.cartState == .active {\n\t\t\t// Our cart is active!\n\t\t}\n\t}\n})\n```\n\nIn case you need resources from an endpoint which hasn't been implemented in our SDK yet, you can easily create class representing that endpoint, and conform to appropriate protocols which take care of abstract endpoint implementations for many common use cases.\n\nThe following list represents currently supported abstract endpoints. For each protocol, there is a default extension provided, which will almost always cover your needs:\n\n* Create endpoint - `create(object: [String: AnyObject], expansion: [String]?, result: (Result\u003cResponseType\u003e) -\u003e Void)`\n* Update endpoint - `update(id: String, version: UInt, actions: [[String: AnyObject]], expansion: [String]?, result: (Result\u003cResponseType\u003e) -\u003e Void)`\n* Update by key endpoint - `updateByKey(key: String, version: UInt, actions: [[String: AnyObject]], expansion: [String]?, result: (Result\u003cResponseType\u003e) -\u003e Void)`\n* Query endpoint - `query(predicates predicates: [String]?, sort: [String]?, expansion: [String]?, limit: UInt?, offset: UInt?, result: (Result\u003cQueryResponse\u003cResponseType\u003e\u003e) -\u003e Void)`\n* Retrieve resource by ID endpoint - `byId(id: String, expansion: [String]?, result: (Result\u003cResponseType\u003e) -\u003e Void)`\n* Retrieve resource by key endpoint - `byKey(key: String, expansion: [String]?, result: (Result\u003cResponseType\u003e) -\u003e Void)`\n* Delete endpoint - `delete(id: String, version: UInt, expansion: [String]?, result: (Result\u003cResponseType\u003e) -\u003e Void)`\n\n### Currently Supported Endpoints\n\n#### Project settings\n\nIn order to get the countries, languages, and currencies supported for the current Commercetools project, you should use the project settings endpoint:\n```swift\nProject.settings { result in\n    if let settings = result.model {\n        // use settings.currencies, settings.countries, settings.languages, etc\n    }\n}\n```\n\n#### Cart\n\nCart endpoint supports all common operations:\n- Retrieve active cart\n```swift\nCart.active(result: { result in\n    if let cart = result.model, result.isSuccess {\n        // Cart successfully retrieved, response contains currently active cart\n    } else {\n        // Your user might not have an active cart at the moment\n    }\n})\n```\n- Query for carts\n```swift\nCart.query(limit: 2, offset: 1, result: { result in\n    if let response = result.model, let count = response.count,\n            let results = response.results, result.isSuccess {\n        // response contains an array of cart instances\n    }\n})\n```\n- Create new cart\n```swift\nvar cartDraft = CartDraft()\ncartDraft.currency = \"EUR\"\n\nCart.create(cartDraft, result: { result in\n    if let cart = result.model, let cartState = cart.cartState, result.isSuccess {\n        // Cart successfully created, and cart contains \n    }\n})\n```\n- Update existing cart\n```swift\nlet draft = LineItemDraft(productVariantSelection: .productVariant(productId: productId, variantId: variantId))\n\nlet updateActions = UpdateActions\u003cCartUpdateAction\u003e(version: version, actions: [.addLineItem(lineItemDraft: draft)])\nCart.update(cartId, actions: updateActions, result: { result in\n    if let cart = result.model, result.isSuccess {\n        // Cart successfully updated, response contains updated cart\n    }\n})\n```\n- Delete existing cart\n```swift\nlet version = 1 // Set the appropriate current version\n\nCart.delete(cartId, version: version, result: { result in\n    if let cart = result.model, result.isSuccess {\n        // Cart successfully deleted\n    }\n})\n```\n- Retrieve cart by UUID\n```swift\nCart.byId(\"cddddddd-ffff-4b44-b5b0-004e7d4bc2dd\", result: { result in\n    if let cart = result.model, cart.cartState == .active \u0026\u0026 result.isSuccess {\n        // response contains cart dictionary\n    }\n})\n```\n\nThere is also a subset of Cart methods for in-store actions. The parameters are the same as the methods above, with an additional parameter specifying the store key (`storeKey: String`).\n\n#### Category\n\nUsing regular mobile scope, it is possible to retrieve by UUID and query for categories.\n- Query for categories\n```swift\nCategory.query(limit: 10, offset: 1, result: { result in\n    if let response = result.model, let count = response.count,\n            let categories = response.results, result.isSuccess {\n        // categories contains an array of category objects\n    }\n})\n```\n- Retrieve category by UUID\n```swift\nCategory.byId(\"cddddddd-ffff-4b44-b5b0-004e7d4bc2dd\", result: { result in\n    if let category = result.model, result.isSuccess {\n        // response contains category objects\n    }\n})\n```\n\n#### Customer\n\nCustomer endpoint offers you several possible actions to use from your iOS app:\n- Retrieve user profile (user must be logged in)\n```swift\n// Optionally set `storeKey` for customers registered in a specific store.\nCustomer.profile { result in\n    if let profile = result.model, let firstName = profile.firstName,\n            let lastName = profile.lastName, result.isSuccess {\n        // E.g present user profile details\n    }\n}\n```\n- Sign up for a new account (anonymous user is being handled by `AuthManager`)\n```swift\nvar customerDraft = CustomerDraft()\ncustomerDraft.email = \"new.swift.sdk.test.user@commercetools.com\"\ncustomerDraft.password = \"password\"\n\n// Optionally set `storeKey` to sign up the customer in that store.\nCommercetools.signUpCustomer(customerDraft, result: { result in\n    if let customer = result.model?.customer, let version = customer.version, result.isSuccess {\n        // User has been successfully signed up.\n        // Now, you'd probably want to present the login form, or simply\n        // use AuthManager to login user automatically\n    }\n})\n```\n- Update customer account (user must be logged in)\n```swift\nvar options = SetFirstNameOptions()\noptions.firstName = \"newName\"\n\nlet updateActions = UpdateActions\u003cCustomerUpdateAction\u003e(version: version, actions: [.setFirstName(options: options)])\n// Optionally set `storeKey` for customers registered in a specific store.\nCustomer.update(actions: updateActions, result: { result in\n    if let customer = result.model, let version = customer.version, result.isSuccess {\n    \t// User profile successfully updated\n    }\n})\n```\n- Delete customer account (user must be logged in)\n```swift\n// Optionally set `storeKey` for customers registered in a specific store.\nCustomer.delete(version: version, result: { result in\n    if let customer = result.model, result.isSuccess {\n        // Customer was successfully deleted\n    }\n})\n```\n- Change password (user must be logged in)\n```swift\nlet  version = 1 // Set the appropriate current version\n\n// Optionally set `storeKey` for customers registered in a specific store.\nCustomer.changePassword(currentPassword: \"password\", newPassword: \"newPassword\", version: version, result: { result in\n    if let customer = result.model, result.isSuccess {\n    \t// Password has been changed, and now AuthManager has automatically obtained new access token\n    }\n})\n```\n- Reset password with token (anonymous user is being handled by `AuthManager`)\n```swift\nlet token = \"\" // Usually this token is retrieved from the password reset link, in case your app does support universal links\n\n// Optionally set `storeKey` for customers registered in a specific store.\nCustomer.resetPassword(token: token, newPassword: \"password\", result: { result in\n    if let customer = result.model, let email = customer.email, result.isSuccess {\n        // Password has been successfully reset, now would be a good time to present the login screen\n    }\n})\n```\n- Verify email with token (user must be logged in)\n```swift\nlet token = \"\" // Usually this token is retrieved from the activation link, in case your app does support universal links\n\n// Optionally set `storeKey` for customers registered in a specific store.\nCustomer.verifyEmail(token: token, result: { result in\n    if let customer = result.model, let email = customer.email, result.isSuccess {\n        // Email has been successfully verified, probably show UIAlertController with this info\n    }\n})\n```\n\n#### Order\n\nOrder endpoint provides the ability to create an order from an existing `Cart`, but also retrieve orders by UUID, and perform queries for orders.\n\n#### Shipping Method\n\nIn order to present shipping options to the customer during checkout, you need to use the shipping method endpoint:\n- Retrieve shipping methods for a cart\n```swift\nShippingMethod.for(cart: cart) { result in\n    if let shippingMethods = result.model, result.isSuccess {\n        // present shipping methods to the customer\n    }\n}\n```\n- Retrieve shipping methods for a country\n```swift\nShippingMethod.for(country: \"DE\") { result in\n    if let shippingMethods = result.model, result.isSuccess {\n        // present shipping methods to the customer\n    }\n}\n```\n- Query for shipping methods\n```swift\nlet predicate = \"name=\\\"DHL\\\"\"\n\nShippingMethod.query(predicates: [predicate], result: { result in\n    if let response = result.model, let count = response.count,\n\t\t\tlet results = response.results, result.isSuccess {\n        // results contains an array of shipping method objects\n    }\n})\n```\n- Retrieve shipping method by UUID\n```swift\nShippingMethod.byId(\"cddddddd-ffff-4b44-b5b0-004e7d4bc2dd\", result: { result in\n    if let shippingMethod = result.model, result.isSuccess {\n        // response contains product projection object\n    }\n})\n```\n\n#### Product Projection\n\nMost common way for your iOS app to retrieve the product data is by consuming the product projection endpoint. The following actions are currently supported:\n- Search for product projections\n```swift\nProductProjection.search(sort: [\"name.en asc\"], limit: 10, lang: Locale(identifier: \"en\"), text: \"Michael Kors\", result: { result in\n    if let response = result.model, let total = response.total,\n    \t\tlet results = response.results, result.isSuccess {\n        // results contains an array of product projection objects\n    }\n})\n```\n- Product projection keyword suggestions\n```swift\nProductProjection.suggest(lang: Locale(identifier: \"en\"), searchKeywords: \"michael\", result: { result in\n    if let response = result.json, let keywords = response[\"searchKeywords.en\"] as? [[String: AnyObject]],\n    \t\tlet firstKeyword = keywords.first?[\"text\"] as? String, result.isSuccess {\n        // keywords contains an array of suggestions in dictionary representation\n    }\n})\n```\n- Query for product projections\n```swift\nlet predicate = \"slug(en=\\\"michael-kors-bag-30T3GTVT7L-lightbrown\\\")\"\n\nProductProjection.query(predicates: [predicate], sort: [\"name.en asc\"], limit: 10, offset: 10, result: { result in\n    if let response = result.model, let count = response.count,\n\t\t\tlet results = response.results, result.isSuccess {\n        // results contains an array of product projection objects\n    }\n})\n```\n- Retrieve product projection by UUID\n```swift\nProductProjection.byId(\"cddddddd-ffff-4b44-b5b0-004e7d4bc2dd\", result: { result in\n    if let product = result.model, result.isSuccess {\n        // response contains product projection object\n    }\n})\n```\n\n#### Product Type\n\nUsing regular mobile scope, it is possible to retrieve by UUID, key and query for product types.\n- Query for product types\n```swift\nProductType.query(limit: 10, offset: 1, result: { result in\n    if let response = result.model, let count = response.count,\n            let productTypes = response.results, result.isSuccess {\n        // productTypes contains an array of product type objects\n    }\n})\n```\n- Retrieve product type by UUID\n```swift\nProductType.byId(\"cddddddd-ffff-4b44-b5b0-004e7d4bc2dd\", result: { result in\n    if let productType = result.model, result.isSuccess {\n        // response contains product type object\n    }\n})\n```\n- Retrieve product type by key\n```swift\nProductType.byKey(\"main\", result: { result in\n    if let productType = result.model, result.isSuccess {\n        // response contains product type object\n    }\n})\n```\n\n#### Store\n\nUsing `view_stores` scope, it is possible to retrieve by UUID, key and query for stores.\n- Query for stores\n```swift\nStore.query(limit: 10, offset: 1, result: { result in\n    if let response = result.model, let count = response.count,\n            let stores = response.results, result.isSuccess {\n        // stores contains an array of store objects\n    }\n})\n```\n- Retrieve store by UUID\n```swift\nStore.byId(\"cddddddd-ffff-4b44-b5b0-004e7d4bc2dd\", result: { result in\n    if let store = result.model, result.isSuccess {\n        // response contains store object\n    }\n})\n```\n- Retrieve store by key\n```swift\nStore.byKey(\"unionSquare\", result: { result in\n    if let store = result.model, result.isSuccess {\n        // response contains store object\n    }\n})\n```\n\n## Consuming Machine Learning Endpoints\n\nFor [machine learning API](https://docs.commercetools.com/http-api-ml) Commercetools provides, the SDK has a separate set of endpoints.\n\n### Currently Supported Machine Learning Endpoints\n\n#### Similar products\nSearching for similar products is possible using one method for initiating a search request, and another for checking the progress and obtaining search results.\n- Initiate a search request for similar products\n```swift\nlet request = SimilarProductSearchRequest(limit: 10, similarityMeasures: SimilarityMeasures(name: 1))\n\nSimilarProducts.initiateSearch(request: request) { result in\n    if let taskToken = result.model {\n        // use taskToken.taskId to monitor for progress\n    }\n}\n```\n- Check for status, and obtain results\n```swift\nSimilarProducts.status(for: taskToken.taskId) { result in\n    if let taskStatus = result.model, taskStatus == .success {\n        // task has been completed, use taskStatus.result to get the products from `PagedQueryResult`\n    }\n}\n```\n\n#### Category recommendations\nSearching for best-fitting categories for a specific product ID is possible using provided query method.\n- Searching for category recommendations\n```swift\nCategoryRecommendations.query(productId: product.id) { result in\n    if let results = result.model?.results {\n        // results contains an array of `ProjectCategoryRecommendation`s\n    }\n}\n```\n\n## Handling Results\n\nIn order to check whether any action with Commercetools services was successfully executed, you should use `isSuccess` or `isFailure` property of the result in question. For all successful operations, there're two properties, which can be used to consume actual responses. Recommended one for all endpoints which have incorporated models is `model`. This property has been used in all of the examples above. Alternatively, in case you are writing a custom endpoint, and do not wish to add model properties and mappings, `json` property will give you access to `[String: Any]` (dictionary representation of the JSON received from the Commercetools platform).\n\nFor all failed operations, `errors` property should be used from the result in question to present or handle specific issues. `CTError` instances are enumerations, with seven main cases, where each of those cases contains `FailureReason`, and some additional associated values, depending on the specific case.\n\n## Tests Setup\n\nIf there is a need to implement a custom endpoint which communicates with Commercetools services, it is recommended that such endpoint is also tested. Our `XCTestCase` extension provides good examples on how to setup test configuration. For some tests regular mobile client scope is sufficient (in most cases `view_products manage_my_profile manage_my_orders`). If your tests require setup or configuration with higher level privileges (scope), you can setup them as well. SDK tests consume this configuration from the environment variables for safety reasons.\n\nSetting up helper endpoints in test classes is also very easy. You can declare a private class conforming to specific endpoint protocols:\n```swift\nprivate class Foobar: QueryEndpoint, ByIdEndpoint, CreateEndpoint, UpdateEndpoint, DeleteEndpoint {\n    static let path = \"foobar\"\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcommercetools%2Fcommercetools-ios-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcommercetools%2Fcommercetools-ios-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcommercetools%2Fcommercetools-ios-sdk/lists"}