Skip to main content

Your First API

Learn how to create your first CRUD API with MasLazu.AspNet Framework.

Overview

In this tutorial, you'll create a complete Product API with CRUD operations using the MasLazu.AspNet Framework. We'll cover:

  • Setting up entities and DTOs
  • Configuring the database context
  • Creating service implementations
  • Building API endpoints
  • Testing your API

Prerequisites

Before starting, make sure you have:

Step 1: Create the Product Entity

First, let's create a simple Product entity:

// Entities/Product.cs
using MasLazu.AspNet.Framework.Domain.Entities;

namespace MyApp.Entities;

public class Product : BaseEntity
{
public string Name { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public decimal Price { get; set; }
public int StockQuantity { get; set; }
public string Category { get; set; } = string.Empty;
public bool IsActive { get; set; } = true;
}

Step 2: Create the Product DTO

Create a DTO for API operations:

// DTOs/ProductDto.cs
using MasLazu.AspNet.Framework.Application.Models;

namespace MyApp.DTOs;

public record ProductDto(
Guid Id,
string Name,
string Description,
decimal Price,
int StockQuantity,
string Category,
bool IsActive,
DateTimeOffset CreatedAt,
DateTimeOffset? UpdatedAt
) : BaseDto(Id, CreatedAt, UpdatedAt);

public record CreateProductRequest(
string Name,
string Description,
decimal Price,
int StockQuantity,
string Category
);

public record UpdateProductRequest(
string Name,
string Description,
decimal Price,
int StockQuantity,
string Category,
bool IsActive
);

Step 3: Configure the Database Context

Add the Product entity to your DbContext:

// Data/AppDbContext.cs
using MasLazu.AspNet.Framework.EfCore.Data;
using MyApp.Entities;
using Microsoft.EntityFrameworkCore;

namespace MyApp.Data;

public class AppDbContext : BaseDbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }

public DbSet<Product> Products { get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);

// Configure Product entity
modelBuilder.Entity<Product>(entity =>
{
entity.Property(e => e.Name)
.IsRequired()
.HasMaxLength(100);

entity.Property(e => e.Description)
.HasMaxLength(500);

entity.Property(e => e.Price)
.HasPrecision(18, 2);

entity.Property(e => e.Category)
.IsRequired()
.HasMaxLength(50);

entity.HasIndex(e => e.Name);
entity.HasIndex(e => e.Category);
});
}
}

Step 4: Create the Product Service

Implement the CRUD service:

// Services/ProductService.cs
using MasLazu.AspNet.Framework.Application.Interfaces;
using MasLazu.AspNet.Framework.Application.Services;
using MyApp.Entities;
using MyApp.DTOs;
using AutoMapper;

namespace MyApp.Services;

public class ProductService : CrudService<Product, ProductDto>
{
public ProductService(
IRepository<Product> repository,
IReadRepository<Product> readRepository,
IMapper mapper)
: base(repository, readRepository, mapper)
{
}

// Add custom business logic here if needed
public async Task<IEnumerable<ProductDto>> GetProductsByCategoryAsync(
string category,
CancellationToken ct = default)
{
var products = await ReadRepository
.GetAsync(p => p.Category == category && p.IsActive, ct);
return Mapper.Map<IEnumerable<ProductDto>>(products);
}
}

Step 5: Configure AutoMapper

Create mapping profiles:

// Mapping/ProductMappingProfile.cs
using AutoMapper;
using MyApp.Entities;
using MyApp.DTOs;

namespace MyApp.Mapping;

public class ProductMappingProfile : Profile
{
public ProductMappingProfile()
{
CreateMap<Product, ProductDto>();
CreateMap<CreateProductRequest, Product>();
CreateMap<UpdateProductRequest, Product>();
CreateMap<ProductDto, Product>();
}
}

Step 6: Create API Endpoints

Create FastEndpoints for your API:

// Endpoints/Products/GetProductEndpoint.cs
using MasLazu.AspNet.Framework.Endpoint.Endpoints;
using MasLazu.AspNet.Framework.Endpoint.EndpointGroups;
using MyApp.DTOs;
using MyApp.Services;

namespace MyApp.Endpoints.Products;

public class GetProductEndpoint : BaseEndpoint<GetProductRequest, ProductDto>
{
private readonly ProductService _productService;

public GetProductEndpoint(ProductService productService)
{
_productService = productService;
}

public override void Configure()
{
Get("/products/{id}");
Group<V1EndpointGroup>();
Summary("Get a product by ID");
}

public override async Task HandleAsync(GetProductRequest req, CancellationToken ct)
{
var product = await _productService.GetByIdAsync(req.Id, ct);

if (product == null)
{
await SendNotFoundAsync(ct);
return;
}

await SendOkAsync(product, ct);
}
}

public record GetProductRequest(Guid Id);
// Endpoints/Products/CreateProductEndpoint.cs
using MasLazu.AspNet.Framework.Endpoint.Endpoints;
using MasLazu.AspNet.Framework.Endpoint.EndpointGroups;
using MyApp.DTOs;
using MyApp.Services;

namespace MyApp.Endpoints.Products;

public class CreateProductEndpoint : BaseEndpoint<CreateProductRequest, ProductDto>
{
private readonly ProductService _productService;

public CreateProductEndpoint(ProductService productService)
{
_productService = productService;
}

public override void Configure()
{
Post("/products");
Group<V1EndpointGroup>();
Summary("Create a new product");
}

public override async Task HandleAsync(CreateProductRequest req, CancellationToken ct)
{
var productDto = new ProductDto(
Guid.Empty, // Will be set by the service
req.Name,
req.Description,
req.Price,
req.StockQuantity,
req.Category,
true, // New products are active by default
DateTimeOffset.UtcNow,
null
);

var created = await _productService.CreateAsync(productDto, ct);
await SendCreatedAtAsync<GetProductEndpoint>(new { created.Id }, created, cancellation: ct);
}
}

Step 7: Register Services

Configure dependency injection in Program.cs:

// Program.cs
using MasLazu.AspNet.Framework.EfCore.Postgresql.Extensions;
using MasLazu.AspNet.Framework.Endpoint.Extensions;
using MyApp.Data;
using MyApp.Services;
using MyApp.Mapping;

var builder = WebApplication.CreateBuilder(args);

// Add MasLazu.AspNet services
builder.Services.AddMasLazuFramework();
builder.Services.AddMasLazuPostgreSQL<AppDbContext>(builder.Configuration);
builder.Services.AddMasLazuEndpoints();

// Add AutoMapper
builder.Services.AddAutoMapper(typeof(ProductMappingProfile));

// Add application services
builder.Services.AddScoped<ProductService>();

var app = builder.Build();

// Configure pipeline
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}

app.UseMasLazuEndpoints();

app.Run();

Step 8: Run Migrations

Create and apply database migrations:

# Add migration
dotnet ef migrations add CreateProductTable

# Update database
dotnet ef database update

Step 9: Test Your API

Start your application and test the endpoints:

dotnet run

Create a Product

curl -X POST http://localhost:5000/api/v1/products \
-H "Content-Type: application/json" \
-d '{
"name": "Sample Product",
"description": "A great product",
"price": 29.99,
"stockQuantity": 100,
"category": "Electronics"
}'

Get a Product

curl http://localhost:5000/api/v1/products/{product-id}

Get Products with Pagination

curl "http://localhost:5000/api/v1/products?page=1&pageSize=10&orderBy=name&orderAscending=true"

Next Steps

Congratulations! You've created your first API with MasLazu.AspNet. Next, you can:

Complete Code

You can find the complete example code in our GitHub repository.