Fewbit.EntityFramework.CrudApi.Abstractions 1.0.0-beta-1

This is a prerelease version of Fewbit.EntityFramework.CrudApi.Abstractions.
There is a newer prerelease version of this package available.
See the version list below for details.
dotnet add package Fewbit.EntityFramework.CrudApi.Abstractions --version 1.0.0-beta-1
NuGet\Install-Package Fewbit.EntityFramework.CrudApi.Abstractions -Version 1.0.0-beta-1
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Fewbit.EntityFramework.CrudApi.Abstractions" Version="1.0.0-beta-1" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Fewbit.EntityFramework.CrudApi.Abstractions --version 1.0.0-beta-1
#r "nuget: Fewbit.EntityFramework.CrudApi.Abstractions, 1.0.0-beta-1"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Fewbit.EntityFramework.CrudApi.Abstractions as a Cake Addin
#addin nuget:?package=Fewbit.EntityFramework.CrudApi.Abstractions&version=1.0.0-beta-1&prerelease

// Install Fewbit.EntityFramework.CrudApi.Abstractions as a Cake Tool
#tool nuget:?package=Fewbit.EntityFramework.CrudApi.Abstractions&version=1.0.0-beta-1&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 Compatible and additional computed target framework versions.
.NET net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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-3 49 4/23/2024
1.0.0-beta-2 45 4/22/2024
1.0.0-beta-1 80 1/19/2024
1.0.0-alpha-9 45 1/19/2024
1.0.0-alpha-8 48 1/19/2024
1.0.0-alpha-7 47 1/18/2024
1.0.0-alpha-6 56 1/17/2024
1.0.0-alpha-5 52 1/17/2024
1.0.0-alpha-4 51 1/16/2024
1.0.0-alpha-3 52 1/16/2024
1.0.0-alpha-2 55 1/16/2024
1.0.0-alpha-10 45 1/19/2024