Swift and Convex type conversion
Custom data types
Convex lets you easily express your data in the backend as TypeScript objects,
and can return those objects from queries, mutations and actions. To handle
objects on the Swift side, create struct
definitions that conform to the
Decodable
protocol. Usually that’s fairly trivial to do, as any struct
with
all Decodable
members can automatically conform.
Consider a Convex query function that returns results like this JavaScript object:
{
name: "Guardians",
uniformColors: ["blue", "white", "red"],
wins: 80n,
losses: 60n
}
That can be represented in Swift using:
struct BaseballTeam: Decodable {
let name: String
let uniformColors: [String]
@ConvexInt
var wins: Int
@ConvexInt
var losses: Int
}
Then you can pass that type as the yielding argument in your subscribe call:
convex.subscribe(to: "mlb:first_place_team",
with: ["division": "AL Central"],
yielding: BaseballTeam.self)
The data from the remote function will be deserialized to your custom struct. Often your use of the type can be inferred from the calling context, and you can skip the yielding argument.
Numerical types
Numeric types like Int
and Double
are encoded in a special format to ensure
proper interoperation with your TypeScript backend functions. To safely use them
on the Swift side, ensure that you use one of the following property wrappers.
Type | Wrapper |
---|---|
Float or Double | @ConvexFloat |
Float? or Double? | @OptionalConvexFloat |
Int or Int32 or Int64 | @ConvexInt |
Int? or Int32? or Int64? | @OptionalConvexInt |
Note that struct
properties with wrappers must be declared as var
.
Field name conversion
If your code receives objects with names that you need to or want to translate
to different names, you can use a CodingKeys
enum
to specify a mapping of
remote names to names on your struct. For example, imagine a backend function or
API that returns log entries like the following representing when someone came
in and went out:
{name: "Bob", in: "2024-10-03 08:00:00", out: "2024-10-03 11:00:00"}
That data can’t decode directly into a struct
because in
is a keyword in
Swift. We can use CodingKeys
to give it an alternate name while still
ingesting the data from the original name.
struct Log: Decodable {
let name: String
let inTime: String
let outTime: String
enum CodingKeys: String, CodingKey {
case name
case inTime = "in"
case outTime = "out"
}
}
Putting it all together
In the custom data type example above, JavaScript's BigInt
type is used in the
backend data by adding a trailing n
to the wins
and losses