API REST serverless construida con Azure Functions v4 y .NET 8 que implementa un CRUD completo para la gestiΓ³n de productos, utilizando Entity Framework Core con PostgreSQL como base de datos.
- Arquitectura
- TecnologΓas
- Estructura del Proyecto
- Prerrequisitos
- ConfiguraciΓ³n
- EjecuciΓ³n Local
- Endpoints API
- Flujos de la AplicaciΓ³n
- DocumentaciΓ³n OpenAPI
- Docker
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Azure Functions Host β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β ββββββββββββββββ βββββββββββββββββββ ββββββββββββββββββ β
β β HTTP βββββΆβ Middleware βββββΆβ Functions β β
β β Trigger β β (Logging) β β (Endpoints) β β
β ββββββββββββββββ βββββββββββββββββββ βββββββββ¬βββββββββ β
β β β
β βββββββββΌβββββββββ β
β β IProductServiceβ β
β β (Service) β β
β βββββββββ¬βββββββββ β
β β β
β βββββββββΌβββββββββ β
β β DbContext β β
β β (EF Core) β β
β βββββββββ¬βββββββββ β
β β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββΌββββββββββββ
β
βββββββββΌβββββββββ
β PostgreSQL β
β Database β
ββββββββββββββββββ
| TecnologΓa | VersiΓ³n | DescripciΓ³n |
|---|---|---|
| .NET | 8.0 | Framework principal |
| Azure Functions | v4 | Plataforma serverless |
| Entity Framework Core | 8.0.10 | ORM para acceso a datos |
| PostgreSQL (Npgsql) | 8.0.10 | Base de datos relacional |
| Ardalis.Result | 10.1.0 | PatrΓ³n Result para manejo de respuestas |
| OpenAPI | 1.5.1 | DocumentaciΓ³n de API |
| Application Insights | 2.22.0 | Monitoreo y telemetrΓa |
FunctionApp/
βββ Database/
β βββ Configurations/
β β βββ ProductConfiguration.cs # ConfiguraciΓ³n de entidad EF Core
β βββ Constants/
β β βββ TableNames.cs # Constantes de nombres de tablas
β βββ ApplicationDbContext.cs # Contexto de base de datos
βββ Entities/
β βββ Product.cs # Entidad de dominio
βββ Extensions/
β βββ HostExtensions.cs # Extensiones para migraciones
β βββ HttpRequestExtensions.cs # Extensiones para HttpRequest
βββ Functions/
β βββ CreateProduct.cs # POST /api/products
β βββ GetAllProducts.cs # GET /api/products
β βββ GetProductById.cs # GET /api/products/{id}
β βββ UpdateProduct.cs # PUT /api/products/{id}
β βββ DeleteProduct.cs # DELETE /api/products/{id}
βββ Middlewares/
β βββ CustomMiddleware.cs # Middleware de logging
βββ Migrations/
β βββ ... # Migraciones de EF Core
βββ Services/
β βββ Abstraction/
β β βββ IProductService.cs # Interfaz del servicio
β βββ ProductService.cs # ImplementaciΓ³n del servicio
βββ Program.cs # Punto de entrada
βββ host.json # ConfiguraciΓ³n del host
βββ local.settings.json # ConfiguraciΓ³n local
- .NET 8 SDK
- Azure Functions Core Tools v4
- PostgreSQL (local o en la nube)
- Visual Studio 2022 o VS Code
Crea un archivo local.settings.json en la raΓz del proyecto FunctionApp:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
"Postgres": "Host=localhost;Database=ProductsDb;Username=postgres;Password=tu_password"
}
}Las migraciones se aplican automΓ‘ticamente al iniciar la aplicaciΓ³n mediante el mΓ©todo ApplyMigrations() en Program.cs.
Para crear nuevas migraciones manualmente:
cd FunctionApp
dotnet ef migrations add NombreMigracioncd FunctionApp
func start- Abrir la soluciΓ³n
- Establecer
FunctionAppcomo proyecto de inicio - Presionar F5
docker build -t simple-azure-function .
docker run -p 7071:80 simple-azure-functionLa API estarΓ‘ disponible en: http://localhost:7071/api/
| MΓ©todo | Ruta | DescripciΓ³n | Request Body | Response |
|---|---|---|---|---|
GET |
/api/products |
Obtener todos los productos | - | List<Product> |
GET |
/api/products/{id} |
Obtener producto por ID | - | Product o 404 |
POST |
/api/products |
Crear nuevo producto | CreateProductRequest |
Guid |
PUT |
/api/products/{id} |
Actualizar producto | UpdateProductRequest |
204 o 404 |
DELETE |
/api/products/{id} |
Eliminar producto | - | 204 o 404 |
CreateProductRequest
{
"name": "Producto Ejemplo",
"description": "DescripciΓ³n del producto",
"price": 99.99
}UpdateProductRequest
{
"description": "Nueva descripciΓ³n",
"price": 149.99
}{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"name": "Producto Ejemplo",
"description": "DescripciΓ³n del producto",
"price": 99.99
}ββββββββββββ ββββββββββββββββ ββββββββββββββββββ βββββββββββββββ ββββββββββββββ
β Cliente ββββββΆβ HTTP Trigger ββββββΆβ CustomMiddlewareββββββΆβCreateProductββββββΆβProductServiceβ
ββββββββββββ ββββββββββββββββ ββββββββββββββββββ ββββββββ¬βββββββ ββββββββ¬ββββββ
β β
β Create() β
βββββββββββββββββββββ
β β
βββββββΌββββββ βββββββΌββββββ
β Return β β DbContext β
β Guid β β SaveAsyncβ
βββββββββββββ βββββββ¬ββββββ
β
βββββββΌββββββ
βPostgreSQL β
β INSERT β
βββββββββββββ
Pasos detallados:
- El cliente envΓa una peticiΓ³n POST con el body JSON
- El HTTP Trigger activa la funciΓ³n
CreateProduct - El
CustomMiddlewareregistra la entrada en logs - Se deserializa el request usando
HttpRequestExtensions.GetBody<T>() - Se llama a
IProductService.Create()con los datos ProductServicecrea una nueva entidadProduct- EF Core persiste el producto en PostgreSQL
- Se retorna el GUID del producto creado
ββββββββββββ ββββββββββββββββ ββββββββββββββββββ βββββββββββββββββ
β Cliente ββββββΆβ HTTP Trigger ββββββΆβ CustomMiddlewareββββββΆβGetAllProducts β
ββββββββββββ ββββββββββββββββ ββββββββββββββββββ βββββββββ¬ββββββββ
β
βββββββΌββββββ
βProductServiceβ
β GetAll() β
βββββββ¬ββββββ
β
βββββββΌββββββ
β DbContext β
βToListAsyncβ
βββββββ¬ββββββ
β
βββββββΌββββββ
βPostgreSQL β
β SELECT * β
βββββββ¬ββββββ
β
βββββββΌββββββ
βReturn JSONβ
βList<Product>β
βββββββββββββ
Pasos detallados:
- El cliente envΓa una peticiΓ³n GET
- Se ejecuta el middleware de logging
ProductService.GetAll()ejecuta una consulta a la base de datos- EF Core traduce la consulta a SQL
SELECT - Se retorna la lista de productos como JSON
ββββββββββββ ββββββββββββββββ βββββββββββββββββ βββββββββββββββ
β Cliente ββββββΆβ HTTP Trigger ββββββΆβGetProductById ββββββΆβProductServiceβ
ββββββββββββ ββββββββββββββββ βββββββββββββββββ ββββββββ¬βββββββ
β
βββββββΌββββββ
β GetById() β
βResult<T> β
βββββββ¬ββββββ
β
ββββββββββββββββββββββΌβββββββββββββββββββββ
β β β
βββββββΌββββββ βββββββΌββββββ βββββββΌββββββ
β Existe β β Producto β βNo Existe β
β β β β Found β β β β
βββββββ¬ββββββ βββββββββββββ βββββββ¬ββββββ
β β
βββββββΌββββββ βββββββΌββββββ
β Return β β Return β
β 200 + JSONβ β 404 β
βββββββββββββ βββββββββββββ
Pasos detallados:
- El cliente envΓa GET con el GUID en la ruta
ProductService.GetById()busca el producto- Se usa el patrΓ³n
Result<T>de Ardalis.Result - Si existe β retorna
200 OKcon el producto - Si no existe β retorna
404 Not Found
ββββββββββββ ββββββββββββββββ βββββββββββββββ βββββββββββββββ
β Cliente ββββββΆβ HTTP Trigger ββββββΆβUpdateProductββββββΆβProductServiceβ
β PUT β β β β β β Update() β
ββββββββββββ ββββββββββββββββ βββββββββββββββ ββββββββ¬βββββββ
β
βββββββΌββββββ
βFind Productβ
βby ID β
βββββββ¬ββββββ
β
ββββββββββββββββββββββββΌβββββββββββββββββββββββ
β β β
βββββββΌββββββ βββββββΌββββββ βββββββΌββββββ
β Existe β β Update β βNo Existe β
β β βββββββββββΆβEntity β β β β
βββββββββββββ βββββββ¬ββββββ βββββββ¬ββββββ
β β
βββββββΌββββββ βββββββΌββββββ
βSaveChangesβ β Return β
βReturn 204 β β 404 β
βββββββββββββ βββββββββββββ
Pasos detallados:
- El cliente envΓa PUT con ID en ruta y datos en body
- Se deserializa
UpdateProductRequest ProductService.Update()busca el producto- Si existe β actualiza
DescriptionyPrice - EF Core persiste los cambios
- Retorna
204 No Contento404 Not Found
ββββββββββββ ββββββββββββββββ βββββββββββββββ βββββββββββββββ
β Cliente ββββββΆβ HTTP Trigger ββββββΆβDeleteProductββββββΆβProductServiceβ
β DELETE β β β β β β Delete() β
ββββββββββββ ββββββββββββββββ βββββββββββββββ ββββββββ¬βββββββ
β
βββββββΌββββββ
βFind Productβ
βββββββ¬ββββββ
β
ββββββββββββββββββββββββΌβββββββββββββββββββββββ
β β β
βββββββΌββββββ βββββββΌββββββ βββββββΌββββββ
β Existe β β Remove β βNo Existe β
β β βββββββββββΆβ Entity β β β β
βββββββββββββ βββββββ¬ββββββ βββββββ¬ββββββ
β β
βββββββΌββββββ βββββββΌββββββ
βSaveChangesβ β Return β
βReturn 204 β β 404 β
βββββββββββββ βββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Program.cs - Startup β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β 1. HostBuilder β
β β β
β ββββΆ ConfigureFunctionsWebApplication() β
β β ββββΆ UseMiddleware<CustomMiddleware>() β
β β β
β ββββΆ ConfigureServices() β
β β ββββΆ AddDbContext<ApplicationDbContext>() β
β β β ββββΆ UseNpgsql(connectionString) β
β β β β
β β ββββΆ AddScoped<IProductService, ProductService>() β
β β β
β ββββΆ ConfigureOpenApi() β
β β
β 2. Build() β
β β β
β ββββΆ host.ApplyMigrations() β
β ββββΆ Database.Migrate() β
β β
β 3. Run() β
β ββββΆ AplicaciΓ³n lista para recibir requests β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
La API incluye documentaciΓ³n OpenAPI/Swagger automΓ‘tica. DespuΓ©s de iniciar la aplicaciΓ³n, accede a:
- Swagger UI:
http://localhost:7071/api/swagger/ui - OpenAPI JSON:
http://localhost:7071/api/openapi/v3.json
Cada endpoint estΓ‘ documentado con:
- OperaciΓ³n y tags
- ParΓ‘metros de ruta
- Request body schemas
- Response schemas y cΓ³digos de estado
El proyecto estΓ‘ configurado para ejecutarse en contenedores Docker con soporte para Linux.
El proyecto incluye configuraciΓ³n para Docker con:
- Target OS: Linux
- Mount directory:
/home/site/wwwroot
Postgres=Host=db;Database=ProductsDb;Username=postgres;Password=password
AzureWebJobsStorage=UseDevelopmentStorage=true
FUNCTIONS_WORKER_RUNTIME=dotnet-isolatedEste proyecto estΓ‘ bajo la licencia MIT.
Repositorio: SimpleAzureFunction