Skip to content

Commit 7f3d1cc

Browse files
committed
health endpoint stablized
1 parent aaa1b3d commit 7f3d1cc

File tree

10 files changed

+152
-6
lines changed

10 files changed

+152
-6
lines changed

src/Extensions/WebAppExtensions.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,24 @@ private static async Task EnsureDatabaseCreated(this WebApplication app)
6262
private static void AddEndpoints(this WebApplication app)
6363
{
6464
app.MapGet("/", () => "DotNet API Boilerplate");
65-
app.MapGet("/health", () => "Healthy");
65+
var startTime = DateTime.UtcNow;
66+
app.MapGet("/health", (HttpContext context) => {
67+
var uptime = (DateTime.UtcNow - startTime).TotalSeconds;
68+
var healthResponse = new {
69+
status = "Healthy",
70+
uptime = uptime,
71+
timestamp = DateTime.UtcNow,
72+
version = typeof(WebAppExtensions).Assembly.GetName().Version?.ToString() ?? "unknown"
73+
};
74+
context.Response.ContentType = "application/json";
75+
return Results.Json(healthResponse);
76+
})
77+
.WithOpenApi(op => {
78+
op.Summary = "Health check endpoint";
79+
op.Description = "Returns the health status, uptime, timestamp, and version of the API.";
80+
op.Responses["200"].Description = "API is healthy";
81+
return op;
82+
});
6683

6784
// app.MapGet("/secure", () => "You are authenticated!")
6885
// .RequireAuthorization(); // Protect this endpoint

src/Features/GraphQL/Types/CommentType.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ public record CreateCommentInput(
4646
public record UpdateCommentInput(
4747
int Id,
4848
string? Content = null,
49-
bool? IsApproved = null
49+
bool? IsApproved = null,
50+
string? AuthorName = null,
51+
string? AuthorEmail = null
5052
);
5153

5254
/// <summary>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using FluentValidation;
2+
3+
namespace NetAPI.Features.GraphQL.Types;
4+
5+
public class CreateCommentInputValidator : AbstractValidator<CreateCommentInput>
6+
{
7+
public CreateCommentInputValidator()
8+
{
9+
RuleFor(x => x.Content)
10+
.NotEmpty().WithMessage("Content is required")
11+
.MaximumLength(1000);
12+
RuleFor(x => x.AuthorName)
13+
.NotEmpty().WithMessage("Author name is required")
14+
.MaximumLength(50);
15+
RuleFor(x => x.AuthorEmail)
16+
.NotEmpty().WithMessage("Author email is required")
17+
.EmailAddress().WithMessage("Invalid email format");
18+
RuleFor(x => x.PostId)
19+
.GreaterThan(0).WithMessage("PostId must be positive");
20+
}
21+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using FluentValidation;
2+
3+
namespace NetAPI.Features.GraphQL.Types;
4+
5+
public class CreatePostInputValidator : AbstractValidator<CreatePostInput>
6+
{
7+
public CreatePostInputValidator()
8+
{
9+
RuleFor(x => x.Title)
10+
.NotEmpty().WithMessage("Title is required")
11+
.MaximumLength(100);
12+
RuleFor(x => x.Content)
13+
.MaximumLength(1000);
14+
RuleFor(x => x.AuthorName)
15+
.NotEmpty().WithMessage("Author name is required")
16+
.MaximumLength(50);
17+
RuleFor(x => x.BlogId)
18+
.GreaterThan(0).WithMessage("BlogId must be positive");
19+
}
20+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using FluentValidation;
2+
3+
namespace NetAPI.Features.GraphQL.Types;
4+
5+
public class UpdateCommentInputValidator : AbstractValidator<UpdateCommentInput>
6+
{
7+
public UpdateCommentInputValidator()
8+
{
9+
RuleFor(x => x.Id)
10+
.GreaterThan(0).WithMessage("Id must be positive");
11+
RuleFor(x => x.Content)
12+
.MaximumLength(1000);
13+
RuleFor(x => x.AuthorName)
14+
.MaximumLength(50);
15+
RuleFor(x => x.AuthorEmail)
16+
.EmailAddress().WithMessage("Invalid email format");
17+
}
18+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using FluentValidation;
2+
3+
namespace NetAPI.Features.GraphQL.Types;
4+
5+
public class UpdatePostInputValidator : AbstractValidator<UpdatePostInput>
6+
{
7+
public UpdatePostInputValidator()
8+
{
9+
RuleFor(x => x.Id)
10+
.GreaterThan(0).WithMessage("Id must be positive");
11+
RuleFor(x => x.Title)
12+
.MaximumLength(100);
13+
RuleFor(x => x.Content)
14+
.MaximumLength(1000);
15+
}
16+
}

src/Features/Posts/CreatePost.cs

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,57 @@
1-
namespace NetAPI.Features.Posts;
1+

2+
namespace NetAPI.Features.Posts;
23

34
using Microsoft.AspNetCore.Http.HttpResults;
45
using System.Security.Claims;
56
using NetAPI.Common.Api;
7+
using FluentValidation;
8+
using FluentValidation.Results;
9+
using Microsoft.AspNetCore.Http;
10+
using System.Linq;
11+
612
public class CreatePost : IEndpoint
713
{
814
public static void Map(IEndpointRouteBuilder app) => app
915
.MapPost("/", Handle)
10-
.WithSummary("Creates a new post");
16+
.WithSummary("Creates a new post")
17+
.WithDescription("Creates a new post with the specified title and content.")
18+
.WithName("CreatePost")
19+
.WithTags("Post");
20+
1121

1222
public record Request(string Title, string? Content);
1323
public record CreatedResponse(int Id);
1424

15-
private static Task<Ok<CreatedResponse>> Handle(Request request, ClaimsPrincipal claimsPrincipal, CancellationToken cancellationToken)
25+
// FluentValidation validator for Request
26+
public class Validator : AbstractValidator<Request>
27+
{
28+
public Validator()
29+
{
30+
RuleFor(x => x.Title)
31+
.NotEmpty().WithMessage("Title is required")
32+
.MaximumLength(100);
33+
RuleFor(x => x.Content)
34+
.MaximumLength(1000);
35+
}
36+
}
37+
38+
private static async Task<IResult> Handle(
39+
Request request,
40+
ClaimsPrincipal claimsPrincipal,
41+
CancellationToken cancellationToken)
1642
{
43+
var validator = new Validator();
44+
ValidationResult result = await validator.ValidateAsync(request, cancellationToken);
45+
if (!result.IsValid)
46+
{
47+
// Return standardized error response using ProblemDetails
48+
return Results.Problem(
49+
title: "Validation Failed",
50+
detail: string.Join("; ", result.Errors.Select(e => e.ErrorMessage)),
51+
statusCode: StatusCodes.Status400BadRequest
52+
);
53+
}
1754
var response = new CreatedResponse(2);
18-
return Task.FromResult(TypedResults.Ok(response));
55+
return TypedResults.Ok(response);
1956
}
2057
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using FluentValidation;
2+
3+
namespace NetAPI.Features.Posts;
4+
5+
public class CreatePostValidator : AbstractValidator<CreatePost.Request>
6+
{
7+
public CreatePostValidator()
8+
{
9+
RuleFor(x => x.Title)
10+
.NotEmpty().WithMessage("Title is required")
11+
.MaximumLength(100);
12+
RuleFor(x => x.Content)
13+
.MaximumLength(1000);
14+
}
15+
}

src/blog-dev.db-shm

32 KB
Binary file not shown.

src/blog-dev.db-wal

Whitespace-only changes.

0 commit comments

Comments
 (0)