mariossimou.dev
HomeBlogContact

mariossimou.dev 2.0

Published on 23rd January 2023

Front-end DevelopmentBack-end Development

Introduction

Did you miss me? For a few months now, I haven't written a post for any of my pages, which may sounds a bit weird for those who are following me. You may be thinking that I wanted to take a break, but the actual reason is that I used my time to re-organise my domain and re-write my apps with a new tech-stack. Previously, I had two webapps, one for my portofolio and another one for my blog. If you wanted to access my portofolio page, then you would visit www.mariossimou.dev. On the other hand, if you wanted to access my blog page, then you would visit www.blog.mariossimou.dev. But, why I have done this? The reason is simple.Those apps were implemented on different time periods and each time I was experimenting with different tools. As a result, I didn't really care about the structure of my domain and preferred to have a playground for me to experiment with different tools. But, after a couple of years, I wanted to do something with that. It started bothering me.

This bring us to the purpose of this post. I am writing this post to present the work I have done, as well as explain some of the design decisions I have taken. WIthout further ado, let's start.

Legacy pages

As I have already described, previously, I had two separate web apps, one for my portofolio and another one for my blog. The former was under my root domain, mariossimou.dev, and users could access it in order to display/download my CV, as well as navigate throught some of the projects that I was working on. This was a simple single-page app (SPA), and I have used create-react-app and material-ui to develop it. I have also used an S3 bucket, Cloudfront and Route53 to upload the app and make it available to the web.

The blog app was a bit more interesting. I used ghost CMS and MySQL, Unfortunately, MySQL was the only data storage solution supported from Ghost CMS, so I had to go with that; I think that's still the case, even in Ghost CMS v5. I am saying that because I am a big fan of Postgresql. If you haven't worked with Ghost CMS before, it comes with its own UI, admin dashboard and REST API. The admin is available on /ghost/admin and the API on /ghost/api/admin. Both, the frontend and admin consume the ghost API, which in turn fetches everything from the MySQL database. One thing that was bothering me was the UI, which wasn't as fancy as I wanted it to be. For that reason, I built my own UI using Next.js, and also used CSS modules for styling. In terms of hosting, I have deployed both, the frontend and Ghost CMS in heroku. The former was available on blog.mariossimou.dev and the latter on admin.mariossimou.dev.

New Pages

The inconsistency between different stacks led me to re-organise my apps. I thought that I don't need to have a separate app for my portofolio, so decided to put both, my portofolio and blog into a single app. In addition, I tried to combine a few new tools with some tools that I already know. On the one hand, I didn't want all tools to be new because the learning curve would be too high, and on the other hand, I didn't want the development to be very monotonous. As a result, I chose the below tools:

  1. Next.js

  2. Chakra-UI

  3. react-hook-form

  4. apollo

  5. Jest

  6. react-testing-library

  7. cypress

  8. Serverless Framework

  9. fly.io

  10. AWS - Cognito, API Gateway, Simple Notification Service(SNS), Simple Email Service(SES), Route53, DynamoDB

  11. Localstack

  12. react-admin

  13. GraphQL Codegen

  14. Turborepo

Next.js, Chakra UI, react-hook-form, apollo, jest, react-testing-library and Jest

I think the frontend was the most simple part because is the area I feel more comfortable. I have worked in the past with most tools I mention, except react-hook-form, but still, I didn't find it that hard. The idea of delegating the responsibility of managing the state of the form to the library, as well as the library to provide utiltiies to the consumers to manage the state, is not something new. The same idea is used by formik, which I have worked in the past. The only difference is that react-hook-form relies heavily on hooks, but formik uses a combination of hooks and higher order components(HOC).

Lastly, I used fly.io to deploy my frontend. fly.io was a new tool for me and I was suprised with how compact, simple and intuitive it is. It provides commands to monitor, curl and ssh your application, debug reading the container logs, and organise your applications under your own org. In addition, integrating the fly CLI in my pipeline was smooth. fly.io has a github action which I could use.

Serverless Framework, AWS and Localstack

There are plenty CMS solutions out there, but I wanted to builld something highly customizable. In the future, I am planning to extend my blog to include programming courses, so I knew that I had to take a step back and think for a proper design. Before I choose Serverless framework, I experimented with mongo realm, supabase and firebase, but even if they could provide most of the features I wanted (authentication, email service, serverless functions, data storage solution, analytics), I didn't feel that are exactly what I want. For that reason, I decided to be build my own serverless backend.

While developing my backend, soon I realised that development and testing wasn't so straightforward with AWS and Serverless. In order to test my changes, I had to re-deploy my backend to the cloud, which was taking a lot of time. This was breaking my develompent cycle and I wasn't very happy about it. For that reason, I added Localstack in my stack, a local emulator of AWS services, and I used it to build a network of services that I could use locally. Many of you will argue that I could use plugins(dynamodb,sns,api-gateway) in serverless framework in order to get support for some of those services, but I couldn't find any support for Cognito and SES. In addition, I didnt' want to block myself from the fact of adding more AWS services in the future, which very likely they wouldn't be available as plugins. With docker, I managed to build a network of containers, including my backend, localstack and frontend, and all of them to communicate without any issues. I even managed to get it fully working without a network connection. A have tested that a month ago, when I was on a trip back in Cyprus. For the whole time in the plane I was developing my backend, which took 5 hours, and when I got out of the plane, I released my changes and everything worked nicely.

Since Localstack and serverless were working fine after that first step, now it was time to build my backend. I developed a GraphQL API, which runs in a serverless function using the apollo-server-lambda package. I didn't choose AppSync because I found it complex and preferred to have something easier. Other than pricing, I don't think there are many differences between AppSync and a GraphQL server in a lambda, especially since I can scale my lambda as I want; either vertically providing more memory and CPU or horizontally increasing concurrency.

When I finished working with the data models of my API, I introduced a custom authorizer for authentication and the backend was ready for consumption. As a side not, I have also created a few cronjobs and SNS topics that run in the background and use for some events that I am dispatching.

react-admin

All the pieces where almost there, except the admin panel that I would use. In that case, I used react-admin to build the dashboard, which is a SPA application deployed in fly.io. The most difficult part here was the creation of a data provider, which acts as the communication bridge between the admin dashboard and the API.

Turborepo

Since I wanted to organise all my applications in a monorepo, I decided to use Turporepo, which ensured that shared dependencies between the applications, such as linters, code analysis tools and test runners were abstracted at the top and included as a single dependency. I have also created a few shared packages that were used by the consuming apps. Those packages are mainly wrappers around various SDK that I was using.

GraphQL Codegen

Since GraphQL forces you to build a type system for you backend, I wanted to utilise that schema in the frontend for my own. For that reason, I used a collection of @graphql/codegen modules in the frontend to generate types and GraphQL documents for the admin and blog apps. Those types combined with Typescript worked very well, but I need to admin, I had to invest far more time adding that setup compared of a good old REST API.

Summary

This was the end of this post, which I hoped you enjoyed it. The last few months were very interesting for me, and now is time to enjoy the work that I put re-building my blog page. With that been said, let's welcome mariossimou.dev 2.0!!

Designed by
mariossimou.dev
All rights reserved © mariossimou.dev 2023