Create a React-based app with ASP.NET Minimal APIs and MongoDB storage
Tags: react, dotnet, mongodb, docker
Published: 2022-06-23 22:57:53

---
title: Create a React-based app with ASP.NET Minimal APIs and MongoDB storage
published: true
description: I've been using React for while by mixing it up with .NET stuff and enjoying it a lot. For this post, I decided to combine them along Compose containers, ASP.NET Minimal APIs and MongoDB support!
tags:
- React
- DotNet
- MongoDB
- Docker
cover_image: https://stvansolano.github.io/2022/06/20/Creating-a-react-app-with-AspNet-Minimal-APIs-and-MongoDb-CosmosDb/preview.webp
---
I've been using React for while by mixing it up with .NET stuff and enjoying it a lot. For this post, I decided to combine them along Compose containers, ASP.NET Minimal APIs and MongoDB support!

> This post is also available from my blog: https://stvansolano.github.io/blog/

## Using React
I use React the tech behind my blog (mostly NodeJS/Jamstack client-side generated which I migrated recently from existing code that has been around ~2015) both for the client and server side rendering.

So this time I decided to set a sample to combine React and .NET in a sample app and ended-up packing it as Pull-Request [#248](https://github.com/docker/awesome-compose/pull/248) for the [Awesome-Compose](https://github.com/docker/awesome-compose) repo from Docker in GitHub, following same structure I did for previous .NET contributions into that repo. If you are interested in previous posts about Awesome-Compose, either curious about Docker-izing .NET 5/6 apps or using GitHub Codespaces for development you can browse them from [here](/2022/03/24/Upgrading-dotnet-5-to-6-using-minimal-apis-and-github-codespaces/) and [here](/2020/11/30/Creating-your-first-GitHub-codespace-for-F-Sharp-and-Net/).

The code for this post is also available under my GitHub in this repo:

https://github.com/stvansolano/codebox-react-dotnet-mongodb

So, let's get started! A few things you may need to install: 

- Docker Compose
- .NET 6 SDK
- NodeJS

> **Side-note:** I didn't really have to install anything while developing this on my local as I was using GitHub Codespaces with my some tailored devcontainer setup, so I can focus on development!

<img class="img-fluid box-shadow text-center" width="360" height="202" src="https://stvansolano.github.io/2022/06/20/Creating-a-react-app-with-AspNet-Minimal-APIs-and-MongoDb-CosmosDb/preview.png" alt="Preview" title="Preview">

## 1) Creating the /frontend: A simple TODO app.

For this sample, we will use `react-scripts` scaffold for creating a basic app and use a very simple, still classic sample for having a TODO app in order to focus on JavaScript, NodeJS/Npx stuff. For this sample, it contains also some files I re-used from Awesome-Compose repo:

<img class="img-fluid box-shadow text-center" width="183" height="400" src="https://stvansolano.github.io/2022/06/20/Creating-a-react-app-with-AspNet-Minimal-APIs-and-MongoDb-CosmosDb/frontend-structure.png" alt="Frontend structure" title="Frontend structure">

In order to consume our API later from ASP.NET, let's add a NGINX file for taking care of the API calls later from our ASP.NET Web API. Things will run on their own NGINX-based container so the backend is de-coupled from here.

<pre class="language-yaml">
  <code id="nginx-conf" class="language-yaml">
server {
    listen       80;
    server_name  localhost;
    
    server_tokens off;
    proxy_hide_header X-Powered-By;
    proxy_hide_header Server;
    add_header X-XSS-Protection "1; mode=block";
    add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains; preload';
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;
    add_header X-Permitted-Cross-Domain-Policies master-only;
    add_header Referrer-Policy same-origin;
    add_header Expect-CT 'max-age=60';
    
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
        try_files $uri $uri/ /index.html;
    }

    location /api {
        proxy_set_header  Host $host;
        proxy_set_header  X-Real-IP $remote_addr;
        proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header  X-Forwarded-Host $server_name;
        proxy_pass        http://backend:8000;
        proxy_redirect    default;
    }
}
</code>
</pre>

> **Important:** The .NET CLI and also Visual Studio provide a great set of pre-defined templates that also include React, Angular and more great stuff, which I encourage to give it a try. Also, pretty much of this tutorial can be also take .NET on the frontend, with the help of amazing Blazor 💖✨ 

## 2) Now it's time for .NET in the /backend: Set up Minimal API for MongoDB

Here things become more interesting. By scaffolding a new Web API from .NET 6, we can implement a very-simple, still small program to call MongoDB collection and support some basic operations for our API, and we can add Swagger+OpenAPI support with a few lines of code:

<pre class="language-dotnet">
  <code id="mongodb-aspnet" class="language-dotnet">
using System;
using System.Linq;
using System.Threading.Tasks;
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Driver;
using Models;
using Swashbuckle.AspNetCore.SwaggerGen;

var builder = WebApplication.CreateBuilder(args);

// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

string connectionString = builder.Configuration.GetConnectionString("DocumentDbConnection");
string databaseName = builder.Configuration.GetConnectionString("DocumentDbName") ?? "BackendMongoDb";
string collectionName = builder.Configuration.GetConnectionString("DocumentCollectionName") ?? "ToDos";

builder.Services.AddTransient<MongoClient>((_provider) => new MongoClient(connectionString));

var app = builder.Build();

var isSwaggerEnabledFromConfig = bool.TrueString.Equals(builder.Configuration["EnableSwagger"] ?? "", StringComparison.OrdinalIgnoreCase);
if (isSwaggerEnabledFromConfig) 
{
    Console.WriteLine("Swagger enabled via appsettings.json");
}

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment() || isSwaggerEnabledFromConfig)
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.MapGet("/api/todos", async (MongoClient connection) =>
{
    try
    {
        var database = connection.GetDatabase(databaseName);
        var collection = database.GetCollection<ToDo>(collectionName);
        var results = await collection.Find(_ => true).ToListAsync().ConfigureAwait(false);

        return Results.Ok(results);
    }
    catch (Exception ex)
    {
        return Results.Problem(detail: ex.ToString());
    }
});

app.MapGet("/api/todos/{id}", async (string id, MongoClient connection) =>
{
    try
    {
        var database = connection.GetDatabase(databaseName);
        var collection = database.GetCollection<ToDo>(collectionName);
        var result = await collection.FindAsync(record => record.Id == id).ConfigureAwait(false) as ToDo;
        
        if (result is null) 
        {
            return Results.NotFound();
        }

        return Results.Created($"/todoitems/{result.Id}", result);
    }
    catch (Exception ex)
    {
        return Results.Problem(detail: ex.ToString());
    }
});

app.MapPost("/api/todos", async (ToDo record, MongoClient connection) =>
{
    try
    {
        var database = connection.GetDatabase(databaseName);
        var collection = database.GetCollection<ToDo>(collectionName);
        await collection.InsertOneAsync(record).ConfigureAwait(false);

        return Results.Created($"/api/todos/{record.Id}", record);
    }
    catch (Exception ex)
    {
        return Results.Problem(detail: ex.ToString());
    }
});

app.Run();
  </code>
</pre>

Here is a screenshot of the backend when opening the /swagger endpoint:

<img class="img-fluid box-shadow text-center" width="400" height="377" src="https://stvansolano.github.io/2022/06/20/Creating-a-react-app-with-AspNet-Minimal-APIs-and-MongoDb-CosmosDb/swagger.png" alt="Backend swagger" title="Backend swagger">

## 3) Oh! Yes, MongoDB. Let's Compose it and wrap up with .NET!

Last but not least, let's have the Frontend in place, connect it to the Backend and store our To-Dos in MongoDB.

We can use Compose services here by just grabbing the container images and set things up. 

<pre class="language-yaml">
  <code id="compose-final" class="language-yaml">
 services:
  frontend:
    build:
      context: frontend
    ports:
      - 80:80
    volumes:
      - '.:/app'
      - '/app/node_modules'
    networks:
      - react-frontend
    depends_on:
      - backend
    links:
      - backend

  backend:
    build: backend
    restart: always
    ports:
      - 8000:8000
    depends_on: 
      - mongo
    links:
      - mongo
    environment:
      - ASPNETCORE_URLS=http://+:8000
      - EnableSwagger=true
    networks:
      - react-backend
      - react-frontend

  mongo:
    restart: always
    image: mongo:4.2.0
    volumes:
      - ./data:/data/db
    networks:
      - react-backend

  mongo-express:
    image: mongo-express
    restart: always
    ports:
      - 8081:8081
    environment:
      ME_CONFIG_MONGODB_ADMINUSERNAME: root
      ME_CONFIG_MONGODB_ADMINPASSWORD: example
    depends_on: 
      - mongo
    links:
      - mongo
    networks:
      - react-backend

networks:
  react-backend: {}
  react-frontend: {} 
  </code>
</pre>

The compose file also includes a Mongo-Express server in the Compose file so we can quickly explore the NoSQL documents and check everything end-to-end from UI in React either Swagger document generated for us with .NET

## Bonus tip: CosmosDB support out of the box!

We can take advantage of using Azure CosmosDB, which supports MongoDB connector so it's pretty easy to set-up and swap from vanilla MongoDB to use CosmosDB. Here I include some links for reference along with more samples to follow-up:

- https://docs.microsoft.com/en-us/azure/cosmos-db/mongodb/connect-using-mongoose/
- https://docs.microsoft.com/en-us/azure/cosmos-db/mongodb/mongodb-introduction/
- https://devblogs.microsoft.com/cosmosdb/build-a-node-js-app-with-azure-cosmos-dbs-api-for-mongodb/

Happy coding!