Configuring data mapping
You may need to map data between some API types and Model types, known as DTO design pattern.
Apizr could handle it for you by providing an IMappingHandler
interface implementation to it.
Fortunately, there are some integration Nuget packages to do so.
Of course, you can implement your own integration, but here we'll talk about the provided ones.
Please first install this integration package of your choice:
Project | Current | Upcoming |
---|---|---|
Apizr.Integrations.AutoMapper | ||
Apizr.Integrations.Mapster |
Where:
- Apizr.Integrations.AutoMapper package brings an
IMappingHandler
implementation for AutoMapper - Apizr.Integrations.Mapster package brings an
IMappingHandler
implementation for Mapster
Defining
AutoMapper
As usually with AutoMapper, define your mapping profiles, like for example:
public class UserMinUserProfile : Profile
{
public UserMinUserProfile()
{
CreateMap<User, MinUser>()
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.FirstName));
CreateMap<MinUser, User>()
.ForMember(dest => dest.FirstName, opt => opt.MapFrom(src => src.Name));
}
}
Mapster
No need to write your own DTO classes. Mapster provides Mapster.Tool to help you generating models. And if you would like to have explicit mapping, Mapster also generates mapper class for you.
[AdaptTo("[name]Dto"), GenerateMapper]
public record Student {
...
}
Then Mapster will generate:
public record StudentDto {
...
}
public static class StudentMapper {
public static StudentDto AdaptToDto(this Student poco) { ... }
public static StudentDto AdaptTo(this Student poco, StudentDto dto) { ... }
public static Expression<Func<Student, StudentDto>> ProjectToDto => ...
}
But you can also write your own mapping configuration, like for example:
TypeAdapterConfig<TSource, TDestination>
.NewConfig()
.Ignore(dest => dest.Age)
.Map(dest => dest.FullName,
src => string.Format("{0} {1}", src.FirstName, src.LastName));
Advanced
Warning
Data Mapping with MediatR
If you plan to use MediatR integrations, one more defining step has to be done.
Only for those of you planning to use data mapping with MediatR, Apizr provide a MappedWith
attribute telling it to map api object with model object.
You’ll find another MappedCrudEntity
attribute dedicated to CRUD apis, coming with auto-registration capabilities, in case of access restricted to only local client model.
We could get a model class mapped to an api one like:
[MappedWith(typeof(User))]
public record MinUser
{
public int Id { get; init; }
public string Name { get; init; }
}
Registering
AutoMapper
First register AutoMapper as you used to do:
services.AddAutoMapper(ASSEMBLIES_CONTAINING_PROFILES);
Then you'll be able to register with this option:
// direct short configuration
options => options.WithAutoMapperMappingHandler()
// OR direct configuration
options => options.WithMappingHandler(new AutoMapperMappingHandler(YOUR_MAPPER_CONFIG))
// OR factory configuration
options => options.WithMappingHandler(() => new AutoMapperMappingHandler(YOUR_MAPPER_CONFIG))
// OR factory configuration with the service provider instance
options => options.WithMappingHandler(serviceProvider => new AutoMapperMappingHandler(YOUR_MAPPER_CONFIG))
// OR closed type configuration
options => options.WithMappingHandler<AutoMapperMappingHandler>()
// OR parameter type configuration
options => options.WithMappingHandler(typeof(AutoMapperMappingHandler))
Mapster
First register Mapster as you used to do:
var config = new TypeAdapterConfig();
// Or
// var config = TypeAdapterConfig.GlobalSettings;
services.AddSingleton(config);
services.AddScoped<IMapper, ServiceMapper>();
Then you'll be able to register with this option:
// direct short configuration
options => options.WithMapsterMappingHandler()
// OR closed type configuration
options => options.WithMappingHandler<MapsterMappingHandler>()
// OR parameter type configuration
options => options.WithMappingHandler(typeof(MapsterMappingHandler))
Using
You can tell Apizr to map data just by providing types when executing a request.
Something like:
var result = await reqResManager.ExecuteAsync<MinUser, User>((api, user) =>
api.CreateUser(user, CancellationToken.None), minUser);
Here we give a MinUser typed object to Apizr, which will be mapped to User type just before sending it. Then Apizr will map the User typed result back to MinUser type just before returning it.
There are much more overloads so you can map objects the way you need. The same while using MediatR.