{"id":23407697,"url":"https://github.com/bestia-dev/database_web_ui_on_server","last_synced_at":"2025-04-09T00:49:17.172Z","repository":{"id":105010955,"uuid":"528415679","full_name":"bestia-dev/database_web_ui_on_server","owner":"bestia-dev","description":"07. Tutorial for Coding a Database Web UI in Rust (2022-08)","archived":false,"fork":false,"pushed_at":"2025-03-29T15:47:33.000Z","size":823,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-29T16:30:08.182Z","etag":null,"topics":["maintained","ready-for-use","tutorial","youtube"],"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/bestia-dev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"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":"2022-08-24T12:32:57.000Z","updated_at":"2025-03-29T15:47:36.000Z","dependencies_parsed_at":"2024-03-02T22:29:21.619Z","dependency_job_id":"159467f9-b403-4baf-a75e-f8dca5c75f0d","html_url":"https://github.com/bestia-dev/database_web_ui_on_server","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/bestia-dev%2Fdatabase_web_ui_on_server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bestia-dev%2Fdatabase_web_ui_on_server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bestia-dev%2Fdatabase_web_ui_on_server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bestia-dev%2Fdatabase_web_ui_on_server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bestia-dev","download_url":"https://codeload.github.com/bestia-dev/database_web_ui_on_server/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247953090,"owners_count":21023945,"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":["maintained","ready-for-use","tutorial","youtube"],"created_at":"2024-12-22T14:29:34.578Z","updated_at":"2025-04-09T00:49:17.143Z","avatar_url":"https://github.com/bestia-dev.png","language":"Rust","readme":"\u003c!-- markdownlint-disable MD041 --\u003e\n[//]: # (auto_md_to_doc_comments segment start A)\n\n# database_web_ui_on_server\n\n[//]: # (auto_cargo_toml_to_md start)\n\n**07. Tutorial for Coding a Database Web UI in Rust (2022-08)**  \n***version: 0.0.47 date: 2022-08-28 author: [bestia.dev](https://bestia.dev) repository: [GitHub](https://github.com/bestia-dev/database_web_ui_on_server)***  \n\n[//]: # (auto_cargo_toml_to_md end)\n\n ![maintained](https://img.shields.io/badge/maintained-green)\n ![ready_for_use](https://img.shields.io/badge/ready_for_use-green)\n ![tutorial](https://img.shields.io/badge/tutorial-yellow)\n ![youtube](https://img.shields.io/badge/youtube-yellow)\n\n[//]: # (auto_lines_of_code start)\n\n[![Lines in Rust code](https://img.shields.io/badge/Lines_in_Rust-230-green.svg)](https://github.com/bestia-dev/database_web_ui_on_server/)\n[![Lines in Doc comments](https://img.shields.io/badge/Lines_in_Doc_comments-9-blue.svg)](https://github.com/bestia-dev/database_web_ui_on_server/)\n[![Lines in Comments](https://img.shields.io/badge/Lines_in_comments-28-purple.svg)](https://github.com/bestia-dev/database_web_ui_on_server/)\n[![Lines in examples](https://img.shields.io/badge/Lines_in_examples-0-yellow.svg)](https://github.com/bestia-dev/database_web_ui_on_server/)\n[![Lines in tests](https://img.shields.io/badge/Lines_in_tests-0-orange.svg)](https://github.com/bestia-dev/database_web_ui_on_server/)\n\n[//]: # (auto_lines_of_code end)\n\n [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/bestia-dev/database_web_ui_on_server/blob/main/LICENSE)\n [![Rust](https://github.com/bestia-dev/database_web_ui_on_server/workflows/rust_fmt_auto_build_test/badge.svg)](https://github.com/bestia-dev/database_web_ui_on_server/)\n ![database_web_ui_on_server](https://bestia.dev/webpage_hit_counter/get_svg_image/65663564.svg)\n\nHashtags: #rust #rustlang #tutorial  \nMy projects on GitHub are more like a tutorial than a finished product: [bestia-dev tutorials](https://github.com/bestia-dev/tutorials_rust_wasm).\n\n## Intro\n\nThis is the 7th part of the [Rust tutorial series](https://www.youtube.com/channel/UCitt3zFHK2jDetDh6ezI05A). Today we will code a \"Web app processed on the web server for CRUD database operations\". We will use the Rust development environment inside a container and the knowledge we developed in this tutorial series.  \n\nThis project has also a youtube video tutorial. Watch it:\n\u003c!-- markdownlint-disable MD033 --\u003e\n[\u003cimg src=\"https://bestia.dev/youtube/database_web_ui_on_server.jpg\" width=\"400px\"\u003e](https://bestia.dev/youtube/database_web_ui_on_server.html)\n\u003c!-- markdownlint-enable MD033 --\u003e\n\n## Motivation\n\nMost of software solutions do just simple things: saving, transforming and reading data.  \nThis is typically the work of an SQL database server.  \nThe big job for us developers is to represent this data in a friendly way for the final user.  \nThe problem is pretty simple, but the separation of the architecture into 3 different tiers, with different technologies and languages, makes it difficult to start.  \nI'd like to make a simple scaffolding example to enable a quick start of the development for similar applications.  \nI'd like to use Rust as much as possible.  \n\n## Cross-platform, internet, cloud, architecture\n\nWe can use the internet standards to assure that our application is cross-platform. It will work as long as a modern browser works on the machine.\n\nWe want to separate the application into 3 tiers, to allow for great installation flexibility.  \nThree-tier architecture is a well-established software application architecture that organizes applications into three logical and physical computing tiers:\n\n1. the presentation tier, or user interface\n2. the application tier, where data is processed\n3. the data tier, where the data is stored and managed\n\n\u003cdetails\u003e\n\n```plantuml\n@startuml\npackage [1tier_web_browser] {\n  [browser HTTP protocols (https, 1.0, 1.1, 2.0, 3.0)]\n  [WASM programs (compiled from Rust)] #Orange\n  [HTML5 + CSS3 renderer]\n}\n\npackage \"2tier_Web_Server\" {\n  [server HTTP protocols (https, 1.0, 1.1, 2.0, 3.0)]\n  [web server Actix (compiled from Rust)] #Orange\n  [Connection to Postgres]\n}\n\npackage \"3tier_database\" {    \n    [PGX extensions (compiled from Rust)] #Orange\n    [SQL or pgSQL language]\n    [DB Connection address]\n}\n\n[browser HTTP protocols (https, 1.0, 1.1, 2.0, 3.0)] --\u003e [server HTTP protocols (https, 1.0, 1.1, 2.0, 3.0)]\n[Connection to Postgres] --\u003e [DB Connection address]\n@enduml\n```\n\n\u003c/details\u003e\n\n![3tier](https://github.com/bestia-dev/database_web_ui_on_server/raw/main/images/3tier.png)\n\nThe same application could then work everywhere:\n\n1. on a single machine\n2. on separate machines in the local network\n3. on a cluster of machines in the cloud\n\n## Database\n\nFor most real-life problems the performance and flexibility of the SQL server is fantastic. Just in rare cases of very big-data collections, the performance of the SQL server is not enough and we must go into the non-SQL territory. But then we lose all the magnificent flexibility and simplicity of SQL and relational database (RDB).  \nI like to use the open-source Postgres sql server.  \nThe 4 operations on the data are called CRUD (create, read, update and delete). It does not look complicated.  \nThe SQL language is also extra simple. It uses just a few simple and understandable English words and a simple syntax.  \nWe can read the data with the SELECT statement. We can JOIN related tables and we can filter the data with WHERE. Finally, we can ORDER the data.  \nSQL statements are usually just a string and the first instinct is to just concatenate it.  \nWrong !!!  \nIf you mix commands and data like in the SQL statement, there is the possibility of an SQL injection! If a malicious player writes commands instead of data, the server will run it and chaos will win. So we need to enforce true parameters. There must be no way how to introduce a SQL injection attack.  \n\nFor complicated SELECT statements, I prefer to create VIEWs inside the database server. Then this can be used from multiple places.  \n\nFor INSERT, UPDATE and DELETE I like to write sql functions that change data.  Often, we need to check some other data before or after we change some data. Sql functions live very near to where the data is stored so I expect the best performance.  \n\n## Web server and web app\n\nBasically, all the data manipulation and retrieval is coded inside the database with views and sql functions. Our web server just needs to transform this data into a user-friendly interface. There is not much specific code we need in this Rust code. It is mostly generic. Just transformation between the database and user interface.  \n\nFor this tutorial, I will manipulate the HTML code on the server, just like in the good old times. In the next tutorial, we will manipulate the data on the client like kids do it today.  \n\n## Browser, HTML5, CSS3, Wasm\n\nThe graphical user interface is rendered inside the web browser.  \nThe web standards HTML5 and CSS3 are pretty good. Most of the web is done just with them.  \nInstead of Javascript, I will use WASM/Webassembly compiled from my Rust code. It is not difficult once the development project is scaffolded. With the crates web_sys, js_sys and wasm-bindgen I can code just everything that javascript can do. So I don't need javascript anymore. FTW!  \n\n## Communication\n\nThe 3 tiers communication is mostly just request-response of text over a TCP or similar connection.  \nThe browser sends a request to the web server. The request is just some text sent to an URL address.  \nThe web server parses the request to understand what to do. Then it calls some function of the web application.  \nNothing much happens in this function. Usually, it just sends a SQL statement to the SQL server. Again it is just a text sent to an URL address.  \nThe logic is mostly inside the database in views and sql functions. This is performant because it is really close to the data. After the logic read and transform the data, it responds with some data back to the web server. This can be a single or multiple records/rows. We can call this a dataset.  \nThe web server/application now combines the data with the user interface. Sadly, HTML does not have a clear separation between data and the HTML code. We will try to create that in the next tutorial. Step-by-step.  \nThe web server replies to the browser with some HTML5, CSS3 and WASM code.\nThe browser finally renders this into a Graphical User Interface.  \n\nThis looks overly complicated, but it really solves a lot of problems in the long run. It is complicated just to start developing and arranging all projects and communications. Once it is working with the simplest example, it is very easy to add some new functionality. This tutorial project can be used as a scaffolding to create other, more complex projects.  \n\n## Workspace\n\nWe have basically 3 projects here. Rust allows us to combine projects into workspaces. Then we can treat them as a group.  \nThe automation tasks that are very simple for one solo project will be a little more complex now. But we have no limits to write any Rust code in the cargo-auto tasks. And once it works, it is a template for any 3-tier project.  \nThe sub-project for this tutorial will have these names:  \n\n- tier1_browser_wasm  \n- tier2_web_server_actix_postgres  \n- tier3_database_postgres  \n\nThe Cargo.toml of the workspace is very different from Cargo.toml of solo projects. It only contains the members of the workspace.  \n\n## Rust development environment\n\nWe will use our Rust development environment in a container like we do in all Rust tutorial of this series. We steadily upgrade the development environment and we can do more and more complex projects with it. We already have the postgres server container inside the pod from the last tutorial.  \n\n## First request\n\nWe will start coding with the web server to reply a simple static html code and try it immediately. From the last tutorial we know how to add the Actix crate to Cargo.toml and how to start the server and route the request to call a function. Let call the route and the function \"hit_counter_list\".  \nWe will also use the same exact database \"webpage_hit_counter\" as the last tutorial. I want to create, read, update and delete data for tables \"webpage\" and \"hit_counter\".  \n\n## webpage_hits object\n\nThe user interface will show just one data object \"webpage_hits\". It is a view that joins the 2 tables together. So to spice it up a little.  \nFirst we create all views and functions inside the postgres database.\nThen a Rust module just for that.  \n\nWe want the web routing code to be close to the implementation. We can use the actix ServiceConfig for that. First we use the actix_web scope function to route all requests that start with \"webpage_hits\" to the Rust module. Then inside the module we will route to the appropriate function using the decoration \"#actix web get\". Very easy once it is in place.  \n\nFor the CRUD User interface we need 7 functions. The 3 functions not included in the acronym CRUD are: List, New and Edit. This is part of the User Interface, there is not a lot of data manipulation here. So we have more or less:\n\n- 7 web paths,\n- 7 Rust functions,\n- 5 database functions and 1 view.\n\nIn the first iteration of the project there will be a lot of code duplication. This enables great flexibility, but the maintenance can get boring if we need to change something.  \nHaving the HTML code inside the Rust code is also not great. We will make it better the next time.  \n\n## Error handling\n\nWe need some error handling now. We want to show a meaningful message to the user and to log something more detailed for the developer. I will use the \"thiserror\" crate to customize the library errors. Actix has a trait that we can use to define the reporting behavior for errors in the web server.  \nAll the error handling is done in helper functions. So it is not duplicated in the specific response functions. The new feature \"track_caller\" shows the meaningful location in the source code where the error happened.  \n\n## Refactoring\n\nThe strongest feature of Rust is fearless refactoring. The compiler with the strict type system is so good that it catches every mistake while refactoring. After refactoring the code is neatly structured in functions and regions. These can be folded for better readability.  \n\n## Final test\n\nWe can finally try all the CRUD functionality of our application. We can also try the error handling and reporting when we enter bad data.  \nEverything works like a swiss clock! Great!  \n\n## Deploy\n\nI will use the knowledge from the last tutorial to deploy this all to my Google VM.\nI will restrict the access to this web app, so only I can modify the webpage_hits.\nBut this will not be part of the tutorial.  \n\n## Open-source and free as a beer\n\nMy open-source projects are free as a beer (MIT license).  \nI just love programming.  \nBut I need also to drink. If you find my projects and tutorials helpful, please buy me a beer by donating to my [PayPal](https://paypal.me/LucianoBestia).  \nYou know the price of a beer in your local bar ;-)  \nSo I can drink a free beer for your health :-)  \n[Na zdravje!](https://translate.google.com/?hl=en\u0026sl=sl\u0026tl=en\u0026text=Na%20zdravje\u0026op=translate) [Alla salute!](https://dictionary.cambridge.org/dictionary/italian-english/alla-salute) [Prost!](https://dictionary.cambridge.org/dictionary/german-english/prost) [Nazdravlje!](https://matadornetwork.com/nights/how-to-say-cheers-in-50-languages/) 🍻\n\n[//bestia.dev](https://bestia.dev)  \n[//github.com/bestia-dev](https://github.com/bestia-dev)  \n[//bestiadev.substack.com](https://bestiadev.substack.com)  \n[//youtube.com/@bestia-dev-tutorials](https://youtube.com/@bestia-dev-tutorials)  \n\n[//]: # (auto_md_to_doc_comments segment end A)\n","funding_links":["https://paypal.me/LucianoBestia"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbestia-dev%2Fdatabase_web_ui_on_server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbestia-dev%2Fdatabase_web_ui_on_server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbestia-dev%2Fdatabase_web_ui_on_server/lists"}