Swift icon

Swift Quick Start Guide

Get started with FacePing's face recognition API using Swift

Prerequisites

Step 1: Create FacePing Client

Create a new file FacePingClient.swift:

import Foundation

class FacePingClient {
    private let apiKey: String
    private let baseUrl = "https://api.faceping.ai"
    
    init(apiKey: String) {
        self.apiKey = apiKey
    }
    
    func createGroup(name: String) async throws {
        let url = URL(string: "\(baseUrl)/groups/\(name)")!
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
        
        let (_, response) = try await URLSession.shared.data(for: request)
        
        guard let httpResponse = response as? HTTPURLResponse,
              httpResponse.statusCode == 200 else {
            throw NSError(domain: "FacePingError", code: 1, 
                userInfo: [NSLocalizedDescriptionKey: "Failed to create group"])
        }
        
        print("Group created successfully")
    }
}

Usage example:

let client = FacePingClient(apiKey: "your_api_key_here")
try await client.createGroup(name: "my-group")

Step 2: Add Face Upload

Add to FacePingClient.swift:

func uploadFace(groupName: String, imageData: Data) async throws {
    let url = URL(string: "\(baseUrl)/groups/\(groupName)/faces")!
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
    
    let boundary = UUID().uuidString
    request.setValue("multipart/form-data; boundary=\(boundary)", 
        forHTTPHeaderField: "Content-Type")
    
    // Create multipart form data
    var body = Data()
    body.append("--\(boundary)\r\n".data(using: .utf8)!)
    body.append("Content-Disposition: form-data; name=\"image\"; filename=\"image.jpg\"\r\n".data(using: .utf8)!)
    body.append("Content-Type: image/jpeg\r\n\r\n".data(using: .utf8)!)
    body.append(imageData)
    body.append("\r\n--\(boundary)--\r\n".data(using: .utf8)!)
    
    request.httpBody = body
    
    let (_, response) = try await URLSession.shared.data(for: request)
    
    guard let httpResponse = response as? HTTPURLResponse,
          httpResponse.statusCode == 200 else {
        throw NSError(domain: "FacePingError", code: 2, 
            userInfo: [NSLocalizedDescriptionKey: "Failed to upload face"])
    }
    
    print("Face uploaded successfully")
}

Usage example:

if let imageUrl = Bundle.main.url(forResource: "face", withExtension: "jpg"),
   let imageData = try? Data(contentsOf: imageUrl) {
    try await client.uploadFace(groupName: "my-group", imageData: imageData)
}

Step 3: Add Face Search

Add to FacePingClient.swift:

struct MatchResult: Decodable {
    let score: Double
}

struct SearchResponse: Decodable {
    let matches: [MatchResult]
}

func searchFaces(groupName: String, imageData: Data) async throws -> [MatchResult] {
    let url = URL(string: "\(baseUrl)/groups/\(groupName)/search")!
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
    
    let boundary = UUID().uuidString
    request.setValue("multipart/form-data; boundary=\(boundary)", 
        forHTTPHeaderField: "Content-Type")
    
    // Create multipart form data
    var body = Data()
    body.append("--\(boundary)\r\n".data(using: .utf8)!)
    body.append("Content-Disposition: form-data; name=\"image\"; filename=\"image.jpg\"\r\n".data(using: .utf8)!)
    body.append("Content-Type: image/jpeg\r\n\r\n".data(using: .utf8)!)
    body.append(imageData)
    body.append("\r\n--\(boundary)--\r\n".data(using: .utf8)!)
    
    request.httpBody = body
    
    let (data, response) = try await URLSession.shared.data(for: request)
    
    guard let httpResponse = response as? HTTPURLResponse,
          httpResponse.statusCode == 200 else {
        throw NSError(domain: "FacePingError", code: 3, 
            userInfo: [NSLocalizedDescriptionKey: "Failed to search faces"])
    }
    
    let searchResponse = try JSONDecoder().decode(SearchResponse.self, from: data)
    print("Found \(searchResponse.matches.count) matches")
    return searchResponse.matches
}

Usage example:

if let imageUrl = Bundle.main.url(forResource: "search", withExtension: "jpg"),
   let imageData = try? Data(contentsOf: imageUrl) {
    let matches = try await client.searchFaces(groupName: "my-group", imageData: imageData)
    for match in matches {
        print("Match Score: \(match.score)")
    }
}

Security Notes

  • Images are immediately discarded after vector conversion
  • Face vectors cannot be reverse-engineered into images
  • Always use HTTPS for all API calls
  • Store your API keys securely (e.g., in Keychain)

Ready to get started?

Take a look at the API documentation
API docs