{"id":22868901,"url":"https://github.com/corrieriluca/realworld-actix-web","last_synced_at":"2025-03-31T11:13:47.399Z","repository":{"id":37010685,"uuid":"434173358","full_name":"corrieriluca/realworld-actix-web","owner":"corrieriluca","description":"Partial implementation of the RealWorld Example App Backend with Actix Web and PostgreSQL","archived":false,"fork":false,"pushed_at":"2023-04-13T16:47:31.000Z","size":254,"stargazers_count":2,"open_issues_count":3,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-06T16:03:57.666Z","etag":null,"topics":["actix-web","backend","realworld","realworld-backend","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/corrieriluca.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-12-02T10:19:34.000Z","updated_at":"2023-07-31T19:03:12.000Z","dependencies_parsed_at":"2025-02-06T15:53:41.518Z","dependency_job_id":"bfb04116-fae4-444e-8c88-ed1d05855704","html_url":"https://github.com/corrieriluca/realworld-actix-web","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/corrieriluca%2Frealworld-actix-web","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/corrieriluca%2Frealworld-actix-web/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/corrieriluca%2Frealworld-actix-web/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/corrieriluca%2Frealworld-actix-web/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/corrieriluca","download_url":"https://codeload.github.com/corrieriluca/realworld-actix-web/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246458001,"owners_count":20780677,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["actix-web","backend","realworld","realworld-backend","rust"],"created_at":"2024-12-13T12:44:34.953Z","updated_at":"2025-03-31T11:13:47.375Z","avatar_url":"https://github.com/corrieriluca.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ![RealWorld Example App](logo.png) \u003c!-- omit in toc --\u003e\n\n[![codecov](https://codecov.io/gh/corrieriluca/realworld-actix-web/branch/main/graph/badge.svg?token=W3M8HKYJS8)](https://codecov.io/gh/corrieriluca/realworld-actix-web) ![mit](https://img.shields.io/badge/lisence-MIT-green) ![rust](https://img.shields.io/badge/Rust-dea584?logo=rust\u0026logoColor=black)\n\n\u003e ### [Actix Web](https://actix.rs/) codebase containing real world examples (CRUD, auth, advanced patterns, etc) that adheres to the [RealWorld](https://github.com/gothinkster/realworld) spec and API.\n\n\n### [Demo](https://demo.realworld.io/)\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;[RealWorld](https://github.com/gothinkster/realworld) \u003c!-- omit in toc --\u003e\n\nThis codebase was created to demonstrate a fully fledged fullstack application named **Conduit** (Medium-like) built with **Actix Web** (4.0) including CRUD operations, authentication, routing, pagination, and more.\n\nFor more information on how to this works with other frontends/backends, head over to the [RealWorld](https://github.com/gothinkster/realworld) repo.\n\n## Other tools used \u003c!-- omit in toc --\u003e\n\n- [SQLx](https://github.com/launchbadge/sqlx), 🧰 *The Rust SQL Toolkit*\n- [PostgreSQL](https://www.postgresql.org/), *The World's Most Advanced Open Source Relational Database*\n- [Docker](https://www.docker.com/) 🐳\n- [GitHub Actions](https://github.com/features/actions) ⚙️\n\n## Table of contents \u003c!-- omit in toc --\u003e\n\n- [Introduction](#introduction)\n- [Getting started](#getting-started)\n  - [🔨 With Cargo and Docker (recommended)](#-with-cargo-and-docker-recommended)\n    - [🧪 Run Tests](#-run-tests)\n  - [📦 With Docker Compose](#-with-docker-compose)\n- [How does it work?](#how-does-it-work)\n  - [⚙️ Configuration files](#️-configuration-files)\n  - [🔑 Authentication middleware](#-authentication-middleware)\n  - [🏛 Code architecture](#-code-architecture)\n  - [🧪 Functional Tests (API)](#-functional-tests-api)\n- [Resources \u0026 Bibliography](#resources--bibliography)\n\n# Introduction\n\n**This project is a partial implementation of the RealWorld spec.**\n\nI aimed to use as much as good practices as I could from the Rust community. I also extensively used functional and unit testing in order to have a great code coverage.\n\nGitHub Actions is used to test the whole project, audit security of supply chain and continuously deliver containers.\n\nWhat is implemented is the following:\n- [x] JWT Authentication\n- [x] Users API (Registration, Login, Update)\n- [x] Profiles API (Get, Follow, Unfollow)\n- [ ] Articles API (List, Feed, Comments, Tags...)\n\n# Getting started\n\n## 🔨 With Cargo and Docker (recommended)\n\nYour first need to install the SQLx CLI:\n```\ncargo install sqlx-cli --no-default-features --features rustls,postgres\n```\n\nYou need PostgreSQL running somewhere, and to run migrations on it. To run on localhost, Docker is the preferred way:\n```\ndocker run \\\n  -e POSTGRES_USER=postgres \\\n  -e POSTGRES_PASSWORD=password \\\n  -e POSTGRES_DB=conduit \\\n  -p 5432:5432 \\\n  -d postgres:14 \\\n  postgres -N 1000\n\nsqlx database create\nsqlx migrate run\n```\n\n**💡 Tip:** For faster deployment you can use the [*dev_env.sh*](./scripts/dev_env.sh) script.\n\nFinally you can run the API on port 8080:\n```\ncargo run\n```\nAnd in another terminal (or in [Postman](https://www.postman.com/)):\n```\ncurl -i -X POST http://127.0.0.1:8080/api/users \\\n    -H \"Content-Type: application/json\" \\\n    --data '{\"user\":{\"username\":\"john\",\"email\":\"john.doe@github.com\",\"password\":\"test1234\"}}'\n```\n\n### 🧪 Run Tests\n\nMake sure a database a Postgres database is running on localhost.\n\nJust run:\n```\ncargo test\n```\n\n## 📦 With Docker Compose\n\nRunning with Docker Compose is fairly simple but not very flexible during development (requires to build the API image for each change of the source code).\n\nJust go into the `docker` folder, and run the stack:\n```\ncd docker/\ndocker compose up -d\n```\n\nThe API will be exposed on port 8080, you can run your own tests with tools such as `curl` or Postman.\n\n# How does it work?\n\n## ⚙️ Configuration files\n\nThe [`config`](https://crates.io/crates/config) crate is used to provide a convenient **layered configuration system** (satisfies [the third of the 12-factor](https://12factor.net/config)).\n\nThe config files are written in YAML and are placed under the [`configuration`](./configuration/) folder in the same directory as the app.\n\nYou can see an example of layers with the `base.yml` file which contains a default listening port and credentials for the database, and the `local.yml` and `production.yml` that overrides some settings from the base as well as adding others (such as the listening address).\n\nConfig values can also be overriden with **environment variables** (highest precedence) following this naming convention: `CONDUIT__\u003csettings-category\u003e__\u003csetting\u003e`.\n\n**Example:** override the DB hostname with `CONDUIT__DATABASE__HOST`.\n\n## 🔑 Authentication middleware\n\nAlmost all API endpoints require authentication (see [RealWorld backend specs](https://realworld-docs.netlify.app/docs/specs/backend-specs/endpoints)) with a JWT token.\n\nThis implementation thus makes use of the [`jsonwebtoken`](https://crates.io/crates/jsonwebtoken) crate coupled with a custom authentication middleware that wraps endpoints which need authentication and validate (or reject) requests before they arrive to the endpoint (adding authenticated user information on top of the request).\n\nPlease take a look at the [`auth.rs`](./src/middlewares/auth.rs) source file if you want to know more about the implementation of the middleware, code is documented.\n\n## 🏛 Code architecture\n\nThe source code of this implementation resides in the [`src`](./src/) directory:\n\n```\nsrc\n├── domain\n│   └── ...\n├── dtos\n│   └── ...\n├── handlers\n│   └── ...\n├── middlewares\n│   ├── auth.rs\n│   └── mod.rs\n├── repositories\n│   └── ...\n├── configuration.rs\n├── lib.rs\n├── main.rs\n└── startup.rs\n```\n\nThe `conduit` library is exposed through the `lib.rs` file.\n\nThe `main.rs` source file use the `configuration` and `startup` modules to respectively configure and run the application on the desired listening address and port.\n\nThe `middlewares` module contains middlewares such as the Authentication middleware described above.\n\nThe `repositories` module contains exposed functions doing SQL queries to the database.\n\nThe `dtos` module contains Data Transfer Objects (DTOs) for defining input and output types (as `struct`) of the API.\n\nThe `domain` module contains functions and modules dealing with business logic (input validation, JWT tokens...) for the API.\n\nFinally, the `handlers` module contains functions and modules for the **handlers**: the functions mapped to API endpoints. These handlers use the `dtos`, `domain` and `repositories` modules for their internal logic.\n\n## 🧪 Functional Tests (API)\n\nUnder the [`tests`](./tests/) folder, you will find all the functional tests of the application, this means API tests.\n\nEspecially, the [`reqwest`](https://crates.io/crates/reqwest), [`claim`](https://crates.io/crates/claim) and [`tokio`](https://tokio.rs/) crates are used for HTTP requests, assert functions and background tasks (e.g.: running a test server) respectively.\n\nBefore each test, a database with a random name is created, SQLx migrations are runned against it and an API server is launched in background on a random port (this is called a `TestApp` within the code). The details are in the `helpers.rs` source file.\n\n# Resources \u0026 Bibliography\n\n- [Zero To Production In Rust](https://www.zero2prod.com/) and [A learning journal](https://www.lpalmieri.com/) from [Luca Palmieri](https://github.com/LukeMathWalker), really helped me to catch good practices on Rust Web dev tooling (such as Actix, SQLx...).\n- [Demystifying Actix Web Middleware - Daniel Imfeld](https://imfeld.dev/writing/actix-web-middleware), helped me to write the Authentication middleware with the last version of Actix (v4).\n- [Actix website](https://actix.rs/) and its crate [documentation](https://docs.rs/actix-web/latest/actix_web/).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcorrieriluca%2Frealworld-actix-web","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcorrieriluca%2Frealworld-actix-web","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcorrieriluca%2Frealworld-actix-web/lists"}