diff --git a/Apps/Api/Api.csproj b/Apps/Api/Api.csproj
new file mode 100644
index 0000000..5835475
--- /dev/null
+++ b/Apps/Api/Api.csproj
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+ net5.0
+
+
+
+ true
+ $(NoWarm);1591
+
+
+
+
+
diff --git a/Apps/Api/Api.xml b/Apps/Api/Api.xml
new file mode 100644
index 0000000..9dfee42
--- /dev/null
+++ b/Apps/Api/Api.xml
@@ -0,0 +1,28 @@
+
+
+
+ Api
+
+
+
+
+ Récupère la liste liste des derniers liens publiés.
+
+
+
+
+
+ Récupère les détails d'un lien.
+
+
+
+
+
+
+ Permet de publier un nouveau lien sur la plateforme.
+
+
+
+
+
+
diff --git a/Apps/Api/Controllers/LinksController.cs b/Apps/Api/Controllers/LinksController.cs
new file mode 100644
index 0000000..199c429
--- /dev/null
+++ b/Apps/Api/Controllers/LinksController.cs
@@ -0,0 +1,57 @@
+using System;
+using Application;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Api.Controllers
+{
+ [Route("api/links")]
+ [ApiController]
+ public class LinksController : ControllerBase
+ {
+ private readonly LinkService _linkService;
+
+ public LinksController(LinkService linkService)
+ {
+ _linkService = linkService;
+ }
+
+ ///
+ /// Récupère la liste liste des derniers liens publiés.
+ ///
+ ///
+ [HttpGet]
+ public LinkDTO[] Index()
+ {
+ return _linkService.GetAllLinks();
+ }
+
+ ///
+ /// Récupère les détails d'un lien.
+ ///
+ ///
+ ///
+ [HttpGet("{id:guid}")]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ public LinkDTO Show(Guid id)
+ {
+ return _linkService.GetLinkById(id);
+ }
+
+ ///
+ /// Permet de publier un nouveau lien sur la plateforme.
+ ///
+ ///
+ ///
+ [HttpPost]
+ [ProducesResponseType(StatusCodes.Status400BadRequest)]
+ [ProducesResponseType(StatusCodes.Status201Created)]
+ public IActionResult Create(PublishLinkCommand cmd)
+ {
+ var linkId = _linkService.PublishLink(cmd);
+
+ return CreatedAtAction(nameof(Show), new { id = linkId }, null);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Apps/Api/Program.cs b/Apps/Api/Program.cs
new file mode 100644
index 0000000..4339325
--- /dev/null
+++ b/Apps/Api/Program.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+
+namespace Api
+{
+ public class Program
+ {
+ public static void Main(string[] args)
+ {
+ CreateHostBuilder(args).Build().Run();
+ }
+
+ public static IHostBuilder CreateHostBuilder(string[] args) =>
+ Host.CreateDefaultBuilder(args)
+ .ConfigureWebHostDefaults(webBuilder =>
+ {
+ webBuilder.UseStartup();
+ });
+ }
+}
diff --git a/Apps/Api/Properties/launchSettings.json b/Apps/Api/Properties/launchSettings.json
new file mode 100644
index 0000000..ac3eee8
--- /dev/null
+++ b/Apps/Api/Properties/launchSettings.json
@@ -0,0 +1,28 @@
+{
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:11516",
+ "sslPort": 44313
+ }
+ },
+ "profiles": {
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "Api": {
+ "commandName": "Project",
+ "dotnetRunMessages": "true",
+ "launchBrowser": true,
+ "applicationUrl": "https://localhost:5001;http://localhost:5000",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/Apps/Api/Startup.cs b/Apps/Api/Startup.cs
new file mode 100644
index 0000000..67d6086
--- /dev/null
+++ b/Apps/Api/Startup.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Infrastructure;
+using Infrastructure.Filters;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+
+namespace Api
+{
+ public class Startup
+ {
+ // This method gets called by the runtime. Use this method to add services to the container.
+ // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
+ public void ConfigureServices(IServiceCollection services)
+ {
+ services.AddHNServices();
+ services.AddControllers(options =>
+ {
+ options.Filters.Add();
+ });
+ services.AddOpenApiDocument(doc =>
+ {
+ doc.PostProcess = od =>
+ {
+ od.Info.Title = "Hacker News Clone API";
+ };
+ });
+ }
+
+ // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
+ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
+ {
+ app.UseOpenApi();
+
+ if (env.IsDevelopment())
+ {
+ app.UseDeveloperExceptionPage();
+ }
+
+ app.UseSwaggerUi3();
+ // app.UseReDoc();
+
+ app.UseRouting();
+
+ app.UseEndpoints(endpoints =>
+ {
+ endpoints.MapGet("/", async context =>
+ {
+ await context.Response.WriteAsync("Hello World!");
+ });
+ endpoints.MapControllers();
+ });
+ }
+ }
+}
diff --git a/Apps/Api/api.http b/Apps/Api/api.http
new file mode 100644
index 0000000..3400d67
--- /dev/null
+++ b/Apps/Api/api.http
@@ -0,0 +1,12 @@
+@url = http://localhost:5000
+
+GET {{url}}/api/links
+
+###
+
+POST {{url}}/api/links
+Content-Type: application/json
+
+{
+ "url": "http://google.com"
+}
\ No newline at end of file
diff --git a/Apps/Api/appsettings.Development.json b/Apps/Api/appsettings.Development.json
new file mode 100644
index 0000000..8983e0f
--- /dev/null
+++ b/Apps/Api/appsettings.Development.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ }
+}
diff --git a/Apps/Api/appsettings.json b/Apps/Api/appsettings.json
new file mode 100644
index 0000000..d9d9a9b
--- /dev/null
+++ b/Apps/Api/appsettings.json
@@ -0,0 +1,10 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ },
+ "AllowedHosts": "*"
+}
diff --git a/Apps/Website/Startup.cs b/Apps/Website/Startup.cs
index 94e38aa..b0d73b7 100644
--- a/Apps/Website/Startup.cs
+++ b/Apps/Website/Startup.cs
@@ -1,6 +1,7 @@
using Application;
using Domain;
using Infrastructure;
+using Infrastructure.Filters;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
diff --git a/Apps/Website/CustomExceptionFilter.cs b/Infrastructure/Filters/CustomExceptionFilter.cs
similarity index 93%
rename from Apps/Website/CustomExceptionFilter.cs
rename to Infrastructure/Filters/CustomExceptionFilter.cs
index d7d6c8a..c5d550f 100644
--- a/Apps/Website/CustomExceptionFilter.cs
+++ b/Infrastructure/Filters/CustomExceptionFilter.cs
@@ -1,7 +1,7 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
-namespace Website
+namespace Infrastructure.Filters
{
public class CustomExceptionFilter : IExceptionFilter
{
diff --git a/hn-20-2.sln b/hn-20-2.sln
index 3469924..f277dc4 100644
--- a/hn-20-2.sln
+++ b/hn-20-2.sln
@@ -15,6 +15,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CLI", "Apps\CLI\CLI.csproj"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Website", "Apps\Website\Website.csproj", "{50B328CF-C94B-4CF6-BD4B-A3C5D122EDB4}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Api", "Apps\Api\Api.csproj", "{3514C7EF-B0C1-483A-BB9D-1CDADFC2C104}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -88,9 +90,22 @@ Global
{50B328CF-C94B-4CF6-BD4B-A3C5D122EDB4}.Release|x64.Build.0 = Release|Any CPU
{50B328CF-C94B-4CF6-BD4B-A3C5D122EDB4}.Release|x86.ActiveCfg = Release|Any CPU
{50B328CF-C94B-4CF6-BD4B-A3C5D122EDB4}.Release|x86.Build.0 = Release|Any CPU
+ {3514C7EF-B0C1-483A-BB9D-1CDADFC2C104}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3514C7EF-B0C1-483A-BB9D-1CDADFC2C104}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3514C7EF-B0C1-483A-BB9D-1CDADFC2C104}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {3514C7EF-B0C1-483A-BB9D-1CDADFC2C104}.Debug|x64.Build.0 = Debug|Any CPU
+ {3514C7EF-B0C1-483A-BB9D-1CDADFC2C104}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {3514C7EF-B0C1-483A-BB9D-1CDADFC2C104}.Debug|x86.Build.0 = Debug|Any CPU
+ {3514C7EF-B0C1-483A-BB9D-1CDADFC2C104}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3514C7EF-B0C1-483A-BB9D-1CDADFC2C104}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3514C7EF-B0C1-483A-BB9D-1CDADFC2C104}.Release|x64.ActiveCfg = Release|Any CPU
+ {3514C7EF-B0C1-483A-BB9D-1CDADFC2C104}.Release|x64.Build.0 = Release|Any CPU
+ {3514C7EF-B0C1-483A-BB9D-1CDADFC2C104}.Release|x86.ActiveCfg = Release|Any CPU
+ {3514C7EF-B0C1-483A-BB9D-1CDADFC2C104}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{F76DEBDB-E281-41B6-B476-15871F6BD8E1} = {04765FD6-F289-4A9F-8FBE-9FCB817513DD}
{50B328CF-C94B-4CF6-BD4B-A3C5D122EDB4} = {04765FD6-F289-4A9F-8FBE-9FCB817513DD}
+ {3514C7EF-B0C1-483A-BB9D-1CDADFC2C104} = {04765FD6-F289-4A9F-8FBE-9FCB817513DD}
EndGlobalSection
EndGlobal