|
1 | 1 | # ParseServerSwift
|
2 | 2 |
|
3 |
| -Write Cloud Code in Swift! What is Cloud Code? |
| 3 | +[](https://github.com/netreconlab/parse-server-swift/actions?query=workflow%3Aci+branch%3Amain) |
4 | 4 |
|
5 |
| -For complex apps, sometimes you just need logic that isn’t running on a mobile device. Cloud Code makes this possible. |
| 5 | +Write Cloud Code in Swift! |
| 6 | + |
| 7 | +What is Cloud Code? For complex apps, sometimes you just need logic that isn’t running on a mobile device. Cloud Code makes this possible. |
6 | 8 | Cloud Code in ParseServerSwift is easy to use because it’s built using [Parse-Swift](https://github.com/parse-community/Parse-Swift)
|
7 | 9 | and [Vapor](https://github.com/vapor/vapor). The only difference is that this code runs in your ParseServerSwift rather than running on the user’s mobile device. When you update your Cloud Code,
|
8 | 10 | it becomes available to all mobile environments instantly. You don’t have to wait for a new release of your application.
|
9 | 11 | This lets you change app behavior on the fly and add new features faster.
|
| 12 | + |
| 13 | +## Configure ParseServerSwift |
| 14 | +To configure, you should edit [ParseServerSwift/Sources/ParseServerSwift/configure.swift](https://github.com/netreconlab/ParseServerSwift/blob/main/Sources/App/configure.swift) |
| 15 | + |
| 16 | +### WebhookKey |
| 17 | +The `webhookKey` should match the [webhookKey on the Parse Server](https://github.com/parse-community/parse-server/blob/42c954318926823446326c95188b844e19954711/src/Options/Definitions.js#L491-L494). If you decide not the a `webhookKey`, set the value to `nil` in your ParseServerSwift. |
| 18 | + |
| 19 | +### Hostname, Port, and TLS |
| 20 | +By default, the hostname is `127.0.0.1` and the port is `8081`. These values can easily be changed: |
| 21 | + |
| 22 | +```swift |
| 23 | +app.http.server.configuration.hostname = "your.hostname.com" |
| 24 | +app.http.server.configuration.port = 8081 |
| 25 | +app.http.server.configuration.tlsConfiguration = .none |
| 26 | +``` |
| 27 | + |
| 28 | +### Parse Swift SDK |
| 29 | +Configure the SDK as described in the [documentation](https://parseplatform.org/Parse-Swift/release/documentation/parseswift/parseswift/initialize(applicationid:clientkey:masterkey:serverurl:livequeryserverurl:allowingcustomobjectids:usingtransactions:usingequalqueryconstraint:keyvaluestore:requestcachepolicy:cachememorycapacity:cachediskcapacity:migratingfromobjcsdk:deleti-97083)). |
| 30 | + |
| 31 | +```swift |
| 32 | +// Required: Change to your Parse Server serverURL. |
| 33 | +guard let parseServerUrl = URL(string: "http://localhost:1337/1") else { |
| 34 | + throw ParseError(code: .unknownError, |
| 35 | + message: "Could not make Parse Server URL") |
| 36 | +} |
| 37 | + |
| 38 | +// Initialize the Parse-Swift SDK |
| 39 | +ParseSwift.initialize(applicationId: "applicationId", // Required: Change to your applicationId. |
| 40 | + clientKey: "clientKey", // Required: Change to your clientKey. |
| 41 | + masterKey: "masterKey", // Required: Change to your masterKey. |
| 42 | + serverURL: parseServerUrl) { _, completionHandler in |
| 43 | + completionHandler(.performDefaultHandling, nil) |
| 44 | +} |
| 45 | +``` |
| 46 | + |
| 47 | +## Adding `ParseObject`'s |
| 48 | +It is recommended to add all of your `ParseObject`'s to [ParseServerSwift/Sources/ParseServerSwift/Models](https://github.com/netreconlab/ParseServerSwift/blob/main/Sources/ParseServerSwift/Models). An example `GameScore` model is provided: |
| 49 | + |
| 50 | +```swift |
| 51 | +import Foundation |
| 52 | +import ParseSwift |
| 53 | + |
| 54 | +/** |
| 55 | + An example `ParseObject`. This is for testing. You can |
| 56 | + remove when creating your application. |
| 57 | + */ |
| 58 | +struct GameScore: ParseObject { |
| 59 | + // These are required by ParseObject. |
| 60 | + var objectId: String? |
| 61 | + var createdAt: Date? |
| 62 | + var updatedAt: Date? |
| 63 | + var ACL: ParseACL? |
| 64 | + var originalData: Data? |
| 65 | + |
| 66 | + // Your own properties. |
| 67 | + var points: Int? |
| 68 | + |
| 69 | + // Implement your own version of merge. |
| 70 | + func merge(with object: Self) throws -> Self { |
| 71 | + var updated = try mergeParse(with: object) |
| 72 | + if updated.shouldRestoreKey(\.points, |
| 73 | + original: object) { |
| 74 | + updated.points = object.points |
| 75 | + } |
| 76 | + return updated |
| 77 | + } |
| 78 | +} |
| 79 | +``` |
| 80 | + |
| 81 | +### The `ParseUser` Model |
| 82 | +Be sure to add all of the additional properties you have in your `_User` class to the `User` model which is located at [ParseServerSwift/Sources/ParseServerSwift/Models/User.swift](https://github.com/netreconlab/ParseServerSwift/blob/main/Sources/ParseServerSwift/Models/User.swift) |
| 83 | + |
| 84 | +## Parse Cloud Code Hook Routes |
| 85 | +Adding routes for ParseHooks are as simple as adding [routes in Vapor](https://docs.vapor.codes/basics/routing/). `ParseServerSwift` adds some additional methods to routes to easily create and register [Hook Functions](https://parseplatform.org/Parse-Swift/release/documentation/parseswift/parsehookfunctionable) and [Hook Triggers](https://parseplatform.org/Parse-Swift/release/documentation/parseswift/parsehooktriggerable/). All routes should be added to [ParseServerSwift/Sources/ParseServerSwift/routes.swift](https://github.com/netreconlab/ParseServerSwift/blob/main/Sources/ParseServerSwift/routes.swift) |
| 86 | + |
| 87 | +### Cloud Code Functions |
| 88 | +Cloud Code Functions can also take parameters. It's recommended to place all paramters in |
| 89 | +[ParseServerSwift/Sources/ParseServerSwift/Models/Parameters](https://github.com/netreconlab/ParseServerSwift/blob/main/Sources/ParseServerSwift/Models/Parameters) |
| 90 | + |
| 91 | +```swift |
| 92 | +app.post("foo", |
| 93 | + name: "foo") { req async throws -> ParseHookResponse<String> in |
| 94 | + if let error: ParseHookResponse<String> = checkHeaders(req) { |
| 95 | + return error |
| 96 | + } |
| 97 | + var parseRequest = try req.content |
| 98 | + .decode(ParseHookFunctionRequest<User, FooParameters>.self) |
| 99 | + |
| 100 | + // If a User called the request, fetch the complete user. |
| 101 | + if parseRequest.user != nil { |
| 102 | + parseRequest = try await parseRequest.hydrateUser() |
| 103 | + } |
| 104 | + |
| 105 | + // To query using the User's credentials who called this function, |
| 106 | + // use the options() method from the request |
| 107 | + let options = parseRequest.options() |
| 108 | + let scores = try await GameScore.query.findAll(options: options) |
| 109 | + req.logger.info("Scores this user can access: \(scores)") |
| 110 | + return ParseHookResponse(success: "Hello, new world!") |
| 111 | +} |
| 112 | +``` |
| 113 | + |
| 114 | +### Cloud Code Triggers |
| 115 | +```swift |
| 116 | +app.post("bar", |
| 117 | + className: "GameScore", |
| 118 | + triggerName: .afterSave) { req async throws -> ParseHookResponse<Bool> in |
| 119 | + if let error: ParseHookResponse<Bool> = checkHeaders(req) { |
| 120 | + return error |
| 121 | + } |
| 122 | + var parseRequest = try req.content |
| 123 | + .decode(ParseHookTriggerRequest<User, GameScore>.self) |
| 124 | + |
| 125 | + // If a User called the request, fetch the complete user. |
| 126 | + if parseRequest.user != nil { |
| 127 | + parseRequest = try await parseRequest.hydrateUser() |
| 128 | + } |
| 129 | + |
| 130 | + // To query using the masterKey pass the `useMasterKey option |
| 131 | + // to ther query. |
| 132 | + let scores = try await GameScore.query.findAll(options: [.useMasterKey]) |
| 133 | + req.logger.info("All scores: \(scores)") |
| 134 | + return ParseHookResponse(success: true) |
| 135 | +} |
| 136 | +``` |
0 commit comments