Client Side Rendering

Time: 1 week
Difficulty: Medium
Code Qualtiy points: 10 points

Right now, you have a working server side rendered TODO app. However you want to access your tasks from a mobile app. Lets assume that this mobile app is written by another developer. However, he/she needs to access your tasks. In order to do that, you need to create a REST API. This means that you need to communicate via JSON objects. In this challenge, you will implement a REST API for your TODO app. Also, you will remove SSR support from your TODO app. This means that you will create a client side rendered TODO app.

1. Introduction

Client Side Rendering

Client side rendering is a technique that you render your HTML in browser. This means that you don’t need to render your HTML in your server. This means that you don’t need to use templating engines like EJS or handlebars.

REST API

REST (Representational State Transfer) is an architectural style for developing web services. REST is popular due to its simplicity and the fact that it builds upon existing systems and features of the internet’s HTTP in order to achieve its objectives, as opposed to creating new standards, frameworks and technologies. REST is a stateless client-server architecture where web services

Browser Javascript and DOM

Browser Javascript

Browsers use JavaScript to make web pages dynamic and interactive. JavaScript allows to manipulate the content, structure, and style of a web page in real-time, respond to user inputs, make asynchronous requests to the server, and much more. We are going to cover manipulating the web-content in this challenge. The JavaScript engine in the browser parses the JavaScript code. (V8 Engine for Chrome, SpiderMonkey for Firefox) The parsed JavaScript code is converted into machine code and executed. The JavaScript code can manipulate the DOM, making real-time changes to the web page content, structure, or style. JavaScript is single-threaded, but it can handle asynchronous operations using the event loop and callback queue. When an asynchronous operation is encountered, it’s offloaded, and its callback is placed in the callback queue. The event loop continuously checks if the main thread (where the synchronous code runs) is free. If it is, the event loop takes the next callback from the callback queue and executes it.

DOM

The DOM is a programming interface for HTML and XML documents. It represents the structure of a document as a tree of objects. Each node in this tree corresponds to a part of the document, for example, an element, an attribute, or text content. Mechanism that browsers use to convert HTML into DOM is below:

  • The browser parses the HTML content line by line.
  • It converts HTML elements, attributes, and text into objects.
  • These objects are structured in a tree-like form, mirroring the nested structure of the HTML tags.
  • Each object represents a part of the page and contains properties and methods that you can manipulate using JavaScript.

Resource about DOM

Sending HTTP Requests from Browser

There are multiple ways to send HTTP requests from browser. The first one is to use fetch API. This is a native API and it is supported by all browsers. The second one is to use XMLHttpRequest API. This is an old API and it is supported by all browsers. The third one is using a third party library like axios. This is a library that you can use to send HTTP requests from browser. These libraries actually wrap XMLHttpRequest or fetch API. Third party libraries generally provide easier to use APIs. However, they are not native APIs. This means that you need to include them in your project. Also, they increase the size of your project. It is recommended to use axios API. However, if you try to use fetch and XMLHttpRequest API, it will help you to understand how HTTP requests work under the hood.

File Upload and S3

Sending files over HTTP is a common need in almost every web application. In this challenge, you will try to upload files to S3. S3 is a cloud storage service provided by AWS. You can upload files to S3 and download them later. We will not use FTP because it is not a good practice to store files in your server. If you would use FTP, horizontal scaling would be a problem. Also, you would need to store files in your server. This means that you would need to pay for storage. However, S3 is a cloud storage service. This means that you will only pay for the storage that you use. Also, you can scale your application easily.

There are two approaches to upload files to S3. The first one is to upload files directly from your backend. This means that your backend will receive a file from browser and upload it to S3. The second approach is to upload files directly from browser. This means that your browser will upload a file to S3. The second approach is better because you don’t need to send files to your backend. This means that you don’t need to pay for bandwidth.

S3 Presigned Url

If you have an application where users need to upload files to your S3 bucket, you can provide them with a presigned URL to upload a file directly, without them having AWS access. This way you do not need to share AWS credentials or make the file public. The presigned URL is generated by server that has AWS credentials and permission to access the object. The URL embeds the permissions as query string parameters and a signature to ensure they can’t be tampered with. The URL is valid for a limited time, defined when the URL is created. After this time, the URL will no longer provide access to the object.

Authorization

Authentication and authorization are two different things. Authentication is the process of verifying the identity of a user. Authorization is the process of verifying that a user has access to a resource. In this challenge, you will implement a simple authorization system. This means that, it should not be possible to access a resource which belongs to another user. For example, if you have a task, it should not be possible to delete it if you are not the owner of the task. In order to do that, you need to implement a simple authorization system.

API Rate Limiting

Everything in this world is built with finite resources. if access to the API is unlimited, anyone (or anything) can use the API as much as they want at any time, potentially preventing other legitimate users from accessing the API. Here comes the API rate limiting. API rate limiting is a technique that limits the number of requests that can be made to an API within a specified time period. Here are the general steps conceptually:

  1. Identification: Identify the requester. This can typically be done using the IP address, API key, or token.

  2. Count Requests: Count the requests made by the identified user or system in a specific time window.

  3. Set Limits: Define a limit for the number of requests that can be made in that time window.

  4. Block/Allow: Allow: If the number of requests is below the limit, allow the request. Block: If the number of requests exceeds the limit, block the request and send an error message like 429 Too Many Requests.

There are helper libraries that handles all above steps for you. (‘express-rate-limit’ for Express.js) You can use them in the future.

2. Requirements

There are some rules that you need to follow. If you don’t follow them, you will get 0 points.

  1. You are not allowed to use virtual DOM libraries like React.
  2. You need to use vanilla Javascript and DOM API.
  3. You need to use a database.
  4. You need to implement JSON based HTTP REST API.
  5. You should not use any bundler like webpack or vite.

You can use libraries like axios and lodash. Also in the backend side, there are no restrictions. You can use any library you want.

Also, in order to grasp database indexing, you will write a script which will call your API endpoints. This script will be used to benchmark your API. This means that you need to implement a simple benchmarking script. This script will do the following things (please print results to console):

  • Insert 10 million tasks and measure the time it takes to insert them.
  • List all tasks and measure the time it takes to list them.
  • List all done tasks and measure the time it takes to list them.
  • List all undone tasks and measure the time it takes to list them.
  • Delete all tasks and measure the time it takes to delete them.

Also this script is very similar to integration tests. You will not write any integration tests. However, please keep in mind that integration tests consist of sending and receiving HTTP requests.

3. Features

You need to implement the following features. You will get 0 points if one of them is not implemented.

  1. List all tasks from browser (with filters done and undone tasks)
  2. Add a task from browser
  3. Mark a task as done
  4. Mark a task as undone
  5. Delete a task
  6. Update a task
  7. Authorization
  8. Signup
  9. Profile

4. Score

You will get a score for code quality.

  1. [5 pts] Easy to read code (Good comments, small functions etc.).
  2. [2 pts] Well-designed API endpoints.
  3. [1 pts]
  4. [1 pts]
  5. [1 pts]

5. Objectives

It is expected to learn these topics (or getting familiar with):

  • Basic Javascript DOM knowledge
  • Sending Http requests from browser (via fetch, xhr and axios)
  • Basic API usage (Principal of REST API)
  • HTTP File Upload
  • AWS S3 (with presigned URLs)
  • Github Actions (Simple deployment pipeline)
  • Typescript