A Swift library for dynamic Protocol Buffers message manipulation without pre-compiled schemas.
SwiftProtoReflect enables runtime manipulation of Protocol Buffers messages without requiring code generation from .proto
files. This is useful for building generic tools, API gateways, data processors, and other applications that need to work with protobuf schemas dynamically.
Add to your Package.swift
:
dependencies: [
.package(url: "https://github.com/truewebber/swift-protoreflect.git", from: "2.0.0")
]
import SwiftProtoReflect
// Define a message schema at runtime
let personSchema = try MessageDescriptor.builder("Person")
.addField("name", number: 1, type: .string)
.addField("age", number: 2, type: .int32)
.addField("emails", number: 3, type: .string, label: .repeated)
.build()
// Create and populate a message
let message = try MessageFactory().createMessage(from: personSchema)
try message.set("name", value: "Alice")
try message.set("age", value: 25)
try message.set("emails", value: ["alice@example.com"])
// Serialize to binary or JSON
let binaryData = try BinarySerializer().serialize(message: message)
let jsonString = try JSONSerializer().serialize(message: message)
// Timestamps
let now = Date()
let timestampMessage = try now.toTimestampMessage()
let backToDate = try timestampMessage.toDate()
// JSON-like structures
let data: [String: Any] = ["user": "john", "active": true]
let structMessage = try data.toStructMessage()
// Type erasure
let anyMessage = try message.packIntoAny()
let unpackedMessage = try anyMessage.unpackFromAny(to: personSchema)
let client = ServiceClient(channel: grpcChannel)
let request = try MessageFactory().createMessage(from: requestSchema)
try request.set("query", value: "search term")
let response = try await client.unaryCall(
service: "search.SearchService",
method: "Search",
request: request
)
- Dynamic Message Creation: Create and manipulate protobuf messages at runtime
- Schema Definition: Build message descriptors programmatically
- Serialization: Binary and JSON serialization/deserialization
- Well-Known Types: Support for Google's standard protobuf types
- gRPC Integration: Make dynamic gRPC calls without stub generation
- Swift Protobuf Compatibility: Convert between static and dynamic messages
- Type Registry: Centralized type management and lookup
The library includes 43 working examples demonstrating various use cases:
git clone https://github.com/truewebber/swift-protoreflect.git
cd swift-protoreflect/examples
# Basic examples
swift run HelloWorld
swift run FieldTypes
swift run TimestampDemo
# Advanced examples
swift run DynamicGRPC
swift run ApiGateway
swift run MessageTransform
Examples are organized by topic:
- Basic Usage (4 examples): Getting started
- Dynamic Messages (6 examples): Message manipulation
- Serialization (5 examples): Binary and JSON formats
- Registry (4 examples): Type management
- Well-Known Types (8 examples): Google standard types
- gRPC (5 examples): Service integration
- Advanced (6 examples): Complex patterns
- Real-World (5 examples): Production scenarios
- Swift 5.9+
- macOS 12.0+ / iOS 15.0+
- SwiftProtobuf 1.29.0+
- GRPC-Swift 1.23.0+ (for gRPC features)
- Architecture Guide: Technical implementation details
- Migration Guide: Migrating from static Swift Protobuf
- Generic protobuf tools (viewers, debuggers, converters)
- API gateways with dynamic message routing
- Data processing pipelines with runtime schema handling
- Testing tools that generate data for arbitrary schemas
- Configuration systems using protobuf schemas
SwiftProtoReflect works alongside existing Swift Protobuf code:
// Convert static to dynamic
let staticMessage = Person.with { /* ... */ }
let dynamicMessage = try staticMessage.toDynamicMessage()
// Convert dynamic to static
let staticMessage: Person = try dynamicMessage.toStaticMessage()
The library has comprehensive test coverage with 866 tests covering all functionality and edge cases.
MIT License. See LICENSE for details.