Skip to content

SwiftProtoReflect is a dynamic Protocol Buffers library for Swift, enabling reflection-based message handling, serialization, and deserialization without the need for precompiled .proto files.

License

Notifications You must be signed in to change notification settings

truewebber/swift-protoreflect

Repository files navigation

SwiftProtoReflect

A Swift library for dynamic Protocol Buffers message manipulation without pre-compiled schemas.

Platform Swift Package Index License Coverage

Overview

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.

Installation

Add to your Package.swift:

dependencies: [
    .package(url: "https://github.com/truewebber/swift-protoreflect.git", from: "2.0.0")
]

Basic Usage

Creating Messages Dynamically

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)

Working with Well-Known Types

// 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)

Dynamic gRPC Calls

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
)

Features

  • 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

Examples

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

Requirements

  • Swift 5.9+
  • macOS 12.0+ / iOS 15.0+

Dependencies

Documentation

Use Cases

  • 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

Integration with Swift Protobuf

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()

Testing

The library has comprehensive test coverage with 866 tests covering all functionality and edge cases.

License

MIT License. See LICENSE for details.

About

SwiftProtoReflect is a dynamic Protocol Buffers library for Swift, enabling reflection-based message handling, serialization, and deserialization without the need for precompiled .proto files.

Topics

Resources

License

Stars

Watchers

Forks

Languages