AutoMap exposes a Swift macro that generates code to automatically map one Swift type to another by providing a convenient initializer. Simply annotate your local type with @AutoMap
to transform external or server-side models into your custom Swift structs or classes — no boilerplate required.
Manually mapping an external data model to your local domain model can become repetitive and error-prone. For example, if you have a model:
// Example of tedious boilerplate code in a typical project:
extension DomainEntity {
init(_ apiResponseModel: APIResponseModel.Entity) {
self.id = apiResponseModel.id
self.name = apiResponseModel.name
self.options = apiResponseModel.options.map(Option.init)
}
}
extension DomainEntity.Option {
init(_ apiResponseModel: APIResponseModel.Entity.Option) {
self.id = apiResponseModel.id
self.minLength = apiResponseModel.minLength
self.maxLength = apiResponseModel.maxLength
}
}
You end up writing—and maintaining—these boilerplate initializers over and over again. AutoMap tackles this by automatically generating such mapping code through Swift macros, so you can focus on building features instead of repetitive property assignments.
- Xcode / SwiftPM
Make sure you’re using Xcode 15 or later (or Swift 5.9+). Then addAutoMap
as a dependency to your project. - Import the Macro
In the files where you plan to use the macros, add:
import AutoMap
- Applying the Macro
Annotate your local Swift types with
@AutoMap
and specify which external type to map from. For example:
@AutoMap(from: APIModel.Entity.self, accessControl: .public)
struct DomainEntity: Identifiable, Equatable {
let id: String
let name: String
let options: [Option]
init(id: String, name: String, options: [Option]) {
self.id = id
self.name = name
self.options = options
}
/* This init is generated by `@AutoMap`; you don’t have to implement it yourself.
public init(_ apiModel: APIModel.Entity) {
self.init(id: apiModel.id, name: apiModel.name, options: apiModel.options.map(Entity.Option.init))
}
*/
}
extension DomainEntity {
@AutoMap(from: APIModel.Entity.Option.self, accessControl: .public)
struct Option: Identifiable, Equatable {
let id: String
let minLength: Int
let maxLength: Int
init(id: String, minLength: Int, maxLength: Int) {
self.id = id
self.minLength = minLength
self.maxLength = maxLength
}
/* This init is generated by `@AutoMap`; you don’t have to implement it yourself.
public init(_ apiModel: APIModel.Entity.Option) {
self.init(id: apiModel.id, minLength: apiModel.minLength, maxLength: apiModel.maxLength)
}
*/
}
}
When you build your project, the @AutoMap macro automatically generates a public
initializer for DomainEntity
and its nested Option
struct that accepts an APIModel.Entity
(and APIModel.Entity.Option
) instance respectively.
That’s all there is to it! You no longer need to write repetitive mapping code—just rely on AutoMap to generate the boilerplate for you.
-
Swift Tools Version
AutoMap
relies on Swift Macros, which require Swift 5.9 (Xcode 15) or later. Older Swift versions won’t compile macros.
-
Property Name Matching
- The macro expects properties in your local type to match those in the source type—both in name and type signature. If you rename a property or change its type, you’ll need to handle that explicitly.
-
Complex Type Structures
- While
AutoMap
can handle nested types, deeply nested structures or advanced generics may introduce edge cases. Tests for extremely complex type hierarchies are still limited.
- While
-
Optional & Custom Mappings
- Currently,
AutoMap
generates straightforward “one-to-one” initializers. If you need more nuanced mapping logic or special transformation (e.g., converting fromString
toURL
), you may still need to write some custom code or post-processing.
- Currently,
-
No Partial Initialization
- The macro generates a single convenience initializer that sets all declared properties. If you need partial initializers, you must implement them manually.
-
Limited Diagnostics
- Error messages might not always be descriptive when macro expansion fails (e.g., name mismatches or type mismatches). This is an area of active improvement.
-
Mandatory Explicit Initializer
@AutoMap
requires that any annotated struct or class define a designated initializer. Relying on a compiler-synthesized initializer will not work, as it’s overshadowed by the macro. If you don’t provide an explicit initializer, the macro-generated mapping initializer will fail to compile.
Despite these limitations, AutoMap
is designed to handle the majority of straightforward property-mapping cases so you can avoid boilerplate code and focus on your application’s core logic.