Goal: In this exercise, the participants will be asked to build the backend of a TodoReact App. The user will be exploring the functionality of FeatherHttp, a server-side framework.
What is FeatherHttp: FeatherHttp makes it easy to write web applications.
Why FeatherHttp: FeatherHttp is lightweight server-side framework designed to scale-up as your application grows in complexity.
-
Install git.
-
Install .NET Core 3.1 SDK
-
Install the template using the following command:
dotnet new -i FeatherHttp.Templates::0.1.64-alpha.g00afb18f22 --nuget-source https://f.feedz.io/featherhttp/framework/nuget/index.json
-
Install Node.js
-
Clone this repository and navigate to the Tutorial folder, this consists of the frontend application
TodoReact
app.git clone git@github.com:featherhttp/tutorial.git featherhttp-tutorial cd featherhttp-tutorial/Tutorial
If using Visual Studio Code, install the C# extension for C# support.
- Once you clone the Todo repo, navigate to the
TodoReact
folder and run the following commands
\Tutorial\TodoReact> npm i
\Tutorial\TodoReact> npm start
- The commands above
- Restores packages
npm i
- Starts the react app
npm start
- Restores packages
-
The app will load but have no functionality
Keep this React app running as we'll need it once we build the back-end in the upcoming steps
Create a new project
- Create a new FeatherHttp application and add the necessary packages in the
TodoApi
folder
Tutorial>dotnet new feather -n TodoApi
Tutorial> cd TodoApi
Tutorial\TodoApi> dotnet add package Microsoft.EntityFrameworkCore.InMemory --version 3.1
- The commands above
- create a new FeatherHttp application
dotnet new feather -n TodoApi
- Adds the NuGet packages required in the next section
dotnet add package Microsoft.EntityFrameworkCore.InMemory --version 3.1
- create a new FeatherHttp application
- Open the
Todo
Folder in VS Code
-
Create a file called
TodoItem.cs
in the TodoApi folder. Add the content below:using System.Text.Json.Serialization; public class TodoItem { [JsonPropertyName("id")] public int Id { get; set; } [JsonPropertyName("name")] public string Name { get; set; } [JsonPropertyName("isComplete")] public bool IsComplete { get; set; } }
The above model will be used for reading in JSON and storing todo items into the database.
-
Create a file called
TodoDbContext.cs
with the following contents:using Microsoft.EntityFrameworkCore; public class TodoDbContext : DbContext { public DbSet<TodoItem> Todos { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseInMemoryDatabase("Todos"); } }
This code does 2 things:
- It exposes a
Todos
property which represents the list of todo items in the database. - The call to
UseInMemoryDatabase
wires up the in memory database storage. Data will only be persisted as long as the application is running.
- It exposes a
-
Restart the server side application but this time we're going to use
dotnet watch
:dotnet watch run
This will watch our application for source code changes and will restart the process as a result.
-
In
Program.cs
, create a method calledGetTodos
inside of theProgram
class:static async Task GetTodos(HttpContext context) { using var db = new TodoDbContext(); var todos = await db.Todos.ToListAsync(); await context.Response.WriteJsonAsync(todos); }
This method gets the list of todo items from the database and writes a JSON representation to the HTTP response.
-
Wire up
GetTodos
to theapi/todos
route by modifying the code inMain
to the following:static async Task Main(string[] args) { var app = WebApplication.Create(args); app.MapGet("/api/todos", GetTodos); await app.RunAsync(); }
-
Run the application with
dotnet run
. Navigate to the URL http://localhost:5000/api/todos in the browser. It should return an empty JSON array.
-
In
Program.cs
, create another method calledCreateTodo
inside of theProgram
class:static async Task CreateTodo(HttpContext context) { var todo = await context.Request.ReadJsonAsync<TodoItem>(); using var db = new TodoDbContext(); await db.Todos.AddAsync(todo); await db.SaveChangesAsync(); context.Response.StatusCode = 204; }
The above method reads the
TodoItem
from the incoming HTTP request and as a JSON payload and adds it to the database. -
Wire up
CreateTodo
to theapi/todos
route by modifying the code inMain
to the following:static async Task Main(string[] args) { var app = WebApplication.Create(args); app.MapGet("/api/todos", GetTodos); app.MapPost("/api/todos", CreateTodo); await app.RunAsync(); }
-
Navigate to the
TodoReact
application which should be running on http://localhost:3000. The application should be able to add new todo items. Also, refreshing the page should show the stored todo items.
-
In
Program.cs
, create another method calledUpdateTodoItem
inside of theProgram
class:static async Task UpdateCompleted(HttpContext context) { if (!context.Request.RouteValues.TryGet("id", out int id)) { context.Response.StatusCode = 400; return; } using var db = new TodoDbContext(); var todo = await db.Todos.FindAsync(id); if (todo == null) { context.Response.StatusCode = 404; return; } var inputTodo = await context.Request.ReadJsonAsync<TodoItem>(); todo.IsComplete = inputTodo.IsComplete; await db.SaveChangesAsync(); context.Response.StatusCode = 204; }
The above logic retrives the id from the route parameter "id" and uses it to find the todo item in the database. It then reads the JSON payload from the incoming request, sets the
IsComplete
property and updates the todo item in the database. -
Wire up
UpdateTodoItem
to theapi/todos/{id}
route by modifying the code inMain
to the following:static async Task Main(string[] args) { var app = WebApplication.Create(args); app.MapGet("/api/todos", GetTodos); app.MapPost("/api/todos", CreateTodo); app.MapPost("/api/todos/{id}", UpdateCompleted); await app.RunAsync(); }
-
In
Program.cs
create another method calledDeleteTodo
inside of theProgram
class:static async Task DeleteTodo(HttpContext context) { if (!context.Request.RouteValues.TryGet("id", out int id)) { context.Response.StatusCode = 400; return; } using var db = new TodoDbContext(); var todo = await db.Todos.FindAsync(id); if (todo == null) { context.Response.StatusCode = 404; return; } db.Todos.Remove(todo); await db.SaveChangesAsync(); context.Response.StatusCode = 204; }
The above logic is very similar to
UpdateTodoItem
but instead. it removes the todo item from the database after finding it. -
Wire up
DeleteTodo
to theapi/todos/{id}
route by modifying the code inMain
to the following:static async Task Main(string[] args) { var app = WebApplication.Create(args); app.MapGet("/api/todos", GetTodos); app.MapPost("/api/todos", CreateTodo); app.MapPost("/api/todos/{id}", UpdateCompleted); app.MapDelete("/api/todos/{id}", DeleteTodo); await app.RunAsync(); }