Fewbit.EntityFramework.CrudApi.Abstractions
1.0.0-beta-5
dotnet add package Fewbit.EntityFramework.CrudApi.Abstractions --version 1.0.0-beta-5
NuGet\Install-Package Fewbit.EntityFramework.CrudApi.Abstractions -Version 1.0.0-beta-5
<PackageReference Include="Fewbit.EntityFramework.CrudApi.Abstractions" Version="1.0.0-beta-5" />
paket add Fewbit.EntityFramework.CrudApi.Abstractions --version 1.0.0-beta-5
#r "nuget: Fewbit.EntityFramework.CrudApi.Abstractions, 1.0.0-beta-5"
// Install Fewbit.EntityFramework.CrudApi.Abstractions as a Cake Addin #addin nuget:?package=Fewbit.EntityFramework.CrudApi.Abstractions&version=1.0.0-beta-5&prerelease // Install Fewbit.EntityFramework.CrudApi.Abstractions as a Cake Tool #tool nuget:?package=Fewbit.EntityFramework.CrudApi.Abstractions&version=1.0.0-beta-5&prerelease
EntityFramework.CrudApi.Abstractions
The EntityFramework.CrudApi.Abstractions library provides abstractions and contracts to extend the functionality of the EntityFramework.CrudApi within your projects. These abstractions allow developers to customize the behavior of CRUD (Create, Read, Update, Delete) operations exposed by the "EntityFramework.CrudApi" library.
Overview
The abstractions in this library enable developers to:
- Define custom logic, validations, or additional processing steps before or after the execution of CRUD operations on the underlying Entity Framework DbContext.
- Implement interfaces or extend base classes to tailor the behavior of the CRUD API according to specific project requirements.
Usage
Developers can include this library in their projects and utilize the provided interfaces and base classes to introduce custom logic and fine-tune the behavior of the exposed REST API.
For more information on the core library, refer to EntityFramework.CrudApi.
Example
// API Response Model
public record GetMovieResponse
{
public int Id { get; init; }
public string Title { get; init; }
public string? Description { get; init; }
public int Votes { get; init; }
public MovieUserVote? BestVoteByUser { get; init; }
public GetMovieResponse(string title, string? description)
{
Title = title;
Description = description;
}
}
public record MovieUserVote(string? Username, int Vote);
// API Request Models
public record PostMovieRequest(string Title, string? Description);
public record PutMovieRequest(PostMovieRequest Item, bool ResetVotes, List<int> RemoveVotesForUserId);
public record GetSearchMovieRequest(string? Title, int Page = 1, int PageSize = 100) : IPageable;
// API Request Validator Models
public class PutMovieRequestValidator : AbstractValidator<PutMovieRequest>
{
public PutMovieRequestValidator()
{
RuleFor(x => x.Item.Title).NotEmpty();
}
}
public class PostMovieRequestValidator : AbstractValidator<PostMovieRequest>
{
public PostMovieRequestValidator()
{
}
}
public class SearchMovieRequestValidator : AbstractValidator<GetSearchMovieRequest>
{
public SearchMovieRequestValidator()
{
RuleFor(x => x.Title).MinimumLength(500);
}
}
// API Query command (GET Request/Response): Search, Builder
public class MovieQuery(MovieStore movieStore, IMapper mapper) : IGetRequestSearchFilter<GetSearchMovieRequest, Movie>, IGetResponseBuilder<GetMovieResponse, Movie>
{
public MovieStore MovieStore { get; } = movieStore;
public IMapper Mapper { get; } = mapper;
public IQueryable<Movie> Apply(GetSearchMovieRequest filter, IQueryable<Movie> entities)
{
return filter.Title is null ? entities : entities.Where(_ => EF.Functions.Like(_.Title, $"{filter.Title}%"));
}
public async Task<GetMovieResponse> BuildAsync(Movie entity, CancellationToken cancellationToken)
{
await MovieStore.LoadNavigationsAsync(entity, cancellationToken);
return Mapper.Map<GetMovieResponse>(entity);
}
public async Task<IEnumerable<GetMovieResponse>> BuildAsync(IQueryable<Movie> entities, CancellationToken cancellationToken)
{
return await entities.ProjectTo<GetMovieResponse>(Mapper.ConfigurationProvider).ToListAsync(cancellationToken);
}
public async Task<PagedList<GetMovieResponse>> BuildAsync(IQueryable<Movie> entities, PagingInfo pagingInfo, CancellationToken cancellationToken)
{
return await entities.ToPagedListAsync<Movie, GetMovieResponse>(Mapper, pagingInfo, cancellationToken);
}
}
// API Command (POST/PUT Request): Processors
public class MovieProcessors(MovieStore movieStore) : IPostRequestProcessor<PostMovieRequest, Movie>, IPutRequestProcessor<PutMovieRequest, Movie>, IDeleteRequestProcessor<int, Movie>
{
public MovieStore MovieStore { get; } = movieStore;
public async Task<Movie> ExecutePostAsync(PostMovieRequest request, CancellationToken cancellationToken)
{
var movie = new Movie()
{
Title = request.Title,
Description = request.Description ?? request.Title
};
await MovieStore.AddAsync(movie, cancellationToken);
return movie;
}
public async Task<Movie> ExecutePutAsync(PutMovieRequest request, Movie entity, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(request);
ArgumentNullException.ThrowIfNull(entity);
await Task.Delay(1, cancellationToken);
entity.Title = request.Item.Title;
if (request.Item.Description is not null)
{
entity.Description = request.Item.Description;
}
MovieStore.Update(entity);
return entity;
}
public async Task<Movie> ExecuteDeleteAsync(Movie entity, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(entity);
await Task.Delay(1, cancellationToken);
MovieStore.Remove(entity);
return entity;
}
}
// Mapper Profile
public class MovieProfile : Profile
{
public MovieProfile()
{
CreateMap<Movie, GetMovieResponse>()
.ForMember(dto => dto.BestVoteByUser, conf => conf.MapFrom(m => m.Votes.GroupBy(v => v.User.Username).OrderByDescending(g => g.Max(v => v.Value)).Select(g => new MovieUserVote(g.Key, g.Max(v => v.Value))).FirstOrDefault()))
.ForMember(dto => dto.Votes, conf => conf.MapFrom(ol => ol.Votes.Sum(_ => _.Value)));
}
}
// Notification Handler
public class MovieNotifications : INotificationHandler<EntityUpdatedNotification<Movie, int>>
{
public Task Handle(EntityUpdatedNotification<Movie, int> notification, CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net8.0
- AutoMapper (>= 13.0.1)
- Fewbit.Bricks.Kernel.Abstractions (>= 1.1.6)
- Microsoft.EntityFrameworkCore (>= 8.0.4)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Fewbit.EntityFramework.CrudApi.Abstractions:
Package | Downloads |
---|---|
Fewbit.EntityFramework.CrudApi
EntityFramework.CrudApi is a powerful library that seamlessly integrates with DotNet Core's Minimal API approach, allowing developers to effortlessly expose their Entity Framework DbContext as RESTful APIs. With minimal configuration, this library leverages reflection to dynamically create REST resources for each Entity/Class mapped through Entity Framework, supporting standard CRUD operations (GET, PUT, POST, DELETE). Say goodbye to manual endpoint definition and boilerplate code – streamline your REST API creation process with just a single line of code |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
1.0.0-beta-5 | 62 | 5/14/2024 |
1.0.0-beta-4 | 60 | 5/14/2024 |
1.0.0-beta-3 | 68 | 4/23/2024 |
1.0.0-beta-2 | 64 | 4/22/2024 |
1.0.0-beta-1 | 97 | 1/19/2024 |
1.0.0-alpha-9 | 59 | 1/19/2024 |
1.0.0-alpha-8 | 61 | 1/19/2024 |
1.0.0-alpha-7 | 61 | 1/18/2024 |
1.0.0-alpha-6 | 71 | 1/17/2024 |
1.0.0-alpha-5 | 71 | 1/17/2024 |
1.0.0-alpha-4 | 66 | 1/16/2024 |
1.0.0-alpha-3 | 66 | 1/16/2024 |
1.0.0-alpha-2 | 70 | 1/16/2024 |
1.0.0-alpha-10 | 60 | 1/19/2024 |