Securely synchronize any CareKit 2.1+ based app to a Parse Server Cloud. Compatible with parse-hipaa.

Overview

ParseCareKit

CI Status CI-objc Status Release Status Codecov License

Use at your own risk. There is no promise that this is HIPAA compliant and we are not responsible for any mishandling of your data

This framework is an API to synchronize CareKit 2.1+ data with parse-server using Parse-Swift. The learn more about how to use ParseCareKit check out the API documentation along with the rest of the README.

For the backend, it is suggested to use parse-hipaa which is an out-of-the-box HIPAA compliant Parse/Postgres or Parse/Mongo server that comes with Parse Dashboard. Since parse-hipaa is a pare-server, it can be used for iOS, Android, and web based apps. API's such as GraphQL, REST, and JS are also enabled in parse-hipaa and can be accessed directly or tested via the "API Console" in parse-dashboard. See the Parse SDK documentation for details. These docker images include the necessary database auditing and logging for HIPAA compliance.

You can also use ParseCareKit with any parse-server setup. If you devide to use your own parse-server, it's strongly recommended to add the following CloudCode to your server's "cloud" folder to ensure the necessary classes and fields are created as well as ensuring uniqueness of pushed entities. In addition, you should follow the directions to setup additional indexes for optimized queries. Note that CareKit data is extremely sensitive and you are responsible for ensuring your parse-server meets HIPAA compliance.

The following CareKit Entities are synchronized with Parse tables/classes:

  • OCKPatient <-> Patient
  • OCKCarePlan <-> CarePlan
  • OCKTask <-> Task
  • OCKHealthKitTask <-> HealthKitTask
  • OCKContact <-> Contact
  • OCKOutcome <-> Outcome
  • OCKRevisionRecord.Clock <-> Clock

ParseCareKit enables iOS and watchOS devices belonging to the same user to be reactively sychronized using ParseLiveQuery without the need of push notifications assuming the LiveQuery server has been configured.

CareKit Sample App with ParseCareKit

A sample app, CareKitSample-ParseCareKit, connects to the aforementioned parse-hipaa and demonstrates how CareKit data can be easily synched to the Cloud using ParseCareKit.

ParseCareKit.plist with server connection information

ParseCareKit comes with a helper method, PCKUtility.setupServer() that easily helps apps connect to your parse-server. To leverage the helper method, copy the ParseCareKit.plist file your "Supporting Files" folder in your Xcode project. Be sure to change ApplicationID and Server to the correct values for your server. Simply add the following inside didFinishLaunchingWithOptions in AppDelegate.swift:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

//Pulls from ParseCareKit.plist to connect to server
PCKUtility.setupServer() 

//If you need certificate pinning:
PCKUtility.setupServer { (challenge, completionHandler) in
    //Return how you want to handle the challenge. See docs for more information.
    completionHandler(.performDefaultHandling, nil)
}

What version of ParseCareKit Suits Your Needs?

  • (Most cases) Need to use ParseCareKit for iOS13+ and/or watchOS7 and will be using the latest (the minimal required commit is from PR #508) CareKit 2.1, CareKitUI, and CareKitStore (using OCKStore) within your app? You should use the main branch. You can take advantage of all of the capabilities of ParseCareKit. You should use ParseRemote() see below more details. This branch uses the Parse-Swift SDK instead of the Parse-Objc SDK.
  • Need to use ParseCareKit for iOS13+ and/or watchOS7 and will be using the latest CareKit, CareKitUI, and CareKitStore (but you would like to use the Parse Objc SDK) within your app? You will need to use Cocoapods and the Parse-Objc SDK branch. You can still use all of the capabilities of ParseCareKit. You should use ParseSynchronizedStoreManager() see here for more details.
  • Need to use ParseCareKit for iOS13+ and will be using CareKit <= 2.0.1, CareKitUI <= 2.0.1, and CareKitStore <= 2.0.1 (using OCKStore or conforming to OCKAnyStoreProtocol) within your app? You should use the carekit_2.0.1 branch. You can still use most of the capabilities of ParseCareKit, but you will be limited to syncing via a "wall clock" instead of "knowledge vectors". You will also have to use the Parse Objc SDK) and Cocoapods. You should use ParseSynchronizedStoreManager() see here for more details.

Note that it is recommended to use Vectors Clocks (ParseRemote) over Wall Clocks (ParseSynchronizedStoreManager) as the latter can run into more synching issues. If you choose to go the wall clock route, I recommend having your application suited for 1 device per user to reduce potential synching issues. You can learn more about how vector clocks work by looking at vector clocks.

Install ParseCareKit

Swift Package Manager (SPM)

ParseCareKit can be installed via SPM. Open an existing project or create a new Xcode project and navigate to File > Swift Packages > Add Package Dependency. Enter the url https://github.com/netreconlab/ParseCareKit and tap Next. Choose the main branch, and on the next screen, check off the package.

Note: ParseCareKit includes CareKitStore (it's a dependency) from CareKit's main branch, so there's no need to add CareKitStore to your app. If you want the rest of CareKit, you only need to add CareKit and CareKitUI via SPM. Anytime you need ParseCareKit, simply add import ParseCareKit at the top of the file.

Installing via cocoapods

To install via cocoapods, go to the Parse-Objc SDK branch for the readme. The main branch isn't compatable with cocoapods as the CareKit framework isn't compatible with Cocoapods.

Installing as a framework

  • Fork the project
  • Build the project
  • In your project Targets, click your corresponding target and then click the General heading to the right
  • Place ParseCareKit.framework in Frameworks, Libraries, and Embedded Content and it should automatically appear in Linked Binary with Libraries under the Build Phases section
  • Then, simply place import ParseCareKit at the top of any file that needs the framework.

If you have CareKit already in your project via SPM or copied, you will need to remove it as ParseCareKit comes with the a compatibile version of CareKit and a conflict of CareKit appearing twice will cause your app to crash

Setup Parse Server

For details on how to setup parse-server, follow the directions here or look at their detailed guide. Note that standard deployment locally on compouter, docker, AWS, Google Cloud, isn't HIPAA complaint by default.

Protecting Patients data in the Cloud using ACL's

You should set the default access for information you placed on your parse-server using ParseCareKit. To do this, you can set the default read/write access for all classes. For example, to make all data created to only be read and written by the user who created at do the following in AppDelegate.swift:

//Set default ACL for all Parse Classes
var defaultACL = ParseACL()
defaultACL.publicRead = false
defaultACL.publicWrite = false
do {
    _ = try ParseACL.setDefaultACL(defaultACL, withAccessForCurrentUser: true)
} catch {
    print(error.localizedDescription)
}

When giving access to a CareTeam or other entities, special care should be taken when deciding the propper ACL or Role. Feel free to read more about ACLs and Role access in Parse. For details, your setup should look similar to the code here.

Synchronizing Your Data

Assuming you are already familiar with CareKit (look at their documentation for details). Using ParseCareKit is simple, especially if you are using OCKStore out-of-the-box. If you are using a custom OCKStore you will need to subclass and write some additional code to synchronize your care-store with parse-server.

Using vector clocks aka CareKit's KnowledgeVector (ParseRemote)

ParseCareKit stays synchronized with the OCKStore by leveraging OCKRemoteSynchronizable. I recommend having this as a singleton, as it can handle all syncs from the carestore. An example is below:

/*Use Clock and OCKRemoteSynchronizable to keep data synced. 
This works with 1 or many devices per patient.*/
let uuid = UUID(uuidString: "3B5FD9DA-C278-4582-90DC-101C08E7FC98")!
let remoteStoreManager = ParseRemote(uuid: uuid, auto: true)
let dataStore = OCKStore(name: "myDataStore", type: .onDisk, remote: remoteStoreManager)
remoteStoreManager.delegate = self //Conform to this protocol if you are writing custom CloudCode in Parse and want to push syncs
remoteStoreManager.parseRemoteDelegate = self //Conform to this protocol to resolve conflicts

The uuid being passed to ParseRemote is used for the Clock. A possibile solution that allows for high flexibity is to have 1 of these per user-type per user. This allows you to have have one ParseUser that can be a "Doctor" and a "Patient". You should generate a different uuid for this particular ParseUser's Doctor and Patient type. You can save all types to ParseUser:

let userTypeUUIDDictionary = [
"doctor": UUID().uuidString,
"patient": UUID().uuidString
]

//Store the possible uuids for each type
PCKUser.current.userTypes = userTypeUUIDDictionary //Note that you need to save the UUID in string form to Parse
PCKUser.current.loggedInType = "doctor" 
PCKUser.current.saveInBackground()

//Start synch with the correct knowlege vector for the particular type of user
let lastLoggedInType = PCKUser.current.loggedInType
let userTypeUUIDString = PCKUser.current.userTypes[lastLoggedInType] as! String
let userTypeUUID = UUID(uuidString: userTypeUUID)!

//Start synching 
let remoteStoreManager = ParseRemote(uuid: userTypeUUID, auto: true)
let dataStore = OCKStore(name: "myDataStore", type: .onDisk, remote: remoteStoreManager)
remoteStoreManager.delegate = self //Conform to this protocol if you are writing custom CloudCode in Parse and want to push syncs
remoteStoreManager.parseRemoteDelegate = self //Conform to this protocol to resolve conflicts

Register as a delegate just in case ParseCareKit needs your application to update a CareKit entity. ParseCareKit doesn't have access to your CareKitStor, so your app will have to make the necessary update if ParseCareKit detects a problem and needs to make an update locally. Registering for the delegates also allows you to handle synching conflicts. An example is below:

extension AppDelegate: OCKRemoteSynchronizationDelegate, ParseRemoteDelegate{
    func didRequestSynchronization(_ remote: OCKRemoteSynchronizable) {
        print("Implement so ParseCareKit can tell your OCKStore to sync to the cloud")
        //example
        store.synchronize { error in
            print(error?.localizedDescription ?? "Successful sync with remote!")
        }
    }
    
    func remote(_ remote: OCKRemoteSynchronizable, didUpdateProgress progress: Double) {
        print("Completed: \(progress)")
    }

    func chooseConflictResolutionPolicy(_ conflict: OCKMergeConflictDescription, completion: @escaping (OCKMergeConflictResolutionPolicy) -> Void) {
        let conflictPolicy = OCKMergeConflictResolutionPolicy.keepDevice
        completion(conflictPolicy)
    }

    func successfullyPushedDataToCloud(){        
             print("Notified when data is succefully pushed to the cloud")        
         }
    }

Customizing Parse Entities to Sync with CareKit

There will be times you need to customize entities by adding fields that are different from the standard CareKit entity fields. If the fields you want to add can be converted to strings, it is recommended to take advantage of the userInfo: [String:String] field of a CareKit entity. To do this, you simply extend the entity you want customize using extension. For example, below shows how to add fields to OCKPatient<->Patient:

extension Patient: Person {
    var primaryCondition String? {
        guard let userInfo = userInfo else {
            return nil
        }
        return userInfo["CustomPatientUserInfoPrimaryConditionKey"]
    }

    mutating func setPrimaryCondition(_ primaryCondition: String?) {
        var mutableUserInfo = currentUserInfo()

        if let primaryCondition = primaryCondition {
            mutableUserInfo[PatientUserInfoKey.primaryCondition.rawValue] = primaryCondition
        }else{
            mutableUserInfo.removeValue(forKey: PatientUserInfoKey.primaryCondition.rawValue)
        }
        userInfo = mutableUserInfo
    }
}

If you want to make you own types and use them to replace the concrete CareKit ones. You should copy/paste the respective code from ParseCareKit, e.g. Patient, Contact, Task, etc. Then you need to pass your custom struct when initializing ParseRemoteSynchronizingManager. The way to do this is below:

let updatedConcreteClasses: [PCKStoreClass: PCKSynchronizable] = [
    .patient: CancerPatient()
]

remoteStoreManager = ParseRemote(uuid: uuid, auto: true, replacePCKStoreClasses: updatedConcreteClasses)
dataStore = OCKStore(name: storeName, type: .onDisk(), remote: remoteStoreManager)
remoteStoreManager.delegate = self
remoteStoreManager.parseRemoteDelegate = self

Of course, you can customize further by implementing your copyCareKit and converToCareKit methods and not call the super methods.

You can also map "custom" Parse classes to concrete OCKStore classes. This is useful when you want to have Doctor's and Patient's in the same app, but would like to map them both locally to the OCKPatient table on iOS devices. ParseCareKit makes this simple. Follow the same process as creating CancerPatient above, but add the kPCKCustomClassKey key to userInfo with Doctor.className() as the value. See below:

struct Doctor: Patient {
    public var type:String?
    
    func new(with careKitEntity: OCKEntity)->PCKSynchronizable? {
        
        switch careKitEntity {
        case .patient(let entity):
            return Doctor(careKitEntity: entity)
        default:
            os_log("new(with:) The wrong type (%{private}@) of entity was passed.", log: .carePlan, type: .error, careKitEntity.entityType.debugDescription)
            completion(nil)
        }
    }
    
    //Add a convienience initializer to to ensure that that the doctor class is always created correctly
    init(careKitEntity: OCKAnyPatient {
        self.init()
        self.copyCareKit(careKitEntity)
        self.userInfo = [kPCKCustomClassKey: self.className]
    }
    
    copyCareKit(_ patientAny: OCKAnyPatient)->Patient? {
        
        guard let doctor = patientAny as? OCKPatient else{
            return nil
        }
        
        super.copyCareKit(doctor, clone: clone)
        self.type = cancerPatient.userInfo?["CustomDoctorUserInfoTypeKey"]
        return seld
    }
    
    func convertToCareKit() -> OCKPatient? {
        guard var partiallyConvertedDoctor = super.convertToCareKit() else{return nil}
        
        var userInfo: [String:String]!
        if partiallyConvertedDoctor.userInfo == nil{
            userInfo = [String:String]()
        }else{
            userInfo = partiallyConvertedDoctor.userInfo!
        }
        if let type = self.type{
            userInfo["CustomDoctorUserInfoTypeKey"] = type
        }
        
        partiallyConvertedDoctor?.userInfo = userInfo
        return partiallyConvertedPatient
    }
}

You should never save changes to ParseCareKit classes directly to Parse as it may cause your data to get out-of-sync. Instead, user the convertToCareKit methods from each class and use the add or update methods from the CareStore. For example, the process below is recommended when creating new items to sync between CareKit and ParseCareKit

//Create doctor using CareKit
let newCareKitDoctor = OCKPatient(id: "drJohnson", givenName: "Jane", familyName: "Johnson")

//Initialize new Parse doctor with the CareKit one
_ = Doctor(careKitEntity: newCareKitDoctor){
   doctor in
   
   //Make sure the Doctor was created as Parse doctor
   guard let newParseDoctor = doctor as? Doctor else{
       return
   }
   
   //Make any edits you need to the new doctor
   newParseDoctor.type = "Cancer" //This was a custom value added in the Doctor class 
   newParseDoctor.sex = "Female" //This default from OCKPatient, Doctor has all defaults of it's CareKit counterpart
   
   
   guard let updatedCareKitDoctor = newParseDoctor.convertToCareKit() else {
       completion(nil,nil)
       return
   }
   
   store.addPatient(updatedCareKitDoctor, callbackQueue: .main){
       result in
       
       switch result{
       
       case .success(let doctor):
           print("Successfully add the doctor to the CareStore \(updatedCareKitDoctor)")
           print("CareKit and ParseCareKit will automatically handle syncing this data to the Parse Server")
       case .failure(let error):
           print("Error, couldn't save doctor. \(error)")
       }
   }
}

Querying Parse Like OCKQuery in CareKit

There are some of helper methods provided in ParseCareKit to query parse in a similar way you would query in CareKit. This is important because Patient, CarePlan, Contact, and Task are versioned entities and Outcome's are tombstoned. Querying each of the aforementioned classes with a reugular query will return all versions for "versioned" entities or tombstoned and not tombstoned Outcomes. A description of how versioning works in CareKit can be found here.

//To query the most recent version
let query = Patient.query(for: Date())

query.find(callbackQueue: .main){ results in
            
    switch results {

    case .success(let patients):
        print(patients)
    case .failure(let error):
        print(error)
    }
}

For Outcome:

//To query all current outcomes
let query = Outcome.queryNotDeleted()
query.find(callbackQueue: .main){ results in

    switch results {

    case .success(let outcomes):
        print(outcomes)
    case .failure(let error):
        print(error)
    }
}

Custom OCKStores

If you have a custom store, and have created your own entities, you simply need to conform to PCKVersionable (OCKPatient, OCKCarePlan, OCKTask, OCKContact, OCKOutcome) protocols. In addition you will need to conform to PCKSynchronizable. You can look through ParseCareKit entities such as CarePlan(PCKVersionable) as a reference for building your own.

Comments
  • Support macOS

    Support macOS

    I have hacked CareKit so it works on macOS and now I would like to be able to sync with macOS as well. One obstacle is WatchConnectivity not being available. Ideas about how to replace this dependency?

    question 
    opened by advatar 4
  • Failed to resolve dependencies.

    Failed to resolve dependencies.

    I ran into an issue when trying to install both ParseCareKit and CareKit via SPM to a SwiftUI app in Xcode 13. The detailed information is as follows:

    First, I created the app using the Swift + SwiftUI template image

    Next, I installed ParseCareKit via SPM following the instructions in the README image

    And this is what Xcode looks like afterward image

    Next, I tried to install CareKit and CareKitUI via SPM and planned to skip CareKitStore as it is included in ParseCareKit already image

    However, Xcode shows the following message image

    If I chose add anyway, and then make the following choices image

    Then Xcode shows the error "Failed to resolve dependencies" image

    Did I make any mistake along the way? Thanks.

    opened by zhang-bo-lilly 2
  • upgrade to ParseSwift 4.9.0

    upgrade to ParseSwift 4.9.0

    Upgrade to ParseSwift 4.9.0.

    • Add setAccessGroup method to SDK which allows developers to set the Keychain access group and cloud synchronization of Keychain via a plist file. The new options added to the plist file are AccessGroup: String, SynchronizeKeychain: Bool
    opened by cbaker6 1
  • Bump cocoapods-downloader from 1.5.1 to 1.6.3

    Bump cocoapods-downloader from 1.5.1 to 1.6.3

    Bumps cocoapods-downloader from 1.5.1 to 1.6.3.

    Release notes

    Sourced from cocoapods-downloader's releases.

    1.6.3

    Enhancements
    • None.
    Bug Fixes
    • None.

    1.6.2

    Enhancements
    • None.
    Bug Fixes
    • None.

    1.6.1

    Enhancements
    • None.
    Bug Fixes
    • None.

    1.6.0

    Enhancements
    • None.
    Bug Fixes
    • Adds a check for command injections in the input for hg and git.
      orta #124
    Changelog

    Sourced from cocoapods-downloader's changelog.

    1.6.3 (2022-04-01)

    Enhancements
    • None.
    Bug Fixes
    • None.

    1.6.2 (2022-03-28)

    Enhancements
    • None.
    Bug Fixes
    • None.

    1.6.1 (2022-03-23)

    Enhancements
    • None.
    Bug Fixes
    • None.

    1.6.0 (2022-03-22)

    Enhancements
    • None.
    Bug Fixes
    • Adds a check for command injections in the input for hg and git.
      orta #124
    Commits
    • c03e2ed Release 1.6.3
    • f75bccc Disable Bazaar tests due to macOS 12.3 not including python2
    • 52a0d54 Merge pull request #128 from CocoaPods/validate_before_dl
    • d27c983 Ensure that the git pre-processor doesn't accidentally bail also
    • 3adfe1f [CHANGELOG] Add empty Master section
    • 591167a Release 1.6.2
    • d2564c3 Merge pull request #127 from CocoaPods/validate_before_dl
    • 99fec61 Switches where we check for invalid input, to move it inside the download fun...
    • 96679f2 [CHANGELOG] Add empty Master section
    • 3a7c54b Release 1.6.1
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 1
  • Notify the delegate when data is being pulled from the cloud

    Notify the delegate when data is being pulled from the cloud

    Add a new method to ParseRemoteDelegate protocol to notify the delegate when synchronization starts. Paired with the successfullyPushedDataToCloud, the delegate is easier to respond when didRequestSynchronization is called.

    no-pr-activity 
    opened by zhang-bo-lilly 1
  • Remove saving uuid on ParseCareKit objects

    Remove saving uuid on ParseCareKit objects

    • [x] The uuid of all ParseCareKit objects is now objectId
    • [x] allowCustomObjectId has been abled on the client

    Warning these updates are not backwards compatible with previous versions of parse-hipaa or ParseCareKit.

    opened by cbaker6 1
  • feat: improve default ACL support

    feat: improve default ACL support

    If the developer doesn't set a defaultACL for the objects being synced, create one for them.

    • [x] Update to Parse-Swift 2.2.6
    • [x] Allow a defaultACL to be set for ParseCareKit
    • [x] Increase codecov
    opened by cbaker6 1
  • Add DeleteKeychainIfNeeded option

    Add DeleteKeychainIfNeeded option

    • [x] Update to ParseSwift 2.0.2
    • [x] Add DeleteKeychainIfNeeded option to PCKUtility
    • [x] Fix sending codecov files with Xcode 13
    • [x] Fix SwiftLint script
    opened by cbaker6 1
  • Changes for supporting Swift 5.5

    Changes for supporting Swift 5.5

    Some changes are needed to support Swift 5.5 and async/await

    • [x] Refactor Task to PCKTask, this classes with Swift 5.5 introduction of Task. This name change is only reflected in the SDK. The server will still have the names without PCK. To prevent issues like this in the future, prepended all ParseCareKit class names with PCK
    • [x] Add async/await wrappers
    • [x] Add combine wrappers
    opened by cbaker6 1
  • Fix outcome value in CareKit

    Fix outcome value in CareKit

    • [x] Update to latest CareKit to properly show OCKOutcomeValues in views
    • [x] Fixed a bug in ParseCareKit that prevented forced syncing after there's no values to push
    opened by cbaker6 1
  • User/Patient Relationship

    User/Patient Relationship

    Hi Corey, I would like to ask you about the User/Patient entity relation. I haven’t discerned how they are related in your code. While the entity Task has a pointer to care plan, and carePlan a pointer to Patient, no such relationship appears to exist for User/Patient. In order to support queries between these two, it appears that I would need to add this relationship. Is that correct?

    question 
    opened by wmfeuvrel 1
Releases(0.10.2)
Owner
Network Reconnaissance Lab
The NetRecon Lab is directed by Professor Corey Baker at the University of Kentucky
Network Reconnaissance Lab
Socket.io iOS and OSX Client compatible with v1.0 and later

SocketIO-Kit ⚠️ This project is no longer maintained. Please use the official framework Socket.IO-Client-Swift. SocketIO-Kit is a Socket.io iOS client

Ricardo Pereira 140 Mar 9, 2022
A utility used to parse number strings

NumberParser is a Swift package used to parse number strings, e.g. "eight thousa

Dalton Claybrook 4 Dec 28, 2021
Layer + Parse iOS Example (Swift)

Note: I no longer actively working on this project. If you encounter any problem, please open an issue and hopefully the community will help out. If y

Kien 119 Feb 10, 2022
A library for Search & Parse the weather data from Wunderground & Openweathermap conveniently.

SmileWeather A library for Search & Parse the weather data from Wunderground & Openweathermap conveniently. #What can it do for you? 1. Handle all com

Rain 482 Sep 28, 2022
A simple GCD based HTTP client and server, written in 'pure' Swift

SwiftyHTTP Note: I'm probably not going to update this any further - If you need a Swift networking toolset for the server side, consider: Macro.swift

Always Right Institute 116 Aug 6, 2022
A native, lightweight and secure time-based (TOTP) & counter-based (HOTP) password client built for iOS

A native, lightweight and secure time-based (TOTP) & counter-based (HOTP) password client built for iOS Built by Tijme Gommers – Buy me a coffee via P

Raivo OTP 770 Jan 8, 2023
Server-side Swift. The Perfect core toolset and framework for Swift Developers. (For mobile back-end development, website and API development, and more…)

Perfect: Server-Side Swift 简体中文 Perfect: Server-Side Swift Perfect is a complete and powerful toolbox, framework, and application server for Linux, iO

PerfectlySoft Inc. 13.9k Jan 6, 2023
💧 A server-side Swift web framework.

Vapor is a web framework for Swift. It provides a beautifully expressive and easy to use foundation for your next website, API, or cloud project. Take

Vapor 22.4k Jan 2, 2023
A Swift web framework and HTTP server.

A Swift Web Framework and HTTP Server Summary Kitura is a web framework and web server that is created for web services written in Swift. For more inf

Kitura 7.6k Jan 6, 2023
Tiny http server engine written in Swift programming language.

What is Swifter? Tiny http server engine written in Swift programming language. Branches * stable - lands on CocoaPods and others. Supports the latest

null 3.6k Dec 31, 2022
Lightweight library for web server applications in Swift on macOS and Linux powered by coroutines.

Why Zewo? • Support • Community • Contributing Zewo Zewo is a lightweight library for web applications in Swift. What sets Zewo apart? Zewo is not a w

Zewo 1.9k Dec 22, 2022
Swift Express is a simple, yet unopinionated web application server written in Swift

Documentation <h5 align="right"><a href="http://demo.swiftexpress.io/">Live ?? server running Demo <img src="https://cdn0.iconfinder.com/data/icons/

Crossroad Labs 850 Dec 2, 2022
🔌 Non-blocking TCP socket layer, with event-driven server and client.

Original authors Honza Dvorsky - http://honzadvorsky.com, @czechboy0 Matthias Kreileder - @matthiaskr1 At the request of the original authors, we ask

Vapor Community 574 Dec 7, 2022
Super lightweight async HTTP server library in pure Swift runs in iOS / MacOS / Linux

Embassy Super lightweight async HTTP server in pure Swift. Please read: Embedded web server for iOS UI testing. See also: Our lightweight web framewor

Envoy 540 Dec 15, 2022
Access Xcode Server API with native Swift objects.

Xcode Server SDK Use Xcode Server's API with native Swift objects. First brought to you in Buildasaur, now in an independent project. This is an unoff

Buildasaurs 401 Dec 29, 2022
Swift HTTP server using the pre-fork worker model

Curassow Curassow is a Swift Nest HTTP Server. It uses the pre-fork worker model and it's similar to Python's Gunicorn and Ruby's Unicorn. It exposes

Kyle Fuller Archive 397 Oct 30, 2022
Swift backend / server framework (Pure Swift, Supports Linux)

NetworkObjects NetworkObjects is a #PureSwift backend. This framework compiles for OS X, iOS and Linux and serves as the foundation for building power

Alsey Coleman Miller 258 Oct 6, 2022
Apple Push Notifications (APNs) Server-Side library.

Perfect-Notifications 简体中文 APNs remote Notifications for Perfect. This package adds push notification support to your server. Send notifications to iO

PerfectlySoft Inc. 113 Oct 28, 2022
WebSocket implementation for use by Client and Server

WebSocket ⚠️ This module contains no networking. To create a WebSocket Server, see WebSocketServer. To create a WebSocket Client, see WebSocketClient.

Zewo Graveyard 63 Jan 29, 2022