github.com/dranikpg/go-dto@v1.0.0/README.md (about) 1 ## go-dto 2 3 go-dto is an easy-to-use library for data mapping. It is intended for the creation of [data transfer objects](https://en.wikipedia.org/wiki/Data_transfer_object), hence the name. 4 5 When working with database relations and ORMS, you often fetch more data than needed. One could create subtypes for all kinds of queries, but this is not suitable for quick prototyping. Tools like [go-funk](https://github.com/thoas/go-funk) and [structs](https://github.com/fatih/structs) make your mapping code less verbose, but _you still have to write it_. 6 7 go-dto requries __only a declaration__ and contraty to many other struct mappers uses __only name-based field resolution__, works with __arbitrary deep__ structures, slices, maps, poiners, embedded structs, supports custom conversion functions, error handling... you name it! 8 9 ### Simple example 10 11 You just have to declare the values you want to extract and go-dto does the rest. 12 13 ```go 14 func GetUserPosts(c *gin.Context) { 15 var userDto struct { 16 Name string 17 Posts []struct { 18 Id int 19 Title string 20 } 21 } 22 userModel := LoadUserWithPosts(userId) 23 dto.Map(&userDto, userModel) 24 c.JSON(200, userDto) 25 } 26 ``` 27 28 ### Installation 29 30 ``` 31 go get github.com/dranikpg/go-dto 32 ``` 33 34 ### More examples 35 36 ##### Slices, maps and structs 37 38 go-dto works its way down recursively through struct fields, slices and maps. 39 40 ```go 41 var shoppingCart struct { 42 GroupedProducts map[string][]struct { 43 Name string 44 Warehouse struct { 45 Location string 46 } 47 } 48 } 49 ``` 50 51 A map of slices can be converted into a single slice. 52 53 ```go 54 var allProducts []Product = nil 55 var groupedProducts map[string][]Product = GetProducts() 56 dto.Map(&allProducts, groupedProducts) 57 ``` 58 59 ##### Emedded structs and pointers 60 61 Embedded struct fields are included. Pointers are automatically dereferenced. 62 63 ```go 64 type User struct { 65 gorm.Model 66 CompanyRefer int 67 Company *Company `gorm:"foreignKey:CompanyRefer"` 68 } 69 70 type UserDto struct { 71 ID int 72 Company struct { 73 Name string 74 } 75 } 76 ``` 77 78 #### Mapper instances 79 80 Local mapper instances can be used to add conversion and inspection functions. Mappers don't change their internal state during mapping, so they can be reused at any time. 81 82 ```go 83 mapper := dto.Mapper{} 84 mapper.Map(&to, from) 85 ``` 86 87 ##### Conversion functions 88 89 They are used to convert one type into another. Conversion functions have the highest priority. The second argument is the current mapper instance and is optional. 90 91 ```go 92 mapper.AddConvFunc(func(p RawPassword, mapper *Mapper) PasswordHash { 93 return hash(p) 94 }) 95 // Now mapper knows how to convert a RawPassword into a PasswordHash 96 ``` 97 98 ##### Inspection functions 99 100 Those are triggered _after_ a value has been successfully mapped. The value is **always taken by pointer**. 101 102 ```go 103 mapper.AddInspectFunc(func(dto *UserDto) { 104 dto.Link = GenerateLink(dto.ID) 105 }) 106 ``` 107 108 They can also be defined with a specific source type. The last argument is optional. 109 110 ```go 111 mapper.AddInspectFunc(func(dto *UserDto, user User, im *Mapper) { 112 dto.Online = IsRecent(user.LastSeen) 113 }) 114 ``` 115 116 ##### Error handling 117 118 * Both conversion and inspection functions can return errors by returning `(value, error)` and `error` respectively 119 * If go-dto failed to map one value onto another, it returns `ErrNoValidMapping` 120 * go-dto silently skips struct fields it found no source for (i.e. no fields with the same name) 121 122 Mapping stops as soon as an error is encountered. 123 124 ```go 125 mapper.AddInspectFunc(func(dto *UserDto) error { 126 if len(dto.Link) == 0 { 127 return errors.New("malformed link") 128 } 129 return nil 130 }) 131 132 err := mapper.Map(&to, from) 133 ``` 134