Encodes Codable
data as www-form-urlencoded
using dot-separated keys.
- Encodes and decodes Swift
Codable
data asapplication/x-www-form-urlencoded
- Expands nested structures into dot-separated keys
- Conforms to the standard
Encodable
andDecodable
protocols
.package(url: "https://github.com/omochi/form-dot-encoding.git", from: "0.1.1")
struct Profile: Codable {
let user: User
}
struct User: Codable {
let name: String
let age: Int
}
let profile = Profile(user: User(name: "Alice", age: 20))
let encoder = FormDotEncoder(mode: .form)
let result = try encoder.encode(profile)
#expect(result == "user.age=20&user.name=Alice")
By using dot-separated keys, form-dot-encoding
avoids the need to escape characters in the query string. The dot (.
) character does not require percent-encoding in URLs, making the resulting strings easy to read and debug.
In contrast, other common approaches like bracket notation require escaping brackets (%5B
and %5D
), which reduces readability in URLs.
For example:
Dot notation
foo.bar=value
Bracket notation
foo%5Bbar%5D=value
By inserting a placeholder value (_
) for empty containers, the encoder preserves the distinction between nil
and empty objects. This ensures that even collapsed or empty objects and arrays are round-trip encodable and decodable.
struct Profile: Codable & Equatable {
var primaryAddress: Address?
var secondaryAddress: Address?
var billingAddress: Address?
}
struct Address: Codable & Equatable {
var zipCode: String?
}
let profile = Profile(
primaryAddress: Address(zipCode: "12345"),
secondaryAddress: Address(),
billingAddress: nil
)
let encoder = FormDotEncoder(mode: .form)
let query = try encoder.encode(profile)
#expect(query == "primaryAddress.zipCode=12345&secondaryAddress=_")
let decoder = FormDotDecoder(mode: .form)
let decoded = try decoder.decode(Profile.self, from: query)
#expect(decoded == profile)
Swift's Codable
serialization encodes enum cases without associated values as empty objects ({}
) when using formats like JSON. The placeholder-based handling of empty containers described above allows these enum cases to be faithfully represented and round-tripped in URL-encoded data.
enum Status: Codable & Equatable {
case active
}
let status = Status.active
let encoder = FormDotEncoder(mode: .form)
let query = try encoder.encode(status)
#expect(query == "active=_")
let decoder = FormDotDecoder(mode: .form)
let decoded = try decoder.decode(Status.self, from: query)
#expect(decoded == status)
For more details and edge cases, check the test cases.