Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
- name: Use multiple cores
run: defaults write com.apple.dt.XCBuild EnableSwiftBuildSystemIntegration 1
- name: Build and Test
run: swift test --enable-code-coverage -v
run: swift test --enable-code-coverage
env:
DEVELOPER_DIR: ${{ env.CI_XCODE }}
- name: Prepare codecov
Expand Down Expand Up @@ -55,7 +55,7 @@ jobs:
release-version: "5"
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Build and Test
run: swift test --enable-test-discovery --enable-code-coverage -v
run: swift test --enable-test-discovery --enable-code-coverage
- name: Update codecov config
run: cat .codecov.yml | curl --data-binary @- https://codecov.io/validate
- name: Prepare codecov
Expand Down
4 changes: 2 additions & 2 deletions Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 6 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,20 @@ import PackageDescription
let package = Package(
name: "ParseServerSwift",
platforms: [
.macOS(.v12)
.iOS(.v13),
.macCatalyst(.v13),
.macOS(.v10_15),
.tvOS(.v13),
.watchOS(.v6)
],
products: [
.library(name: "ParseServerSwift", targets: ["ParseServerSwift"])
],
dependencies: [
// 💧 A server-side Swift web framework.
.package(url: "https://github.com/vapor/vapor.git", .upToNextMajor(from: "4.69.1")),
.package(url: "https://github.com/vapor/leaf.git", .upToNextMajor(from: "4.2.4")),
.package(url: "https://github.com/netreconlab/Parse-Swift.git",
.upToNextMajor(from: "5.0.0-beta.4")),
.upToNextMajor(from: "5.0.0-beta.6")),
],
targets: [
.target(
Expand Down
62 changes: 33 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ Technically, complete apps can be written with `ParseServerSwift`, the only diff
The following enviroment variables are available and can be configured directly or through `.env`, `.env.production`, etc. See the [Vapor Docs for more details](https://docs.vapor.codes/basics/environment/).

```
PARSE_SWIFT_SERVER_HOST_NAME: cloud-code # The name of your host. If you are running in Docker it should be same name as the docker service
PARSE_SWIFT_SERVER_PORT: # This is the default port on the docker image
PARSE_SWIFT_SERVER_DEFAULT_MAX_BODY_SIZE: 500kb # Set the default size for bodies that are collected into memory before calling your handlers (See Vapor docs for more details)
PARSE_SWIFT_SERVER_URLS: http://parse:1337/parse # (Required) Specify one of your Parse Servers to connect to. Can connect to multiple by seperating URLs with commas
PARSE_SWIFT_SERVER_APPLICATION_ID: appId # (Required) The application id of your Parse Server
PARSE_SWIFT_SERVER_PRIMARY_KEY: primaryKey # (Required) The master key of your Parse Server
PARSE_SWIFT_SERVER_WEBHOOK_KEY: webookKey # The webhookKey of your Parse Server
PARSE_SERVER_SWIFT_HOST_NAME: cloud-code # The name of your host. If you are running in Docker it should be same name as the docker service
PARSE_SERVER_SWIFT_PORT: # This is the default port on the docker image
PARSE_SERVER_SWIFT_DEFAULT_MAX_BODY_SIZE: 500kb # Set the default size for bodies that are collected into memory before calling your handlers (See Vapor docs for more details)
PARSE_SERVER_SWIFT_URLS: http://parse:1337/parse # (Required) Specify one of your Parse Servers to connect to. Can connect to multiple by seperating URLs with commas
PARSE_SERVER_SWIFT_APPLICATION_ID: appId # (Required) The application id of your Parse Server
PARSE_SERVER_SWIFT_PRIMARY_KEY: primaryKey # (Required) The master key of your Parse Server
PARSE_SERVER_SWIFT_WEBHOOK_KEY: webookKey # The webhookKey of your Parse Server
```

If you need to customize your configuration you will need to edit [ParseServerSwift/Sources/ParseServerSwift/configure.swift](https://github.com/netreconlab/ParseServerSwift/blob/main/Sources/ParseServerSwift/configure.swift) directly.
Expand Down Expand Up @@ -107,6 +107,7 @@ Cloud Code Functions can also take parameters. It's recommended to place all par
[ParseServerSwift/Sources/ParseServerSwift/Models/Parameters](https://github.com/netreconlab/ParseServerSwift/blob/main/Sources/ParseServerSwift/Models/Parameters)

```swift
// A Parse Hook Function route.
app.post("hello",
name: "hello") { req async throws -> ParseHookResponse<String> in
if let error: ParseHookResponse<String> = checkHeaders(req) {
Expand All @@ -133,13 +134,13 @@ app.post("hello",
```swift
// A Parse Hook Trigger route.
app.post("score", "save", "before",
className: "GameScore",
className: GameScore.className,
triggerName: .beforeSave) { req async throws -> ParseHookResponse<GameScore> in
if let error: ParseHookResponse<GameScore> = checkHeaders(req) {
return error
}
var parseRequest = try req.content
.decode(ParseHookTriggerRequest<User, GameScore>.self)
.decode(ParseHookTriggerObjectRequest<User, GameScore>.self)

// If a User called the request, fetch the complete user.
if parseRequest.user != nil {
Expand All @@ -148,59 +149,62 @@ app.post("score", "save", "before",

guard let object = parseRequest.object else {
return ParseHookResponse(error: .init(code: .missingObjectId,
message: "Object not sent in request."))
message: "Object not sent in request."))
}
// To query using the primaryKey pass the `usePrimaryKey` option
// to ther query.
let scores = try await GameScore.query.findAll(options: [.usePrimaryKey])
req.logger.info("All scores: \(scores)")
req.logger.info("Before save is being made. Showing all scores before saving new ones: \(scores)")
return ParseHookResponse(success: object)
}

// Another Parse Hook Trigger route.
app.post("score", "find", "before",
className: "GameScore",
className: GameScore.className,
triggerName: .beforeFind) { req async throws -> ParseHookResponse<[GameScore]> in
if let error: ParseHookResponse<[GameScore]> = checkHeaders(req) {
return error
}
let parseRequest = try req.content
.decode(ParseHookTriggerRequest<User, GameScore>.self)
.decode(ParseHookTriggerObjectRequest<User, GameScore>.self)
req.logger.info("A query is being made: \(parseRequest)")

// Return two custom scores instead.
let score1 = GameScore(objectId: "yolo",
createdAt: Date(),
points: 50)
createdAt: Date(),
points: 50)
let score2 = GameScore(objectId: "nolo",
createdAt: Date(),
points: 60)
createdAt: Date(),
points: 60)
req.logger.info("""
Returning custom objects to the user from Cloud Code instead of querying:
\(score1); \(score2)
""")
return ParseHookResponse(success: [score1, score2])
}

// Another Parse Hook Trigger route.
app.post("user", "login", "after",
className: "_User",
className: User.className,
triggerName: .afterLogin) { req async throws -> ParseHookResponse<Bool> in
if let error: ParseHookResponse<Bool> = checkHeaders(req) {
return error
}
let parseRequest = try req.content
.decode(ParseHookTriggerRequest<User, GameScore>.self)
.decode(ParseHookTriggerObjectRequest<User, GameScore>.self)

req.logger.info("A user has logged in: \(parseRequest)")
return ParseHookResponse(success: true)
}

// A Parse Hook Trigger route for `ParseFile` where the body will not be collected into a buffer.
// A Parse Hook Trigger route for `ParseFile`.
app.on("file", "save", "before",
body: .stream,
triggerName: .beforeSave) { req async throws -> ParseHookResponse<Bool> in
if let error: ParseHookResponse<Bool> = checkHeaders(req) {
return error
}
let parseRequest = try req.content
.decode(ParseHookTriggerRequest<User, GameScore>.self)
.decode(ParseHookTriggerRequest<User>.self)

req.logger.info("A ParseFile is being saved: \(parseRequest)")
return ParseHookResponse(success: true)
Expand All @@ -213,7 +217,7 @@ app.post("file", "delete", "before",
return error
}
let parseRequest = try req.content
.decode(ParseHookTriggerRequest<User, GameScore>.self)
.decode(ParseHookTriggerRequest<User>.self)

req.logger.info("A ParseFile is being deleted: \(parseRequest)")
return ParseHookResponse(success: true)
Expand All @@ -226,35 +230,35 @@ app.post("connect", "before",
return error
}
let parseRequest = try req.content
.decode(ParseHookTriggerRequest<User, GameScore>.self)
.decode(ParseHookTriggerRequest<User>.self)

req.logger.info("A LiveQuery connection is being made: \(parseRequest)")
return ParseHookResponse(success: true)
}

// Another Parse Hook Trigger route for `ParseLiveQuery`.
app.post("score", "subscribe", "before",
className: "GameScore",
className: GameScore.className,
triggerName: .beforeSubscribe) { req async throws -> ParseHookResponse<Bool> in
if let error: ParseHookResponse<Bool> = checkHeaders(req) {
return error
}
let parseRequest = try req.content
.decode(ParseHookTriggerRequest<User, GameScore>.self)
.decode(ParseHookTriggerObjectRequest<User, GameScore>.self)

req.logger.info("A LiveQuery subscribe is being made: \(parseRequest)")
req.logger.info("A LiveQuery subscription is being made: \(parseRequest)")
return ParseHookResponse(success: true)
}

// Another Parse Hook Trigger route for `ParseLiveQuery`.
app.post("score", "event", "after",
className: "GameScore",
className: GameScore.className,
triggerName: .afterEvent) { req async throws -> ParseHookResponse<Bool> in
if let error: ParseHookResponse<Bool> = checkHeaders(req) {
return error
}
let parseRequest = try req.content
.decode(ParseHookTriggerRequest<User, GameScore>.self)
.decode(ParseHookTriggerObjectRequest<User, GameScore>.self)

req.logger.info("A LiveQuery event occured: \(parseRequest)")
return ParseHookResponse(success: true)
Expand Down
2 changes: 1 addition & 1 deletion Sources/ParseServerSwift/Utility/Functions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public func deleteHooks(_ app: Application) async {
}

func getParseServerURLs(_ urls: String? = nil) throws -> (String, [String]) {
let serverURLs = urls ?? Environment.process.PARSE_SWIFT_SERVER_URLS ?? "http://localhost:1337/parse"
let serverURLs = urls ?? Environment.process.PARSE_SERVER_SWIFT_URLS ?? "http://localhost:1337/parse"
var allServers = serverURLs.replacingOccurrences(of: " ", with: "").split(separator: ",").compactMap { String($0) }
guard let mainServer = allServers.popLast() else {
throw ParseError(code: .otherCause, message: "At least 1 server URL is required")
Expand Down
21 changes: 10 additions & 11 deletions Sources/ParseServerSwift/configure.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import ParseSwift
import Vapor

/// The key used to authenticate incoming webhook calls from a Parse Server
public var webhookKey: String? = Environment.process.PARSE_SWIFT_SERVER_WEBHOOK_KEY
public var webhookKey: String?

/// The current Hook Functions and Triggers.
public var hooks = Hooks()
Expand Down Expand Up @@ -31,13 +31,14 @@ func configure(_ app: Application, testing: Bool) throws {

app.views.use(.leaf)
// Setup current host
app.http.server.configuration.hostname = Environment.process.PARSE_SWIFT_SERVER_HOST_NAME ?? "localhost"
app.http.server.configuration.port = Int(Environment.process.PARSE_SWIFT_SERVER_PORT ?? 8081)
app.http.server.configuration.hostname = Environment.process.PARSE_SERVER_SWIFT_HOST_NAME ?? "localhost"
app.http.server.configuration.port = Int(Environment.process.PARSE_SERVER_SWIFT_PORT ?? 8081)
app.http.server.configuration.tlsConfiguration = .none
serverPathname = app.http.server.configuration.buildServerURL()
webhookKey = Environment.process.PARSE_SERVER_SWIFT_WEBHOOK_KEY

// Increases the streaming body collection limit to 500kb
app.routes.defaultMaxBodySize = ByteCount(stringLiteral: Environment.process.PARSE_SWIFT_SERVER_DEFAULT_MAX_BODY_SIZE ?? "500kb")
app.routes.defaultMaxBodySize = ByteCount(stringLiteral: Environment.process.PARSE_SERVER_SWIFT_DEFAULT_MAX_BODY_SIZE ?? "500kb")

// Parse uses tailored encoders/decoders. These can be retrieved from any ParseObject
ContentConfiguration.global.use(encoder: User.getJSONEncoder(), for: .json)
Expand All @@ -55,8 +56,8 @@ func configure(_ app: Application, testing: Bool) throws {
}

// Initialize the Parse-Swift SDK. Add any additional parameters you need
try ParseSwift.initialize(applicationId: Environment.process.PARSE_SWIFT_SERVER_APPLICATION_ID ?? "applicationId",
primaryKey: Environment.process.PARSE_SWIFT_SERVER_PRIMARY_KEY ?? "primaryKey",
try ParseSwift.initialize(applicationId: Environment.process.PARSE_SERVER_SWIFT_APPLICATION_ID ?? "applicationId",
primaryKey: Environment.process.PARSE_SERVER_SWIFT_PRIMARY_KEY ?? "primaryKey",
serverURL: parseServerURL,
usingPostForQuery: true) { _, completionHandler in
// Setup to use default certificate pinning. See Parse-Swift docs for more info
Expand All @@ -68,14 +69,12 @@ func configure(_ app: Application, testing: Bool) throws {
do {
// Check the health of all Parse-Server
try await checkServerHealth(app)
// register routes
try routes(app)
} catch {
app.shutdown()
}
}
} else {
// register routes
try routes(app)
}

// register routes
try routes(app)
}
Loading