For the longest time, I've thought about creating my own little place online, to share my thoughts and my journey as a freelance dotnet developer and consultant. After well, heck 10 years we are finally here!
The last many years, I've not really payed attention, to what was going on in the frontend world of web-site development. I've been primarly focused on integration projects and development with-in data integration via cloud-based microservices's on Microsoft Azure platform.
I quickly found out alot of things are going on in this space! - so I decided to go with a .NET Core based Web API Backend, so I wouldn't have to figure out what front-end technologies I wanted to use before I could get the project of the ground.
By abstracting the backend to an API service, we are now fully compatible with whatever frontend stratigy and technologi stack we want to go for, which is course is big a plus, the pitfall is a little more overhead in the application landscape, but seeing we are more and more moving away from monolithic application structures and trying to contain everything in micro-service's, this makes alot of sense from that perspective, even with the minor overhead. With the philosophical reasoning in place, let's get some nerdy details!
The Backend consists of an .NET Core 2.2 Web API Project, with reference to the solution's Core Project which contains currently the models of the project, currently only a BlogPost model.
public class BlogPost
{
public Guid Id { get; set; }
public DateTime CreateDate { get; set; }
public string Title { get; set; }
public byte[] Content { get; set; }
public string Summary { get; set; }
public string SmallCoverUrl { get; set; }
public string MediumCoverUrl { get; set; }
public string BigCoverUrl { get; set; }
public Enums.BlogPostCategory Category { get; set; }
public IEnumerable<string> Tags { get; set; }
}
I won't go into the details of saving and retrieing the data in this post, however currently it's just using a temporary JSON file as a db. I would probaly go for a MongoDb or similiar no-sql service / document database.
Anyway back on track. Before we setup a controller let's get some tasty 3rd party components into our solution, for this project there's one nuget you cant get away from and that is swagger / swashbuckle, an open api documentation solution, that is my go to when doing API work. You cant do an API without utilizing this nifty tool! In addtion to swashbuckle / Swagger I've also included the usage Newtonsoft.JSON as it's my prefeered library to work with json with. The default framework is also posible to use, but it's just what I'm used to.
Onces you've added your Nuget packages to the solution, let's jump over to our Startup.cs file and review some of our implementation here. Under ConfigureServies method we need to implement a few lines of code, so it looks similiar to the below. I've opted to do a few changes to the default behavejour so we handle Enums as strings and we ignore null values.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddMvc().AddJsonOptions(options =>
{
options.SerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter());
options.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;
});
services.AddSwaggerGenNewtonsoftSupport();
services.AddSwaggerGen();
}
Now for the Configure method I have included my swagger Endpoint, a tittle and also made a RoutePrefix to empty so we get our Swagger frontend in our root node of our domain.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Jais Edelmann Blog Api");
c.RoutePrefix = string.Empty;
});
app.UseMvc(endpoints =>
{
endpoints.MapRoute("DefaultApiWithAction", "Api/{controller}/{action}");
});
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseMvc();
}
Alright with the basics in place we should now have a working .NET Core 2.2 API with a nice self-explantory documentation site due to Swagger and the ability to work easily with JSON.
Let's move on to our actual controller that can deliver our BlogPost model. I've opted for 2 simple implementation's, that could be optimized if i werent on a json Db, but for our little test here, it really doesent matter. So we basicly have one method that return's all blogposts and one that returns a simple one, what I'm thinking here is 1 for the overview and 1 for the single post view. We should probaly also implement Take and Skip to have paging, but for now since our blog is empty, let's stick with bare minimum. As you can see we have 2 methods one that is a simple GET action where we will return all the posts in the blog, and if the database for some reason is empty - we initialize a new database and store it with 1 dummy post and save it and returning afterwards to our consumer.
For our single post, we accept an Guid called Id but we are utilizing the same service to get our blogposts and we simply fetch one record via a lambda expression. For enterprise development, this service would be depency injected, but for our simple implementation here i opted not to go that route.
[Route("api/[controller]")]
[ApiController]
public class BlogPostController : ControllerBase
{
[HttpGet]
public ActionResult<IEnumerable<Core.Models.BlogPost>> Get()
{
var dbService = new Services.dbService();
var db = dbService.GetDb("db.json");
if(db == null)
db = new Models.Db { blogPosts = new List<Core.Models.BlogPost> { new Core.Models.BlogPost { Id = Guid.NewGuid(), BigCoverUrl = "http://placehold.it/1920x1120" , Category = Core.Models.Enums.BlogPostCategory.Code, Content = "Hello World", CreateDate = DateTime.Now, MediumCoverUrl = "http://placehold.it/1120x640" , SmallCoverUrl = "http://placehold.it/720x432", Summary = "Sumnmary", Tags = new List<String> { "tag1", "tag2" }, Title = "Blog Sample" } } };
dbService.SaveDb(db, "db.json");
}
return db.blogPosts.ToList();
}
[HttpGet("Id")]
public ActionResult<Core.Models.BlogPost> Get(Guid Id)
{
var dbService = new Services.dbService();
var db = dbService.GetDb("db.json");
var result = db.blogPosts.SingleOrDefault(x => x.Id == Id);
if (result == null)
return BadRequest($"BlogPost with Id '{Id}' not found");
return result;
}
}
For the future I think I will go over Depency Injection in the next blog post, feedback is more than welcome and thanks for reading with so far :)