API Keys
This guide will cover setting up the Parra iOS SDK to allow you to start gathering user feedback from within your iOS app. This is done with four steps:
- Prepare your backend
- Install the SDK
- Authenticate your users
- Integrate Parra Feedback Module
- Customizing the Parra Feedback View (Optional)
- Best Practices
Prepare Your Backend
Before you are ready to integrate the Parra Feedback iOS SDK, you will need to make some server side changes to authenticate your users with the Parra API.
Create an API key if you do not already have one. An API key is required to make authenticated requests to the Parra API.
Set up your backend to provide access tokens to your iOS client. These access tokens will be used by the Parra Feedback iOS SDK to securely authenticate your users, without exposing your API key. You should never embed your API Key or Secret in your iOS app.
If you have not already configured your backend to issue access tokens for your users, jump over to our backend guides to do so.
Installation
The Parra Feedback SDK and Parra Core modules require a deployment target of iOS 13 or above and can be installed with Cocoapods.
- Make sure that you have a recent version of Cocoapods installed.
If you were not already using Cocoapods, you will need to run
pod init
from within the same directory as your.xcodeproj
file.Add the
ParraFeedback
Pod under your app's target in your Podfile by addingpod 'ParraFeedback', '~> 1.1.0'
. If you are not exactly clear on where to put this, see the Podfile documentation. Check the Releases page on GitHub to be sure you are installing the latest version.Install the
ParraFeedback
Pod into your project by runningpod install
- Make sure to open the
.xcworkspace
file instead of the.xcodeproj
file from now on.
Authentication
In order to authenticate your users with the Parra API you must configure your backend to
provide you with an access token signed by your API Key for consumption by the Parra SDK
when requested. After your backend is configured to create and sign these access tokens,
you will need to implement one of the available Parra.setAuthenticationProvider
overloads
to retrieve access tokens on behalf of your users whenever authentication is required within the Parra API.
This will happen when an access token for a user has not yet been provided and when a user's access token expires.
If you need to switch between multiple users, it is important that you use Parra.logout()
to
clear the cached access token if your user logs out. This will prevent data collected from the previous user from being
attributed to the new user and trigger a refresh of the access token.
import UIKit
import ParraCore
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let myAppAccessToken = "9B5CDA6B-7538-4A2A-9611-7308D56DFFA1"
Parra.setAuthenticationProvider {(completion: @escaping(Result<ParraCredential, Error>) -> Void) in
// Replace this with your Parra access token generation endpoint
let url = URL(string: "http://localhost:8080/v1/parra/auth/token")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
// Replace this with your app's way of authenticating users
request.setValue("Bearer \\(myAppAccessToken)", forHTTPHeaderField: "Authorization")
URLSession.shared.dataTask(with: request) { data, _, error in
if let error = error {
completion(.failure(error))
} else {
do {
let response = try JSONDecoder().decode([String: String].self, from: data!)
completion(.success(ParraCredential(token: response["access_token"]!)))
} catch let error {
completion(.failure(error))
}
}
}.resume()
}
return true
}
// ...
}
Authentication with Public Auth
If your application does not have a backend, you may use public auth to authenticate directly from your app. This approach is not recommended.
import UIKit
import ParraCore
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let tenantId = "<tenant-id>" // TODO: - Replace me
let publicApiKeyId = "<public-api-key-id>" // TODO: - Replace me
let baseUrl = URL(string: "https://api.parra.io")!
let parraPublicAuthTokenUrl = URL(string: "v1/tenants/\\(tenantId)/issuers/public/auth/token", relativeTo: baseUrl)!
Parra.setAuthenticationProvider { (completion: @escaping (Result<ParraCredential, Error>) -> Void) in
var request = URLRequest(url: parraPublicAuthTokenUrl)
let json: [String: Any] = ["user_id": "cool-user-1"] // TODO: - Replace me with the id of the user in your system
let jsonData = try! JSONSerialization.data(withJSONObject: json)
let authData = ("api_key:" + publicApiKeyId).data(using: .utf8)!.base64EncodedString()
request.httpMethod = "POST"
request.httpBody = jsonData
request.setValue("Basic \\(authData)", forHTTPHeaderField: "Authorization")
URLSession.shared.dataTask(with: request) { data, _, error in
if let error = error {
completion(.failure(error))
} else {
do {
let response = try JSONDecoder().decode([String: String].self, from: data!)
completion(.success(ParraCredential(token: response["access_token"]!)))
} catch let error {
completion(.failure(error))
}
}
}.resume()
}
return true
}
// ...
}
Integration
Now that your users are authenticated, you are ready to request cards and present
them in your app. The Parra Feedback iOS SDK gives you the flexibility to fetch cards when it is
convenient and display the feedback view where it makes sense. To fetch the cards, simple call
ParraFeedback.fetchFeedbackCards
and in the completion handler,
ParraFeedback.fetchFeedbackCards { result in
switch result {
case .success(let cards):
// Store the cards
case .failure(let error):
print(error)
}
}
Once you have the cards, you must pass them into a Parra feedback view. You may add it directly to a UIView or use wrappers around it for both
UITableView
and UICollectionView
implementations. You can find sample implementations in the Demo project
Present Parra Feedback View
import UIKit
import ParraFeedback
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
ParraFeedback.fetchFeedbackCards {result in
switch result {
case .success(let cards):
let feedbackView = ParraFeedbackView(cardItems: cards, config: .default)
self.view.addSubview(feedbackView)
case .failure(let error):
print(error)
}
}
}
// ...
}
When you run your app, you should now see any questions you have created in the Parra dashboard. If you have not yet created any questions, head over to the Dashboard to do so.
Present Parra Feedback View in a UITableView
First, register your cell in viewDidLoad(_:)
.
tableView.register(ParraFeedbackTableViewCell.self, forCellReuseIdentifier: ParraFeedbackTableViewCell.defaultCellId)
Next, dequeue your cell.
override func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == Constant.indexToDisplayParraFeedback {
let parraCell = tableView.dequeueReusableCell(withIdentifier: ParraFeedbackTableViewCell.defaultCellId, for: indexPath) as! ParraFeedbackTableViewCell
parraCell.config = .default
parraCell.delegate = self
return parraCell
}
// ...your normal cells
return cell
}
Finally, call endDisplaying
on the cell when you are done displaying it to trigger a sync of any answers.
override func tableView(_ tableView: UITableView,
didEndDisplaying cell: UITableViewCell,
forRowAt indexPath: IndexPath) {
if let parraCell = cell as? ParraFeedbackTableViewCell {
parraCell.endDisplaying()
}
}
Present Parra Feedback View in a UICollectionView
First, register your cell in viewDidLoad(_:)
.
collectionView.register(ParraFeedbackCollectionViewCell.self, forCellWithReuseIdentifier: ParraFeedbackCollectionViewCell.defaultCellId)
Next, dequeue your cell.
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.row == Constant.indexToDisplayParraFeedback {
let parraCell = collectionView.dequeueReusableCell(
withReuseIdentifier: ParraFeedbackCollectionViewCell.defaultCellId,
for: indexPath
) as! ParraFeedbackCollectionViewCell
parraCell.config = .default
parraCell.delegate = self
return parraCell
}
// ...your other cells
return cell
}
Finally, call endDisplaying
on the cell when you are done displaying it to trigger a sync of any answers.
override func collectionView(_ collectionView: UICollectionView,
didEndDisplaying cell: UICollectionViewCell,
forItemAt indexPath: IndexPath) {
if let parraCell = cell as? ParraFeedbackCollectionViewCell {
parraCell.endDisplaying()
}
}
Customization
Parra Feedback views are built to be customizable to match the look and feel of your app. To facilitate this, the Parra Feedback SDK provides extensive options to customize properties like background and tint colors, content insets, corner radius and many other properties.
Applying Configurations
Customization of the ParraFeedbackView
is done by either setting the config
parameter
when initializing the view, or setting its config
instance variable. config
takes an
instance of ParraFeedbackViewConfig
, which allows you to customize virtually every aspect of the feedback view.
feedbackView.config = ParraFeedbackViewConfig(
backgroundColor: .white,
tintColor: .systemBlue,
cornerRadius: 12,
contentInsets: UIEdgeInsets(top: 12, left: 6, bottom: 12, right: 6),
shadow: .default,
title: .titleDefault,
subtitle: .subtitleDefault,
body: ParraTextConfig(
color: .red,
font: .boldSystemFont(ofSize: 14.0),
shadow: .default
)
)
ParraFeedbackViewConfig
also provides a set of sensible defaults for light and dark themes that you can use as a starting point.
feedbackView.config = .default
feedbackView.config = .defaultDark
Best Practices
Best practices provide guidelines for better integration but your specific integration may differ.
Fetch card in parallel with any other data you are attempting to display
Only show the Parra Feedback view when their are cards available
Before you can make requests to the Parra API, you will need to grab your API key from your dashboard. You find it under Settings » API.
Choose your client
Before making your first API request, you need to pick which API client you will use. In addition to good ol' cURL HTTP requests, Parra offers clients for JavaScript, Python, and PHP. In the following example, you can see how to install each client.
# cURL is most likely already installed on your machine
curl --version
Making your first API request
After picking your preferred client, you are ready to make your first call to the Parra API. Below, you can see how to send a GET request to the Conversations endpoint to get a list of all your conversations. In the cURL example, results are limited to ten conversations, the default page length for each client.
curl -G https://api.parra.io/v1/conversations \
-H "Authorization: Bearer {token}" \
-d limit=10
What's next?
Great, you're now set up with an API client and have made your first request to the API. Here are a few links that might be handy as you venture further into the Parra API: