Skip to content

Instantly share code, notes, and snippets.

@KelsonBall
Last active December 20, 2020 20:46
Show Gist options
  • Save KelsonBall/b6d3236adcf0151c9cd94d9c3201084b to your computer and use it in GitHub Desktop.
Save KelsonBall/b6d3236adcf0151c9cd94d9c3201084b to your computer and use it in GitHub Desktop.
Curly Bracketn't Todos List API in C#
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>preview</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2" />
<PackageReference Include="Microsoft.AspNetCore.Routing" Version="2.2.2" />
</ItemGroup>
</Project>
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Hosting;
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Text.Json;
using System.Collections.Concurrent;
using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
int id = 1;
ConcurrentDictionary<int, TodoItem> items = new();
await Host.CreateDefaultBuilder(args)
.ConfigureServices(services => services.AddRouting())
.ConfigureWebHost(webBuilder => webBuilder
.Configure(app => app
.UseRouting()
.UseDeveloperExceptionPage()
.UseEndpoints(SetupRoutes))
.UseKestrel())
.Build()
.RunAsync();
IEndpointRouteBuilder Map(
IEndpointRouteBuilder builder,
HttpMethodRouter action,
params (string path, RequestDelegate handler)[] gets) =>
gets.Select(route => action(route.path, route.handler))
.Select(_ => builder).ToList().Last();
void SetupRoutes(IEndpointRouteBuilder route) =>
Map(Map(Map(Map(route,
route.MapGet,
("/api/todos/", GetTodoItems),
("/api/todos/{id}", GetTodoItem)),
route.MapPost,
("/api/todos/", AddTodoItem)),
route.MapPut,
("/api/todos/", UpdateTodoItem)),
route.MapDelete,
("/api/todos/{id}", DeleteTodoItem));
Task GetTodoItems(HttpContext context) =>
context.Response.WriteAsync(JsonSerializer.Serialize(items.Values.ToArray()));
Task GetTodoItem(HttpContext context) =>
context.Response.WriteAsync(JsonSerializer.Serialize(FetchByid(GetPathId(context))));
async Task AddTodoItem(HttpContext context) =>
Pass(Pass(
await ReadCreateTodoItem(context.Request),
item => items.TryAdd(item.id, item)),
item => context.Response.WriteAsync(JsonSerializer.Serialize(item)));
async Task UpdateTodoItem(HttpContext context) =>
Pass(Pass(
await ReadTodoItem(context.Request),
item => items[item.id] = item),
item => context.Response.WriteAsync(JsonSerializer.Serialize(item)));
Task DeleteTodoItem(HttpContext context) =>
Pass(Task.CompletedTask, task => items.TryRemove(GetPathId(context), out TodoItem? value));
static async Task<TodoItem> ReadTodoItem(HttpRequest request) =>
JsonSerializer.Deserialize<TodoItem>(new ReadOnlySpan<byte>(
await PassAsync(new byte[(int)request.ContentLength!],
async bytes => await request.Body.ReadAsync(bytes))))!;
async Task<TodoItem> ReadCreateTodoItem(HttpRequest request) =>
Pipe(JsonSerializer.Deserialize<CreateTodoItem>(new ReadOnlySpan<byte>(
await PassAsync(new byte[(int)request.ContentLength!],
async bytes => await request.Body.ReadAsync(bytes))))!,
create => new TodoItem(create.title, id: id++));
static int GetPathId(HttpContext context) => int.Parse((string)context.GetRouteValue("id"));
TodoItem FetchByid(int id) =>
items.TryGetValue(id, out TodoItem? item) ? item! : throw new KeyNotFoundException();
static T Pass<T, U>(T something, Func<T, U> consume) =>
consume(something) is U ? something : something;
static async Task<T> PassAsync<T, U>(T something, Func<T, Task<U>> consume) =>
await consume(something) is U ? something : something;
static U Pipe<T, U>(T something, Func<T, U> transform) => transform(something);
delegate IEndpointConventionBuilder HttpMethodRouter(string path, RequestDelegate handler);
public record CreateTodoItem(string title);
public record TodoItem(string title, int id, bool isCompleted = false);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment