// swift-tools-version:6.0
import PackageDescription
let package = Package(
name: "TestServer",
platforms: [
.macOS(.v13)
],
dependencies: [
// 💧 A server-side Swift web framework.
.package(url: "https://github.com/vapor/vapor.git", from: "4.111.0"),
.package(url: "https://github.com/vapor/fluent", from: "4.12.0"),
.package(url: "https://github.com/vapor/fluent-sqlite-driver", from: "4.8.0"),
.package(url: "https://github.com/vapor/sql-kit", from: "3.33.2"),
.package(url: "https://github.com/lukaskubanek/LoremSwiftum", from: "2.2.3"),
.package(url: "https://github.com/vapor/fluent-postgres-driver", from:"2.10.0"),
.package(url: "https://github.com/vapor/jwt", from: "5.1.2"),
.package(url: "https://github.com/vapor/queues-redis-driver.git", from: "1.0.0"),
],
targets: [
.target(
name: "App",
dependencies: [
.product(name: "Vapor", package: "vapor"),
.product(name: "Fluent", package: "fluent"),
.product(name: "FluentSQLiteDriver", package: "fluent-sqlite-driver"),
.product(name: "SQLKit", package: "sql-kit"),
.product(name: "LoremSwiftum", package: "LoremSwiftum"),
.product(name: "JWT", package: "jwt"),
.product(name: "FluentPostgresDriver", package: "fluent-postgres-driver"),
.product(name: "QueuesRedisDriver", package: "queues-redis-driver")
],
swiftSettings: [
// Enable better optimizations when building in Release configuration. Despite the use of
// the `.unsafeFlags` construct required by SwiftPM, this flag is recommended for Release
// builds. See <https://github.com/swift-server/guides#building-for-production> for details.
.unsafeFlags(["-cross-module-optimization"], .when(configuration: .release))
]
),
.executableTarget(name: "Run", dependencies: [
.target(name: "App")
]
),
.testTarget(name: "AppTests", dependencies: [
.target(name: "App"),
.product(name: "XCTVapor", package: "vapor")
])
]
)
Create an AsyncScheduledJob
import Foundation
import Vapor
import Queues
struct ScheduledJobs: AsyncScheduledJob {
// Add extra services here via dependency injection, if you need them.
func run(context: QueueContext) async throws {
context.logger.info("Starting ScheduledJobs")
print("✅ It is called")
//Call other services using context.application.client
// context.application.client
context.logger.info("ScheduledJobs completed")
}
}
Hope my articles helps you who want to run scheduled job using Redis. Please like my post or leave a comment it helps me continue share my knowledge for free.
This post is for whom want to use AWS Lambda with OpenAPI Generator. Official guide is useful but I felt there are some missing information. So I wrote this post. You can successfully run AWS Lambda function on your local machine and debug your code.
Let’s start from very simple example. You only need 4 files. I’ll explain details. (Ignore Tests folder, no need it in this tutorial)
Package.swift
NativeMobileServer.swift
openapi.yaml
openapi-generator-config.yaml
Step 1. Define OpenAPI Spec
This OpenAPI spec is for tutorial.
Please check folder and file structure. Create an openapi.yaml
openapi: 3.1.0
info:
title: MobileJobService
version: 1.0.0
paths:
/jobs/fetch:
post:
summary: Fetch job data from external source
description: >
This endpoint is called by a scheduled Lambda or backend service.
It fetches job data from the given URL and processes it using the provided prompt.
operationId: fetchJobs
tags:
- jobs
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/FetchJobsRequest'
responses:
'200':
description: Successfully fetched and processed job data
content:
application/json:
schema:
$ref: '#/components/schemas/JobListResponse'
'400':
description: Invalid input parameters
'500':
description: Internal error during job fetch or processing
components:
schemas:
FetchJobsRequest:
type: object
required:
- url
- prompt
properties:
url:
type: string
format: uri
description: Target URL to scrape or fetch job data from
prompt:
type: string
description: Instruction / extraction prompt used to parse the fetched page
JobListResponse:
type: array
items:
$ref: '#/components/schemas/Job'
Job:
type: object
required:
- id
- title
properties:
id:
type: string
description: Unique identifier for the job
title:
type: string
description: Job title
country:
type: string
description: Country code (e.g. SG, US, TW)
city:
type: string
description: City name (e.g. Singapore)
postedAt:
type: string
format: date-time
description: When this job was posted, if known
company:
type: string
description: Company name
team:
type: string
description: Team / department (e.g. Mobile, Backend, Growth)
jobDescriptionLink:
type: string
format: uri
description: Public link to full job description
jobApplyLink:
type: string
format: uri
description: Public link to apply
salary:
$ref: '#/components/schemas/Salary'
description:
type: string
description: Cleaned / extracted full-text description for the role
Salary:
type: object
properties:
min:
type: number
description: Minimum compensation
max:
type: number
description: Maximum compensation
basis:
type: string
enum: [year, month]
description: Salary period basis (yearly or monthly)
And I can see the results from AWS Lambda function
Conclusion
Swift is very powerful for developing server-side applications. There a lot of great open source projects. In Part 2, I’ll explain how to deploy AWS Lambda Swift function to the AWS using SAM CLI.
Choosing a server can be challenging, especially if you’re not a backend engineer but still need one for your iOS app. You may find yourself in this situation.
So, Why did I consider CloudKit?
Well, first off, it’s maintained by Apple and has been around since its introduction at the 2014 WWDC.
Apple actively uses it for various apps like Photos and Notes, which gives me confidence in its longevity and reliability. Plus, I expect it to receive regular updates from Apple.
My experience
Parse.com
I used Parse (Acquired by Facebook) and contributed to the Parse iOS SDK. I liked it, but Facebook announced its discontinuation.
Consequently, I had to migrate to alternatives like back4app or Sashido.io, which serve as alternatives to parse.com. While they were good, I encountered issues with the lack of active updates to the iOS SDK. This led me to contribute to its development, but I felt it was a waste of time. I wanted to focus on my app rather than on open-source projects.
I like Vapor because I can create a server using Swift, which is a significant benefit as an iOS Engineer. Additionally, there are numerous helpful resources available, such as books, YouTube videos, and Udemy courses.
But why did I consider CloudKit?
Unlike CloudKit, I would need to implement server logic from scratch, including authentication, deployment, database setup, migration, and data sharing between users.
My approach
Context
I’ve already implemented a server using Vapor to handle authentication. While working on sharing data between users, I researched an easy way to implement the invite/accept feature and found that CloudKit fully supports it.
The server I implemented using Vapor is deployed on AWS, using ECS with a Load Balancer. Its primary role is handling SignIn/SignUp and supporting user-related features such as changing passwords and usernames. All user information is saved in PostgreSQL.
For data synchronization across user devices, I utilize NSPersistentCloudKitContainer, which syncs data between CoreData and CloudKit seamlessly. This integration is very convenient and eliminates the need for manual synchronization logic.
CloudKit also supports invite and accept functionality for sharing data between users, eliminating the need to implement server-side logic for this feature.
I can access and edit CloudKit’s data using CloudKit Web Service. NSPersistentCloudKitContainer use a special zone called com.apple.coredata.cloudkit.zone. If you’re interested how to access it using CloudKit Web Service, you can check out Reading CloudKit Records for Core Data.
Public Data
As for public data storage, I haven’t decided yet where to store it. I’ll update you once I make a decision.
How about CloudKit costs?
Currently, the pricing seems like a black box. I can’t find pricing information on the Apple Developer website. That’s why I can’t decide where I should store public data.
If you want to know AWS costs, see my previous post.
I’ve been using AWS to host my Vapor Swift server, but currently, there’s no traffic as I am just running the server 24/7.
Monthly Costs:
The total cost is approximately $65 per month, with the most expensive service being RDB (using PostgreSQL). Here’s a list of the AWS services I’m using:
EC2 T2.nano Instance for AWS Cloud9
RDB (PostgreSQL)
Elastic Load Balancer
ECS Fargate, CPU: .25 vCPU, Memory: .5GB (500MB)
Breakdown of Service Costs:
Conclusion
I’m sharing the expenses with two friends, so it’s not too burdensome for me at the moment. However, I’m considering turning off the EC2-Other (Cloud 9 Service) as I only use it to access the terminal for checking database tables.
Despite this, I plan to continue using AWS as switching to another service would be time-consuming. This year, my focus is on monetizing my app through in-app purchases or Adsense. Hopefully, this will cover my server hosting costs.
You must be logged in to post a comment.