Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 27 additions & 27 deletions MyFirstBlog/Controllers/PostsController.cs
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
namespace MyFirstBlog.Controllers;

using Microsoft.AspNetCore.Mvc;
using MyFirstBlog.Dtos;
using MyFirstBlog.Services;

[ApiController]
[Route("posts")]

public class PostsController : ControllerBase {
private IPostService _postService;

public PostsController(IPostService postService) {
_postService = postService;
}

// Get /posts
[HttpGet]
public IEnumerable<PostDto> GetPosts() {
return _postService.GetPosts();
}

// Get /posts/:slug
[HttpGet("{slug}")]
public ActionResult<PostDto> GetPost(string slug) {
var post = _postService.GetPost(slug);

if (post is null) {
return NotFound();
using System.Collections.Generic;

namespace MyFirstBlog.Controllers
{
[ApiController]
[Route("posts")]
public class PostsController : ControllerBase
{
private readonly PostService _postService;

public PostsController(PostService postService)
{
_postService = postService;
}

return post;
[HttpPost]
public IActionResult CreatePost([FromBody] CreatePostDto dto)
{
if (string.IsNullOrWhiteSpace(dto.Title))
{
return BadRequest(new Dictionary<string, List<string>>
{
{ "errors", new List<string> { "Title cannot be blank" } }
});
}

var post = _postService.CreatePost(dto);
return Created("", new Dictionary<string, PostDto> { { "post", post } });
}
}
}
10 changes: 10 additions & 0 deletions MyFirstBlog/Dtos/CreatePostDto.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace MyFirstBlog.Dtos;

public record CreatePostDto
{
public Guid Id { get; init; }
public string Title { get; init; } = default!;
public string Slug { get; init; } = default!;
public string Description { get; init; } = default!;
public DateTime CreatedDate { get; init; }
}
5 changes: 3 additions & 2 deletions MyFirstBlog/Dtos/PostDto.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
namespace MyFirstBlog.Dtos;

public record PostDto {
public record PostDto
{
public Guid Id { get; init; }
public string Title { get; init; } = default!;
public string Slug { get; init; } = default!;
public string Body { get; init; } = default!;
public string Description { get; init; } = default!;
public DateTime CreatedDate { get; init; }
}
1 change: 0 additions & 1 deletion MyFirstBlog/Entities/Post.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,5 @@ public record Post {
public Guid Id { get; init; }
public string Title { get; init; } = default!;
public string Slug { get; init; } = default!;
public string Body { get; init; } = default!;
public DateTime CreatedDate { get; init; }
}
1 change: 0 additions & 1 deletion MyFirstBlog/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ public static PostDto AsDto(this Post post) {
Id = post.Id,
Title = post.Title,
Slug = post.Slug,
Body = post.Body,
CreatedDate = post.CreatedDate
};

Expand Down
5 changes: 4 additions & 1 deletion MyFirstBlog/MyFirstBlog.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
Expand All @@ -14,8 +14,11 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.0" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0" />

</ItemGroup>

</Project>
47 changes: 16 additions & 31 deletions MyFirstBlog/Program.cs
Original file line number Diff line number Diff line change
@@ -1,48 +1,33 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using MyFirstBlog.Helpers;
using MyFirstBlog.Services;

var MyAllowLocalhostOrigins = "_myAllowLocalhostOrigins";
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

var services = builder.Services;
var env = builder.Environment;

// Add services to the container.

services.AddDbContext<DataContext>();

services.AddCors(policyBuilder => {
policyBuilder.AddPolicy( MyAllowLocalhostOrigins,
policy => {
policy.WithOrigins("http://localhost:3000").AllowAnyHeader().AllowAnyMethod();
});
});
// Use in-memory database
// builder.Services.AddDbContext<DataContext>(options =>
// options.UseInMemoryDatabase("MyFirstBlogDummyDb"));

services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
services.AddEndpointsApiExplorer();
services.AddSwaggerGen();
// Register services
builder.Services.AddScoped<IPostService, PostService>();

services.AddScoped<IPostService, PostService>();
// Add controllers and Swagger
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

var scope = app.Services.CreateScope();
await DatabaseHelper.ManageMigrationsAsync(scope.ServiceProvider);
// No migrations needed for in-memory DB

// Configure the HTTP request pipeline.
if (env.IsDevelopment())
// Middleware pipeline
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();

app.UseCors(MyAllowLocalhostOrigins);
}

if (env.IsProduction())
{
app.UseHttpsRedirection();
}

app.UseAuthorization();
Expand Down
9 changes: 9 additions & 0 deletions MyFirstBlog/Services/IPostService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using MyFirstBlog.Dtos;

namespace MyFirstBlog.Services
{
public interface IPostService
{
PostDto CreatePost(CreatePostDto dto);
}
}
44 changes: 13 additions & 31 deletions MyFirstBlog/Services/PostService.cs
Original file line number Diff line number Diff line change
@@ -1,37 +1,19 @@
namespace MyFirstBlog.Services;

using MyFirstBlog.Helpers;
using MyFirstBlog.Entities;
using System.Text.RegularExpressions;
using MyFirstBlog.Dtos;

public interface IPostService
{
IEnumerable<PostDto> GetPosts();
PostDto GetPost(String slug);
}

public class PostService : IPostService
namespace MyFirstBlog.Services
{
private DataContext _context;

public PostService(DataContext context)
{
_context = context;
}

public IEnumerable<PostDto> GetPosts()
{
return _context.Posts.Select(post => post.AsDto());
}

public PostDto GetPost(string slug)
{
return getPost(slug).AsDto();
}

private Post getPost(string slug)
public class PostService : IPostService
{
return _context.Posts.Where(a=>a.Slug==slug.ToString()).SingleOrDefault();
public PostDto CreatePost(CreatePostDto dto)
{
return new PostDto
{
Id = dto.Id != Guid.Empty ? dto.Id : Guid.NewGuid(),
Title = dto.Title,
Slug = dto.Slug,
Description = dto.Description, // <-- changed from Body to Description
CreatedDate = dto.CreatedDate != default ? dto.CreatedDate : DateTime.UtcNow
};
}
}
}
29 changes: 19 additions & 10 deletions MyFirstBlogTests/MyFirstBlogTests.csproj
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <!-- or net7.0/net8.0 if preferred -->
<IsPackable>false</IsPackable>
</PropertyGroup>

<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<!-- xUnit packages -->
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5" />

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4"/>
<PackageReference Include="NUnit" Version="3.13.1"/>
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0"/>
<PackageReference Include="coverlet.collector" Version="3.0.2"/>
</ItemGroup>
<!-- Test SDK -->
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />

<!-- Code coverage tool -->
<PackageReference Include="coverlet.collector" Version="3.0.2" />
</ItemGroup>

<ItemGroup>
<!-- Reference to main project -->
<ProjectReference Include="..\MyFirstBlog\MyFirstBlog.csproj" />
</ItemGroup>

</Project>
25 changes: 25 additions & 0 deletions MyFirstBlogTests/MyFirstBlogTests.csproj # Edit
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<!-- xUnit -->
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5" />

<!-- Test SDK -->
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />

<!-- Code coverage -->
<PackageReference Include="coverlet.collector" Version="3.0.2" />
</ItemGroup>

<ItemGroup>
<!-- Reference to main project -->
<ProjectReference Include="..\MyFirstBlog\MyFirstBlog.csproj" />
</ItemGroup>

</Project>
55 changes: 55 additions & 0 deletions MyFirstBlogTests/PostControllerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// MyFirstBlogTests/PostControllerTests.cs

using Xunit;
using MyFirstBlog.Controllers;
using MyFirstBlog.Services;
using MyFirstBlog.Dtos;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;

namespace MyFirstBlogTests
{
public class PostControllerTests
{
private readonly PostsController _controller;

public PostControllerTests()
{
_controller = new PostsController(new PostService());
}

[Fact]
public void CreatePost_ValidInput_ReturnsCreated()
{
var postDto = new CreatePostDto
{
Title = "Test Title",
Description = "Test Description"
};

var result = _controller.CreatePost(postDto) as CreatedResult;
Assert.NotNull(result);

var post = result.Value as PostDto;
Assert.Equal("Test Title", post.Title);
Assert.Equal("Test Description", post.Description);
}

[Fact]
public void CreatePost_EmptyTitle_ReturnsBadRequest()
{
var postDto = new CreatePostDto
{
Title = "",
Description = "Some content"
};

var result = _controller.CreatePost(postDto) as BadRequestObjectResult;
Assert.NotNull(result);

var errors = result.Value as Dictionary<string, List<string>>;
Assert.True(errors.ContainsKey("errors"));
Assert.Contains("Title cannot be blank", errors["errors"]);
}
}
}
Loading