For one of my hobby projects, a server-side rendered React.js app using nextjs with asp.net core 2.2 serving the web API, I’ve made a conscious decision to keep all validation server-side only to reduce the effort required on the front-end side.

As for SPA being used for a hobby project, it’s great for learning, but not so much for speedy development… when will I ever learn – but that’s a story for another time.

ASP.NET Core Side – Camel Case Serialisation

One of the first things that I do when setting up ASP.NET Core Web API is setup serialisisation for JSON resonse to property names to be camel case – why oh why is this not the default anyway?

We need to install the package Microsoft.Extensions.Configuration.Json.

Then change the actual serialiser configuration.

public class Startup
{
  // ... others
  public IServiceProvider ConfigureServices(IServiceCollection services)
  {
    services
      .AddJsonOptions(options => options.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver() );

    // other configuration stuff...

    return ConfigureIoC(services);
  }
}

Setting up our API

For setting up an API, we need a Request DTO, in this example, a login request with some approriate rules.

public class LoginRequest
{
  [Required]
  [EmailAddress]
  public string Email { get; set; }

  [Required]
  [DataType(DataType.Password)]
  public string Password { get; set; }

  [Display(Name = "Remember me?")]
  public bool RememberMe { get; set; }
}

Then a pretty standard looking controller with check for model state validation.

The most important part is the last part, where we turn it into a serialisable Dictionary.

[Route("api/v1/account")]
[AllowAnonymous]
public class ApiController : Controller
{
  [Route("login")]
  [Post]
  public async Task<IActionResult>Login([FromBody] LoginRequest login) 
  {
    if (ModelState.IsValid)
    {
      // ... logic 
    }

    return BadRequest(ModelState.ToDictionary(
      kvp => kvp.Key,
      kvp => kvp.Value.Errors.Select(e => e.ErrorMessage).ToArray()
    ));
  }
}

Given an empty request body, with Content-Type: application/json in the request header, we should receive the response:

{
  "email": [
    "The Email field is required.",
    "The Email field is not a valid e-mail address."
  ],
  "password": [
    "The Password field is required."
  ]
}

React.js Inline Error Component

Now, for our React app, we simply create a component that takes in the field name, and the errors dictionary and simply list all the errors for that particular field – simple stuff.

import * as React from 'react'

export const InlineError = ({ field, errors }) => {
  if(!errors) {
    return null
  }

  if(!errors[field]) {
    return null
  }

  return (<div className='errors-container'>
    <ul>
      {errors[field].map(error => <li>{error}</li>)}
    </ul>
  </div>)
}

We now have everything needed for displaying inline errors for our React forms.

<form>
<InlineError field='' errors={this.state.errors} />
<div className='form-group'>
  <label>Email Address</label>
  <input
    type='text'
    onChange={(evt) => this.setState({ email: evt.target.value })}
  />
  <InlineError field='email' errors={this.state.errors} />
</div>
<div className='form-group'>
  <label>Password</label>
  <input
    type='password'
    onChange={(evt) => this.setState({ password: evt.target.value })}
  />
  <InlineError field='password' errors={this.state.errors} />
</div>
<div className='form-group'>
  <button
    className='save-btn'
    onClick={this.onLoginClick.bind(this)}
  >Login
  </button>
</div>
</form>

This is the end result – not pretty, but it does the job and it took very little effort – speed > fancy stuff.

react inline errors