I created a simple app by very fast Rust web framework Actix web. Please use this as a sample code.

lechatthecat

lechat

Posted on August 15, 2024

I created a simple app by very fast Rust web framework Actix web. Please use this as a sample code.

Background

I believe it was last year when I had an interview at a company. As part of the technical assessment, I created a simple web application using Rust, React, and Next.js. Since I built it in just a few days specifically for the interview, it may not be highly polished, but I aimed to make it as robust as possible for production use. Therefore, I think it could be a good reference for those looking to create something with Actix web. The application uses Next.js for SSG, so it should load quickly.
https://github.com/lechatthecat/assignment

Every time I start a new development project, I find it tedious to repeatedly implement the same things, like the Docker Compose YAML file, API handlers, and Next.js configurations. I also often find myself wondering, "How did I do that again?" Because of this, I think developing based on this working project could save time.

Although I didn't end up joining the company, I wanted to share this repository with everyone instead of letting it go unused. I've removed any parts related to that company and erased them from the Git history as well.

However, one of the interview conditions was not to use any ORM libraries (such as Diesel), so there are no ORMs included. If you plan to use this as a reference, please keep this in mind, and you’ll likely need to incorporate Diesel or another ORM if you build upon it.

Lastly, please don't use the test code as a reference—it's something I put together quickly under time constraints. I'm sharing this purely as a reference.

By the way, it seems that Actix web, the Rust web framework, is incredibly fast. A few years ago, it topped the charts in the benchmark below.
https://www.techempower.com/benchmarks/#hw=ph&test=fortune&section=data-r22

Although its ranking has dropped quite a bit, as of August 15, 2024, Actix ecosystem's actix-http is still in 12th place. It's probably still one of the faster frameworks, especially among the more mature ones.

How to use

This is witten in the Readme.md too:

$ git clone https://github.com/lechatthecat/assignment
$ cd assignment
$ docker compose up --build -d
Enter fullscreen mode Exit fullscreen mode

This will start release build of the Rust code. When it is done, you can access the app from this URL.
http://localhost/login

Please use the following information to login.
name: test_user1
password: password

For development

If you want to use the docker compose file for development:

$ docker compose -f docker-compose-dev.yml up -d --build
Enter fullscreen mode Exit fullscreen mode

What does the app do?

Structure

The app is divided into an API server built with Actix web and a React + Next.js application that calls it. To see which APIs are available, please refer to the API handlers.
https://github.com/lechatthecat/assignment/blob/main/simple_restaurant_api/src/api/api_handler/handlers.rs

The API server, nginx, and PostgreSQL are all set up as separate containers using Docker Compose. The code in the frontend folder is automatically synchronized within the nginx container, which serves the frontend. However, any request that starts with /api is redirected (via reverse proxy) by nginx to the Actix web server. All other requests are handled by the frontend inside the nginx container.

Overview

This is a simple SPA (though technically it's SSG with Next.js, so I'm not sure if SPA is the right term) designed for use in a restaurant with 10 tables. The idea is that each waiter has a tablet, and when taking orders, they first select the table from which the order is being placed.

Image description

After selecting the table, you'll be taken to a screen showing the list of currently received orders for that table.

Image description

When you press "Menu," you'll be taken to a page displaying the full menu, where you can click on the items that have been ordered. Each menu item includes the price and the estimated time until it's ready. By pressing "Add this to order," you can add the selected menu item to the list of received orders.

Image description

Once you add an order, a real-time countdown begins until the preparation is complete. When it reaches zero, the waiter is expected to go to the kitchen to pick up the dish and serve it to the customer at that table. You can also see the estimated time when the dish will be ready.

Image description

To be honest, the functionality itself isn't anything special. As I mentioned before, I built this in just a few days for an interview, so I only implemented the bare minimum.

Additional Recommendations

Here are a few things that I think should be added to the to-do list:

  • There’s no documentation for the API yet, so I think it would be a good idea to implement Swagger for that.
  • Implementing caching with Redis on the API side, as well as using a CDN like Cloudflare, could help reduce server load. In this case, since it’s only being used internally, I didn’t bother with it. However, if this were a publicly available app, caching would be necessary.
  • If you're hosting a service that might experience high traffic, it’s better to separate containers for the API server, frontend, and load balancer, and use Kubernetes for container management instead of Docker Compose. This makes scaling out much easier.
  • In the docker-compose.yml file, the myrust volume is bound file-by-file, as shown below. This is to avoid overwriting the container’s target folder (built within the container) with an empty target folder from the host. However, for local development, it might be more convenient to sync entire folders instead of individual files. For example, you could set up a shell script that automatically builds the project whenever the container starts. That said, this isn’t mandatory, and using a separate docker-compose.yml for development could also work. I didn’t include the shell script because, during the interview, I wanted to avoid confusing the interviewer with a 404 error that would occur while waiting for the build command (by the script) to finish, even after running docker compose up. Docker compose command wouldn't wait for the script execution to finish if it is executed as command of Dockerfile or docker compose file.
volumes:
    # log
    - ./logs:/simple_restaurant_api/log
    # Rust code
    - ./simple_restaurant_api/src:/simple_restaurant_api/src
    - ./simple_restaurant_api/Cargo.lock:/simple_restaurant_api/Cargo.lock
    - ./simple_restaurant_api/Cargo.toml:/simple_restaurant_api/Cargo.toml
Enter fullscreen mode Exit fullscreen mode
  • On the frontend, I committed the Next.js out directory, but ideally, it would be better to generate it each time the container is started using npm run build, rather than committing it. Since the focus of the interview was on the API implementation, I didn’t want to require the interviewer to run the npm run build command manually. However, for a production environment, this should be fixed (for example, by setting up an automated script to handle the build process).
  • Normally, there would be a step where the customer confirms their order (something like "Is this order correct?") before it's sent to the kitchen. This would require an additional feature to temporarily hold the order for confirmation before actually submitting it. However, since the main focus of this test was the API, I skipped it.
  • I used the unwrap function outside of tests, which isn’t good practice in Rust, especially for production environments. It would be better to replace it with the expect function (which allows for custom error messages) or, for cases where errors are likely in production, handle them explicitly with a match statement or the or_else function.
💖 💪 🙅 🚩
lechatthecat
lechat

Posted on August 15, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related