Skip to content

Commit

Permalink
Initial release
Browse files Browse the repository at this point in the history
  • Loading branch information
ignas-sakalauskas committed Aug 22, 2020
1 parent adf8790 commit c530984
Show file tree
Hide file tree
Showing 15 changed files with 333 additions and 0 deletions.
25 changes: 25 additions & 0 deletions SnsTestReceiver.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30406.217
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SnsTestReceiverApi", "src\SnsTestReceiverApi\SnsTestReceiverApi.csproj", "{2CA8980B-5684-4E40-A20E-257DFC843B20}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2CA8980B-5684-4E40-A20E-257DFC843B20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2CA8980B-5684-4E40-A20E-257DFC843B20}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2CA8980B-5684-4E40-A20E-257DFC843B20}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2CA8980B-5684-4E40-A20E-257DFC843B20}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {153261A3-6356-428D-9142-5594D275A9EE}
EndGlobalSection
EndGlobal
83 changes: 83 additions & 0 deletions src/SnsTestReceiverApi/Controllers/MessagesController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using Microsoft.AspNetCore.Mvc;
using SnsTestReceiverApi.Models;
using SnsTestReceiverApi.Services;
using System;
using System.IO;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

namespace SnsTestReceiverApi.Controllers
{
[ApiController]
[Route("[controller]")]
public class MessagesController : ControllerBase
{
private readonly IRepository _repository;

public MessagesController(IRepository repository)
{
_repository = repository;
}

[HttpGet]
[ActionName("GetAll")]
public IActionResult GetAll(string search, int? limit)
{
if (limit > 100)
return UnprocessableEntity(new ErrorResponse { Error = "Limit must be less then 100" });

return Ok(_repository.Search(search, limit ?? 100));
}

[HttpPost]
[ActionName("Post")]
public async Task<IActionResult> Post()
{
string content;
using (var reader = new StreamReader(Request.Body, Encoding.UTF8))
{
content = await reader.ReadToEndAsync();
}

SnsMessage message;
try
{
message = JsonSerializer.Deserialize<SnsMessage>(content, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
});
}
catch (Exception e)
{
return BadRequest(new ErrorResponse { Error = $"Parsing error: {e.Message}" });
}

if (!_repository.TryCreate(message.MessageId, message))
return Conflict(new { Error = $"Message ID={message.MessageId} already exists" });

return CreatedAtAction("Post", new CreatedResponse { Id = message.MessageId });
}

[HttpGet("{id}")]
[ActionName("Get")]
public IActionResult Get(string id)
{
var item = _repository.Get(id);
if (item == null)
return NotFound();

return Ok(item);
}

[HttpDelete("{id}")]
[ActionName("Delete")]
public IActionResult Delete(string id)
{
if (!_repository.Delete(id))
return NotFound();

return NoContent();
}
}
}
14 changes: 14 additions & 0 deletions src/SnsTestReceiverApi/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-alpine AS build
WORKDIR /app

# copy csproj and restore as distinct layers
COPY . .
RUN dotnet restore

# copy everything else and build app
RUN dotnet publish -c Release -o out

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-alpine AS runtime
WORKDIR /app
COPY --from=build /app/out ./
ENTRYPOINT ["dotnet", "SnsTestReceiverApi.dll"]
34 changes: 34 additions & 0 deletions src/SnsTestReceiverApi/Middleware/RequestLoggingMiddleware.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;

namespace SnsTestReceiverApi.Middleware
{
public class RequestLoggingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger _logger;

public RequestLoggingMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
{
_next = next;
_logger = loggerFactory.CreateLogger<RequestLoggingMiddleware>();
}

public async Task Invoke(HttpContext context)
{
try
{
await _next(context);
}
finally
{
_logger.LogInformation(
"Request {method} {url} => {statusCode}",
context.Request?.Method,
context.Request?.Path.Value,
context.Response?.StatusCode);
}
}
}
}
7 changes: 7 additions & 0 deletions src/SnsTestReceiverApi/Models/CreatedResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace SnsTestReceiverApi.Models
{
public class CreatedResponse
{
public string Id { get; set; }
}
}
7 changes: 7 additions & 0 deletions src/SnsTestReceiverApi/Models/ErrorResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace SnsTestReceiverApi.Models
{
public class ErrorResponse
{
public string Error { get; set; }
}
}
8 changes: 8 additions & 0 deletions src/SnsTestReceiverApi/Models/MessageAttributeValue.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace SnsTestReceiverApi.Models
{
public class MessageAttributeValue
{
public string Type { get; set; }
public object Value { get; set; }
}
}
20 changes: 20 additions & 0 deletions src/SnsTestReceiverApi/Models/SnsMessage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.Collections.Generic;

namespace SnsTestReceiverApi.Models
{
public class SnsMessage
{
public string Type { get; set; }
public string MessageId { get; set; }
public string TopicArn { get; set; }
public string Subject { get; set; }
public string Message { get; set; }
public Dictionary<string, MessageAttributeValue> MessageAttributes { get; set; }
= new Dictionary<string, MessageAttributeValue>();
public string Timestamp { get; set; }
public string SignatureVersion { get; set; }
public string Signature { get; set; }
public string SigningCertUrl { get; set; }
public string UnsubscribeUrl { get; set; }
}
}
20 changes: 20 additions & 0 deletions src/SnsTestReceiverApi/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;

namespace SnsTestReceiverApi
{
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<Startup>();
});
}
}
9 changes: 9 additions & 0 deletions src/SnsTestReceiverApi/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": {
"SnsTestReceiver": {
"commandName": "Project",
"applicationUrl": "http://localhost:5000"
}
}
}
13 changes: 13 additions & 0 deletions src/SnsTestReceiverApi/Services/IRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.Collections.Generic;
using SnsTestReceiverApi.Models;

namespace SnsTestReceiverApi.Services
{
public interface IRepository
{
IReadOnlyList<string> Search(string keyword, int limit);
bool TryCreate(string key, SnsMessage value);
SnsMessage Get(string key);
bool Delete(string key);
}
}
42 changes: 42 additions & 0 deletions src/SnsTestReceiverApi/Services/InMemoryRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using SnsTestReceiverApi.Models;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;

namespace SnsTestReceiverApi.Services
{
public class InMemoryRepository : IRepository
{
private readonly ConcurrentDictionary<string, SnsMessage> _storage = new ConcurrentDictionary<string, SnsMessage>();

public IReadOnlyList<string> Search(string keyword, int limit)
{
var query = _storage.Values.AsQueryable();

if (!string.IsNullOrEmpty(keyword))
{
query = query.Where(m => m.Message != null && m.Message.Contains(keyword, StringComparison.OrdinalIgnoreCase));
}

return query.Select(m=>m.MessageId).Take(limit).ToList();
}

public bool TryCreate(string key, SnsMessage value)
{
return _storage.TryAdd(key, value);
}

public SnsMessage Get(string key)
{
_storage.TryGetValue(key, out var value);

return value;
}

public bool Delete(string key)
{
return _storage.TryRemove(key, out var _);
}
}
}
7 changes: 7 additions & 0 deletions src/SnsTestReceiverApi/SnsTestReceiverApi.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>

</Project>
34 changes: 34 additions & 0 deletions src/SnsTestReceiverApi/Startup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using SnsTestReceiverApi.Middleware;
using SnsTestReceiverApi.Services;

namespace SnsTestReceiverApi
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}

public IConfiguration Configuration { get; }

public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IRepository, InMemoryRepository>();
services.AddControllers();
}

public void Configure(IApplicationBuilder app)
{
app.UseRouting();
app.UseMiddleware<RequestLoggingMiddleware>();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
10 changes: 10 additions & 0 deletions src/SnsTestReceiverApi/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}

0 comments on commit c530984

Please sign in to comment.