{"id":15153080,"url":"https://github.com/gcp-development/web-application","last_synced_at":"2026-01-28T20:39:35.923Z","repository":{"id":142829528,"uuid":"607168127","full_name":"gcp-development/web-application","owner":"gcp-development","description":"Web2 vs Web3","archived":false,"fork":false,"pushed_at":"2023-07-11T09:58:36.000Z","size":402893,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-13T14:19:36.391Z","etag":null,"topics":["actix-web","asynchronous-programming","blockchain","cid","dag","dht","ipfs","ipfs-protocol","ipns","kubernetes","kubo-rpc-api","react","rest-api","restful-api","rust","sqlx","web-application","web3"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gcp-development.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":"2023-02-27T13:07:15.000Z","updated_at":"2023-07-11T07:49:16.000Z","dependencies_parsed_at":"2024-08-21T10:23:14.040Z","dependency_job_id":null,"html_url":"https://github.com/gcp-development/web-application","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/gcp-development%2Fweb-application","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gcp-development%2Fweb-application/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gcp-development%2Fweb-application/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gcp-development%2Fweb-application/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gcp-development","download_url":"https://codeload.github.com/gcp-development/web-application/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247645384,"owners_count":20972466,"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","asynchronous-programming","blockchain","cid","dag","dht","ipfs","ipfs-protocol","ipns","kubernetes","kubo-rpc-api","react","rest-api","restful-api","rust","sqlx","web-application","web3"],"created_at":"2024-09-26T17:00:26.068Z","updated_at":"2026-01-28T20:39:35.886Z","avatar_url":"https://github.com/gcp-development.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Web Application\r\n\r\n## Motivation\r\n\r\nThere is no \"one-size-fits-all\" for any technology and everything comes down to \"what we are trying to solve?\". For Web3, we are dealing with distributed applications working on distributed software infrastructure (P2P networks). In business terms this means we are going to lose money if we don't get the right trade-offs in our technology stack. For startups these technical choices and trade-offs will be crucial in their product development and ability to scale. Having a good idea is not enough for a startup to thrive.\u003cbr\u003e\r\nFor the Web3 world, type safety (verifies and enforces type constraints at compile-time), high-performance async (good [ecosystem](https://rust-lang.github.io/async-book/08_ecosystem/00_chapter.html#the-async-ecosystem) of non-blocking  I/O libraries and runtimes), automatic memory management and memory safety without garbage collection ([ownership model](https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html)) were the main reasons that made [Rust](https://www.rust-lang.org/tools/install) my first choice. For instance, writing [smart contracts](https://use.ink/) that doesn't have memory bugs and consumes less storage on the blockchain is a massive advantage. On the other hand for user interface (UI) development, [React](https://reactjs.org/) is still a better choice due the rich UI features offered.\u003cbr\u003e\r\n\r\nThe examples developed, will be focused on the back-end services and distributed software infrastructure demonstrating the key points of using [Rust](https://github.com/rust-lang/rust) with [React](https://reactjs.org/) and Rust with [IPFS](https://ipfs.tech/) for the Web3 world.\r\n\r\n\u003chr\u003e\r\n\r\n## Table of Contents\u003cbr\u003e\r\n\u003cul\u003e\r\n\u003cli\u003e\u003ca href=\"\" target=\"_self\"\u003eWeb Application\u003c/a\u003e\u003c/li\u003e\r\n\u003cul\u003e\r\n\u003cli\u003e\u003ca href=\"https://github.com/gcp-development/web-application/blob/main/README.md#restful-web-service-library-service\" target=\"_self\"\u003eRESTful Web Service\u003c/a\u003e (library-service)\u003c/li\u003e\r\n\u003cli\u003e\u003ca href=\"https://github.com/gcp-development/web-application#user-web-interface-library-ui\" target=\"_self\"\u003eUser Web Interface\u003c/a\u003e (library-ui)\u003c/li\u003e\r\n\u003cli\u003e\u003ca href=\"https://github.com/gcp-development/web-application/blob/main/README.md#ipfs\" target=\"_self\"\u003eInterPlanetary File System\u003c/a\u003e (IPFS)\u003c/li\u003e\r\n\u003c/ul\u003e\r\n\u003cli\u003e\u003ca href=\"https://github.com/gcp-development/web-application#conclusion\" target=\"_self\"\u003eConclusion\u003c/a\u003e\u003c/li\u003e\r\n\u003c/ul\u003e\r\n\u003chr\u003e\r\n\r\n## Web Application\r\n\r\nOur main objective is to understand how to build a distributed web application that are safe, efficient, highly performant, and do not \"break the piggy bank\" to operate and maintain. We are going to look at two type of storages a central storage(Postgres) and a distributed storage (IPFS).\r\n\r\nWith that in mind two key components were chosen to achieve those objectives:\r\n\u003cul\u003e\r\n  \u003cli\u003e\u003ca href=\"https://actix.rs/docs\" target=\"_self\"\u003eActix\u003c/a\u003e is a modern, light-weight web framework written in \u003ca href=\"https://github.com/rust-lang/rust\" target=\"_self\"\u003eRust\u003c/a\u003e.\u003c/li\u003e\r\n  \u003cli\u003e\u003ca href=\"https://actix.rs/docs](https://crates.io/crates/sqlx/\" target=\"_self\"\u003eSQLx\u003c/a\u003e is a Rust crate that provides asynchronous database access in our case to \u003ca href=\"https://www.postgresql.org/download/\" target=\"_self\"\u003epostgres\u003c/a\u003e.\u003c/li\u003e\r\n\u003c/ul\u003e\r\n\r\nWhen considering open-source software my first look is on the team building the software and the community using and maintaining it. (Makes no point selecting a state of the art software that is supported by a one man show. Believe Me or not, this is one of the most common errors startups do.)\r\nAfter saying that, having asynchronous support, ability to scale and maturity is essential in any startup product development. Nevertheless, there are some very good alternatives options to the ones used for this demo. For a Rust web framework [axum](https://docs.rs/axum/latest/axum/) is also a sound choice and for the database access [SeaORM](https://www.sea-ql.org/SeaORM/docs/introduction/sea-orm/) (SeaORM is an object-relational mapper which SQLx is not).\r\n\r\nWe have the following environment setup using [kubernetes](https://github.com/gcp-development/web-application/tree/main/kubernetes-setup) for our web application:\r\n\r\n![image](https://user-images.githubusercontent.com/76512851/223080940-6f847eb7-8cff-41eb-8571-3e5419391618.png)\r\n\r\nOur web application is composed of a Rust Rest API connected to a postgres database which forms a [Microservice](https://microservices.io/) and a [React](https://reactjs.org/docs/getting-started.html) user web interface served by the Rust Rest API.\r\n\r\n### RESTful Web Service (library-service)\r\n\r\nThe project code is organized with separate and clearly marked areas to store code for [handlers](https://github.com/gcp-development/web-application/tree/main/library-service/src/handlers), database access functions [(dal)](https://github.com/gcp-development/web-application/tree/main/library-service/src/dal), [data models](https://github.com/gcp-development/web-application/tree/main/library-service/src/model) and [database scripts](https://github.com/gcp-development/web-application/tree/main/library-service/src/model/sql_scripts). \r\n\r\n![image](https://user-images.githubusercontent.com/76512851/223094021-910d4695-d224-43bb-aade-ee255a0da1ce.png)\r\n\r\nEach route has a handler function and normally a database access function. The main purpose of structuring our code is to make it easier for other people to read and support a CI/CD pipeline. For instance for this project all [integration tests](https://actix.rs/docs/testing/) are concentrated in the [handler section](https://github.com/gcp-development/web-application/tree/main/library-service/src/handlers). \r\n\r\n![image](https://user-images.githubusercontent.com/76512851/223129476-a0458994-0178-47d9-b978-c3429f548ad5.png)\r\n\r\nKey points:\r\n\r\n\u003cul\u003e\r\n  \u003cli\u003eActix uses async I/O, which enables an Actix web application to perform other tasks while waiting on I/O on a single thread. Actix has its own Async runtime that is based on \u003ca href=\"https://tokio.rs/\" target=\"_self\"\u003eTokio\u003c/a\u003e(async library in Rust).\u003c/li\u003e\r\n  \u003cli\u003eActix allows to define custom application \u003ca href=\"https://github.com/gcp-development/web-application/blob/main/library-service/src/state.rs\" target=\"_self\"\u003estate\u003c/a\u003e, and provides a mechanism to safely access this state from each handler function. Since each application instance of Actix runs in a separate thread, Actix provides a \u003ca href=\"https://actix.rs/docs/application/#shared-mutable-state\" target=\"_self\"\u003esafe mechanism\u003c/a\u003e to access and mutate this shared state without conflicts or data races.\u003c/li\u003e\r\n  \u003cli\u003eSQLx is built from the ground-up using async/await for maximum concurrency.\u003c/li\u003e\r\n  \u003cli\u003eThe Postgres driver is written in pure Rust using zero unsafe code.\u003c/li\u003e\r\n\u003c/ul\u003e\r\n\r\nService Handlers:\r\n\u003cul\u003e\r\n  \u003cli\u003e\u003ca href=\"https://github.com/gcp-development/web-application/blob/main/library-service/src/handlers/book.rs#L7\" target=\"_self\"\u003epost_add_book\u003c/a\u003e Insert one book into the table \u003ca href=\"https://github.com/gcp-development/web-application/blob/main/library-service/src/model/sql_scripts/1_tbBooks.sql\" target=\"_self\"\u003ebooks\u003ca/\u003e.\u003c/li\u003e\r\n  \u003cli\u003e\u003ca href=\"https://github.com/gcp-development/web-application/blob/main/library-service/src/handlers/book.rs#L14\" target=\"_self\"\u003epost_bulk_insert\u003c/a\u003e Insert books in bulk mode into the table \u003ca href=\"https://github.com/gcp-development/web-application/blob/main/library-service/src/model/sql_scripts/1_tbBooks.sql\" target=\"_self\"\u003ebooks\u003ca/\u003e.\u003c/li\u003e\r\n  \u003cli\u003e\u003ca href=\"https://github.com/gcp-development/web-application/blob/main/library-service/src/handlers/book.rs#L21\" target=\"_self\"\u003eget_books\u003c/a\u003e Read all books from the table \u003ca href=\"https://github.com/gcp-development/web-application/blob/main/library-service/src/model/sql_scripts/1_tbBooks.sql\" target=\"_self\"\u003ebooks\u003ca/\u003e.\u003c/li\u003e\r\n  \u003cli\u003e\u003ca href=\"https://github.com/gcp-development/web-application/blob/main/library-service/src/handlers/book.rs#L28\" target=\"_self\"\u003eget_book_by_id\u003c/a\u003e Read a book by id from the table \u003ca href=\"https://github.com/gcp-development/web-application/blob/main/library-service/src/model/sql_scripts/1_tbBooks.sql\" target=\"_self\"\u003ebooks\u003ca/\u003e.\u003c/li\u003e\r\n  \u003cli\u003e\u003ca href=\"https://github.com/gcp-development/web-application/blob/main/library-service/src/handlers/book.rs#L39\" target=\"_self\"\u003eput_book_by_id\u003c/a\u003e Update a book by id from the table \u003ca href=\"https://github.com/gcp-development/web-application/blob/main/library-service/src/model/sql_scripts/1_tbBooks.sql\" target=\"_self\"\u003ebooks\u003ca/\u003e.\u003c/li\u003e\r\n  \u003cli\u003e\u003ca href=\"https://github.com/gcp-development/web-application/blob/main/library-service/src/handlers/book.rs#L51\" target=\"_self\"\u003edelete_book_by_id\u003c/a\u003e Delete a book by id from table \u003ca href=\"https://github.com/gcp-development/web-application/blob/main/library-service/src/model/sql_scripts/1_tbBooks.sql\" target=\"_self\"\u003ebooks\u003ca/\u003e.\u003c/li\u003e\r\n\u003c/ul\u003e\r\n\r\nBefore runing the integration tests we need to create the table [books](https://github.com/gcp-development/web-application/blob/main/library-service/src/model/sql_scripts/1_tbBooks.sql) and run the script [test data](https://github.com/gcp-development/web-application/blob/main/library-service/src/model/sql_scripts/2_testData.sql) using [pgAdmin](https://www.pgadmin.org/download/) for instance.\r\n\r\n![image](https://user-images.githubusercontent.com/76512851/224683234-a3b08cd4-beda-4a4d-8dab-bec152056677.png)\r\n\r\n\u003chr\u003e\r\n\r\n### User Web Interface (library-ui)\r\n\r\nThe project code is organized with separate and clearly marked areas to store code for [API functions](https://github.com/gcp-development/web-application/tree/main/library-ui/src/api), [components](https://github.com/gcp-development/web-application/tree/main/library-ui/src/components) and [types](https://github.com/gcp-development/web-application/tree/main/library-ui/src/types).\r\n\r\n![image](https://user-images.githubusercontent.com/76512851/224685345-476db57f-017b-4d33-817f-c82abddf1916.png)\r\n\r\nThe [React version 18](https://reactjs.org/versions) was used to build this user interface(UI), because of the [concurrent mode](https://reactjs.org/blog/2022/03/29/react-v18.html#what-is-concurrent-react) that comes with this version. This new feature allows React to work on several state updates concurrently. \r\nFor providing asynchronous state management, server-state utilities and data fetching, [TanStack Query](https://tanstack.com/query/latest) was used. Together with [React Router](https://reactrouter.com/en/main), which allow this UI to update the URL from a link click without making another request for another document from the server.\r\n\r\nBy integrating these two libraries and the use of the React V18, we get the following key benefits:\r\n\u003cul\u003e\r\n  \u003cli\u003eAbility to prepare multiple versions of our UI at the same time.\u003c/li\u003e\r\n  \u003cli\u003eReact Router’s data loader prevents an unnecessary re-render when data is loaded onto a page.\u003c/li\u003e\r\n  \u003cli\u003eReact Query’s cache prevents unnecessary calls to the REST API.\u003c/li\u003e\r\n\u003c/ul\u003e\r\n\r\nSolidJS vs [React](https://www.solidjs.com/guides/comparison#react)\r\n\r\n[SolidJS](https://www.solidjs.com/) is an open source, reactive declarative JavaScript library with an API similar to React. There is no such thing \"one better than the other\". Its always about tradeoff [(js-framework-benchmark)](https://krausest.github.io/js-framework-benchmark/current.html), we have to give up something to gain something else. In every decision made, as always, we should select two paths chose one and keep an eye on both.\r\n\r\nComparison Table\r\n| Feature| SolidJS (2021) | React (2016) |\r\n| ------------- | ------------- | ------------- |\r\n| TypeScript support | = | = | \r\n| Declarative nature | = | = | \r\n| JSX Support | = | = |\r\n| Highly performant | + | - |\r\n| Direct manipulation of the DOM | Yes | No |\r\n| Server-side rendering  | = | = |\r\n| Conditional rendering | = | = |\r\n| Concurrent rendering | = | = |\r\n| Community and ecosystem | - | + |\r\n\r\nKey points:\r\n\u003cul\u003e\r\n  \u003cli\u003e\r\n    React is a popular library for creating component-based frontends. React has the largest ecosystem out of any UI library, with very \u003ca href=\"https://reactjs.org/blog/2022/06/15/react-labs-what-we-have-been-working-on-june-2022.html\" target=\"_self\"\u003etalent people\u003c/a\u003e supporting it.\r\n  \u003c/li\u003e\r\n  \u003cli\u003e\r\n    TypeScript provides a much richer type system on top of JavaScript. TypeScript uses the type system to allow \u003ca href=\"https://code.visualstudio.com/docs/languages/typescript target=\"_self\"\u003ecode editors\u003c/a\u003e to catch type errors as developers write code. \r\n  \u003c/li\u003e\r\n  \u003cli\u003e\r\n     \u003ca href=\"https://reactjs.org/blog/2022/03/08/react-18-upgrade-guide.html#updates-to-client-rendering-apis\" target=\"_self\"\u003eConcurrent React\u003c/a\u003e. Until React 18, the React render process was synchronous and non-interruptable. As a result, the UI would lock during long render processes and not respond immediately to user input.\r\n  \u003c/li\u003e\r\n  \u003cli\u003e\r\n     React Router reduces the number of re-renders.\r\n  \u003c/li\u003e\r\n  \u003cli\u003e\r\n     React Query(TanStack Query) provides a client-side cache of the data.\r\n  \u003c/li\u003e\r\n  \u003cli\u003e\r\n     \u003ca href=\"https://www.solidjs.com/\" target=\"_self\"\u003eSolidJS\u003c/a\u003e is a very solid alternative to React.\r\n  \u003c/li\u003e\r\n\u003c/ul\u003e\r\n\r\nRunning the React UI\r\n\r\nThe table [books](https://github.com/gcp-development/web-application/blob/main/library-service/src/model/sql_scripts/1_tbBooks.sql) needs to be create and run the script [test data](https://github.com/gcp-development/web-application/blob/main/library-service/src/model/sql_scripts/2_testData.sql) using [pgAdmin](https://www.pgadmin.org/download/) for instance.\r\n\r\n![image](https://user-images.githubusercontent.com/76512851/224684760-c92e380b-d1b6-487b-9379-872a772b907f.png)\r\n\r\n\u003chr\u003e\r\n\r\n### IPFS\r\n\r\nInterPlanetary File System [(IPFS)](http://docs.ipfs.tech/concepts/what-is-ipfs/) is a peer-to-peer distributed file system, which connect all computing devices with the same system of files.\r\nIPFS is the combinational technology of the version controlling system and peer to peer network spreadover global namespace.\r\n\r\nIn contrast to a central storage(like PostgreSQL), IPFS works on a decentralized system in which every user in the network holds a portion of the overall data, thus creating a resilient system for storage and sharing over the globe. Any user in the network is able to share a file and it will be accessible to everyone in the network by requesting it from a node which possesses it using the Distributed Hash Table (DHT).\r\n\r\nThree fundamental principles to understanding IPFS:\r\n\u003cul\u003e\r\n\u003cli\u003e\u003ca href=\"https://github.com/gcp-development/web-application#unique-identification-via-content-addressing\" target=\"_self\"\u003eUnique identification via content addressing(CID)\u003c/a\u003e\u003c/li\u003e\r\n\u003cli\u003e\u003ca href=\"https://github.com/gcp-development/web-application#content-linking-via-directed-acyclic-graphs-dags\" target=\"_self\"\u003eContent linking via directed acyclic graphs (DAGs)\u003c/a\u003e\u003c/li\u003e\r\n\u003cli\u003e\u003ca href=\"https://github.com/gcp-development/web-application/blob/main/README.md#content-discovery-via-distributed-hash-tables-dhts\" target=\"_self\"\u003eContent discovery via distributed hash tables (DHTs)\u003c/a\u003e\u003c/li\u003e\r\n\u003c/ul\u003e\r\n\r\nThe examples provided were developed using the [Kubo RPC API](https://docs.ipfs.tech/reference/kubo/rpc/#kubo-rpc-api-v0-reference) together with the [actix-web](https://docs.rs/actix-web/latest/actix_web/), [awc](https://crates.io/crates/awc) and [actix-multipart-rfc7578](https://crates.io/crates/actix-multipart-rfc7578) crates.\r\n      \r\n![image](https://user-images.githubusercontent.com/76512851/229612684-30c3e220-c14f-42b5-860a-36c118b0034f.png)\r\n\r\nNote: A Rust implementation of a IPFS node ([iroh](https://iroh.computer/)) is currently being developed. But unfortunately is not mature enough for the examples needed.\r\n\r\n\u003chr\u003e\r\n      \r\n#### Unique identification via content addressing\r\n      \r\nThe [CID](https://docs.ipfs.tech/concepts/content-addressing/#content-identifiers-cids) is a label used to point to material in IPFS. Import the [book1.json](https://github.com/gcp-development/web-application/blob/main/kubo-rpc-api/api-v0-add/book1.json) using the Rust project [api-v0-add](https://github.com/gcp-development/web-application/tree/main/kubo-rpc-api/api-v0-add) file and copy the [CID](https://docs.ipfs.tech/concepts/content-addressing/#content-identifiers-cids).\r\n\r\n![image](https://user-images.githubusercontent.com/76512851/227532596-327ccdf7-1790-4d8b-9dfa-898171c6b192.png)\r\n\r\nSearch for file using the CID \"QmTN78XgBo6fPaWrDhsPf6yzJkcuqpEUBqVRtHu3i5yosL\" in the kubo node webui(http://demo:32546/webui/).\r\n\r\n![image](https://user-images.githubusercontent.com/76512851/227533885-9083e545-a1f8-4262-845b-d955114650b7.png)\r\n\r\nWe can access the file directly via browser https://ipfs.io/ipfs/QmTN78XgBo6fPaWrDhsPf6yzJkcuqpEUBqVRtHu3i5yosL using the [IPNS name](https://docs.ipfs.tech/concepts/ipns/). We can also use a [DNSLink](http://docs.ipfs.tech/concepts/dnslink/) address which looks like an IPNS address, but it uses a DNS name in place of a hashed public key.\r\n\r\n![image](https://user-images.githubusercontent.com/76512851/227534320-5eb3df09-2658-40b5-9ddb-d94b5371ef09.png)\r\n\r\n\u003chr\u003e\r\n\r\n#### Content linking via directed acyclic graphs (DAGs)\r\n\r\n[Directed acyclic graphs (DAGs)](http://demo:30009/ipns/docs.ipfs.tech/concepts/merkle-dag/) are a hierarchical data structure.\r\n      \r\nImport the file [book2.json](https://github.com/gcp-development/web-application/blob/main/kubo-rpc-api/api-v0-add/book2.json).\r\n      \r\n![image](https://user-images.githubusercontent.com/76512851/227559021-67685565-4632-431a-befb-1236eae5130c.png)\r\n      \r\nImport the file [book3.json](https://github.com/gcp-development/web-application/blob/main/kubo-rpc-api/api-v0-add/book3.json).\r\n      \r\n![image](https://user-images.githubusercontent.com/76512851/227558570-393b0b19-83aa-4922-a1b6-d282482c4a39.png)\r\n\r\nImport the DAG node file [library.json](https://github.com/gcp-development/web-application/blob/main/kubo-rpc-api/api-v0-dag-put/library.json) using the the Rust project [api-v0-dag-put](https://github.com/gcp-development/web-application/tree/main/kubo-rpc-api/api-v0-dag-put).\r\n      \r\nUsing the three CIDs of the files already imported(book1.json,book2.json and book3.json) to create a [DAG](http://demo:30009/ipns/docs.ipfs.tech/concepts/merkle-dag/#merkle-directed-acyclic-graphs-dags) in IPFS.\r\n      \r\n```bash\r\n[\r\n { \"/\":\"QmTN78XgBo6fPaWrDhsPf6yzJkcuqpEUBqVRtHu3i5yosL\"},\r\n { \"/\":\"QmYqo1Ack8g2rDX6TEoPA14oNASJrXEVB4oTEKv8So6Ect\"},\r\n {\"/\":\"QmUfV4m2PUM559LSvDsJkoz1KofTVq25RDXwW5uMdjNb4u\"}\r\n]\r\n```\r\n\r\nCopy the CID.\r\n      \r\n![image](https://user-images.githubusercontent.com/76512851/227553593-5645614b-5208-4eaa-8158-390c5f391a29.png)\r\n\r\nUsing the CID \"bafyreihw63bea7teb7araypl6sdhhhv57vohawroks4nxogorc2jx7b5oi\" of the DAG node created. Search for the DAG node in the IPFS Kubo webui (http://demo:32546/webui/).\r\n\r\n![image](https://user-images.githubusercontent.com/76512851/227563963-35175cb3-2a74-4b8a-b1b2-690d9275c934.png)\r\n\r\n\u003chr\u003e\r\n      \r\n#### \u003cb\u003eContent discovery via distributed hash tables (DHTs)\u003c/b\u003e\r\n      \r\n[Distributed Hash Tables](http://docs.ipfs.tech/concepts/dht) are a form of a distributed database that can store and retrieve information associated with a key in a network of peer nodes that can join and leave the network at any time. The nodes coordinate among themselves to balance and store data in the network without any central coordinating party.\r\n\r\nDHTs have the following properties:\r\n\u003cul\u003e\r\n\u003cli\u003eDecentralised \u0026 Autonomous: Nodes collectively form the system without any central authority.\u003c/li\u003e\r\n\u003cli\u003eFault Tolerant: System is reliable with lots of nodes joining, leaving, and failing at all times.\u003c/li\u003e\r\n\u003cli\u003eScalable: System should function efficiently with even thousands or millions of nodes.\u003c/li\u003e\r\n\u003c/ul\u003e\r\n      \r\nHow does DHT work ?\r\n\r\nAs a simple example the diagram below represents a ring overlay network (logical network implemented on top of some underlying network) with 6 nodes. To find out which node (peer) will get to store a specific key we just need to hash that key. Each node will have a hash value (Peer Id) and will store 5 keys. Making each node an independent hash table bucket in that ring overlay network.\r\n      \r\n![image](https://user-images.githubusercontent.com/76512851/229342962-9ba3226b-e5ed-4c88-a7d9-c2dd405b8b40.png)\r\n      \r\nFor this example we are using the DHT to map a data identifier to a peer; this is a \"Provider records\" type of key-value pairing. It's used to find and advertise content.\r\nThere are other two main types, \"IPNS records\" (map an [IPNS key](https://specs.ipfs.tech/ipns/ipns-record/#ipns-keys) to a [IPNS record](https://specs.ipfs.tech/ipns/ipns-record/#ipns-record)) and \"Peer records\" (map a Peer Id to a set of multi addresses at which the peer may be reach)      \r\n      \r\nMost of the DHTs implementations support the following 3 basic functions:\r\n\u003cul\u003e\r\n      \u003cli\u003eput (key, value) We are going to use the \u003ca href=\"http://docs.ipfs.tech/reference/kubo/rpc/#api-v0-routing-put\" target=\"_self\"\u003eKubo RPC api-v0-routing-put\u003ca\u003e (Write a key/value pair to the \u003ca href=\"http://docs.ipfs.tech/concepts/dht/#routing-tables\" target=\"_self\"\u003erouting system\u003c/a\u003e.)\u003c/li\u003e\r\n      \u003cli\u003eget (key) We are going to use the \u003ca href=\"http://docs.ipfs.tech/reference/kubo/rpc/#api-v0-routing-get\" target=\"_self\"\u003eKubo RPC api-v0-routing-get\u003ca\u003e (Given a key, query the \u003ca href=\"http://docs.ipfs.tech/concepts/dht/#routing-tables\" target=\"_self\"\u003erouting system\u003c/a\u003e for its best value.)\u003c/li\u003e\r\n      \u003cli\u003eprovide (key) We are going to use the \u003ca href=\"http://docs.ipfs.tech/reference/kubo/rpc/#api-v0-routing-provide\" target=\"_self\"\u003eKubo RPC api-v0-routing-provide\u003ca\u003e (Announce to the network that we are providing given values.)\u003c/li\u003e\r\n\u003c/ul\u003e\r\n\r\nHow to create an [IPNS record](http://docs.ipfs.tech/concepts/dht/#ipns-records) ?\r\n\r\nExecute the [GO(go1.20.2)](https://go.dev/doc/install) script [ipnsRecord.go](https://github.com/gcp-development/web-application/blob/main/kubo-rpc-api/create-ipns-record/ipnsRecord.go).\r\n      \r\n![image](https://user-images.githubusercontent.com/76512851/229357924-1fcdaa96-d6f8-4bcc-ad34-ac29e338cd08.png)\r\n\r\nCopy the private-key-ipns-record.bin file to the src path and run the Rust project [api-v0-key-import](https://docs.ipfs.tech/reference/kubo/rpc/#api-v0-key-import).\r\n\r\n![image](https://user-images.githubusercontent.com/76512851/229357726-c3395f78-a078-4e6c-b2f9-5a1c3576d821.png)\r\n\r\n```bash\r\n/ipns/k2k4r8lpp59iv154i7dfnd5m99tke25rqhqaybpssnk3ds5h5t5boe8j\r\n```\r\n\r\nCopy the signed-ipns-record.bin file to the src path and run the Rust project [api-v0-name-inspect](https://github.com/gcp-development/web-application/tree/main/kubo-rpc-api/api-v0-name-inspect) against the IPNS name /ipns/k2k4r8lpp59iv154i7dfnd5m99tke25rqhqaybpssnk3ds5h5t5boe8j.\r\n      \r\n![image](https://user-images.githubusercontent.com/76512851/229359402-e00f5a0e-c78d-418f-8de0-8ff396261ca0.png)\r\n\r\n[IPNS Name](https://specs.ipfs.tech/ipns/ipns-record/#ipns-name)\r\n\r\n```bash\r\n/ipns/k2k4r8lpp59iv154i7dfnd5m99tke25rqhqaybpssnk3ds5h5t5boe8j\r\n```\r\n\r\n[IPNS Record](https://specs.ipfs.tech/ipns/ipns-record/#ipns-record)\r\n```bash\r\n{\r\n    \"Entry\": {\r\n        \"Value\": \"/ipfs/QmUfV4m2PUM559LSvDsJkoz1KofTVq25RDXwW5uMdjNb4u\",\r\n        \"ValidityType\": 0,\r\n        \"Validity\": \"2023-04-03T13:29:58.128901162Z\",\r\n        \"Sequence\": 0,\r\n        \"TTL\": 60000000000,\r\n        \"PublicKey\": \"mCAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDSVhekFyk3/EIdJW530Zip/MeliHGDumXpbT6dBB/BWTP8wv7ioRXAiH0fs9v6Uflglw1VqN+08gs4ScbWkeRaVP1Q2d+lzffeTwiG4eZm/O9OGmdPQfXP/nSOVsKjDITxrVnYLoLLXnHpRcSMuueqpULMpxKj1aT3tSetn7YgrC1TuT3A40RVtwi8ODly9dMkzYH1lqzqMNtqHFumAyPN1hgEDHN2awbQs7KDLsvHF/LFUVlq/xZb6mbmiZBhIfv/YpvTNA9sYZVvL02Q1NqqOvcg0T5SY/lLNv8w1PZuePV58ZMJOHYHgP22MR5hnmrSYOlpebbU8A3EJCgG9FGvAgMBAAE\",\r\n        \"SignatureV1\": \"meWDwdTYzNsaCrn/rP6IVaa5cnmqs5tYA6OKN1p647UcoGGDrurSgVXvIKmjIlKr6JigJB6NL2cnRksDdX+vYQdSNejb2bqtne+bG7jmc2hpj4xQHMWpVdgKdN1GwG1rJdcrEJnzqt0eNhiwKOMmhC8ynlx7B/8vzw+70unxCyBaWeXnumJYKXzymSRIe2UdI87WRzu6NEJh7QJuIBOuwlGjAyRepCAodUCVqr/Fl2hAtdlyRGmavtwGda6TmVp9Xi2F+o2qOwLJEvA6fMiR5uH0YoXnMdN7DY3IVr0+BmKnPyCsoCx+X5OsVofCkWpEKFvJKfY9ILeqxEp/7DbvabQ\",\r\n        \"SignatureV2\": \"modrb+wC4mBtUahM/KhSm1tYWhUj73fENvmceLAklbYYVfWwnmAHl1VGrlOmDVrdJv40+7gQgQcMUTwfk1S9XWqwopbBHhfKZxb0RFIoGy/Fmpay0rHpYBzLJBM5ah+Xcz6rnfo0FsNSjLz4PFl/dG4gNPNL1Pv9W01G3abjTEcZoTm8BOh7wRkbagG1eO/UayKaXeCRVgd/9xfKF9XJs0jo3RIbbf4lXbWme1j7k8vO861OCEp+bky9P5eQ/dnYnjxhysE6HkvbofqJxg9VVfyhe7DC46ZXu0FVmw2PznrsHz+mPRogZwawVrqxh+6YBkbJTJhd4YoEZdd5MEnZUaA\",\r\n        \"Data\": {\r\n            \"Sequence\": 0,\r\n            \"TTL\": 60000000000,\r\n            \"Validity\": {\r\n                \"/\": {\r\n                    \"bytes\": \"MjAyMy0wNC0wM1QxMzoyOTo1OC4xMjg5MDExNjJa\"\r\n                }\r\n            },\r\n            \"ValidityType\": 0,\r\n            \"Value\": {\r\n                \"/\": {\r\n                    \"bytes\": \"L2lwZnMvUW1VZlY0bTJQVU01NTlMU3ZEc0prb3oxS29mVFZxMjVSRFh3VzV1TWRqTmI0dQ\"\r\n                }\r\n            }\r\n        }\r\n    },\r\n    \"Validation\": {\r\n        \"Valid\": true,\r\n        \"Reason\": \"\",\r\n        \"PublicKey\": \"QmUYNURRiUgNo1YevHW7XH8dDTqw3ywKdUZN6PiVP1deJe\"\r\n    }\r\n}\r\n```\r\n      \r\nCopy the signed-ipns-record.bin file to the src path and run the Rust project [api-v0-routing-put](https://github.com/gcp-development/web-application/tree/main/kubo-rpc-api/api-v0-routing-put).\r\n\r\n![image](https://user-images.githubusercontent.com/76512851/229452909-4e9da6cc-1944-4a0e-8e81-18c55f68269a.png)\r\n      \r\nTo get the new route created just, run the Rust project [api-v0-routing-get](https://github.com/gcp-development/web-application/tree/main/kubo-rpc-api/api-v0-routing-get).\r\n      \r\n![image](https://user-images.githubusercontent.com/76512851/229458025-43cc1879-b034-43c3-aad9-5f1f37263d6c.png)\r\n      \r\nTo resolve the IPNS name k2k4r8lpp59iv154i7dfnd5m99tke25rqhqaybpssnk3ds5h5t5boe8j we will use the Rust project [api-v0-name-resolve](https://github.com/gcp-development/web-application/tree/main/kubo-rpc-api/api-v0-name-resolve).\r\n      \r\n![image](https://user-images.githubusercontent.com/76512851/229470868-b3ac421d-e89e-45c4-a3f9-f96c8b181158.png)\r\n\r\nIPFS CID\r\n```bash\r\n/ipfs/QmUfV4m2PUM559LSvDsJkoz1KofTVq25RDXwW5uMdjNb4u\r\n```\r\nNote: IPNS names are mutable pointers to immutable pointers IPFS CIDs (immutable because they're derived from the content).\r\n\r\nResolve the IPNS Name in the browser (https://ipfs.io/ipns/k2k4r8lpp59iv154i7dfnd5m99tke25rqhqaybpssnk3ds5h5t5boe8j)\r\n![image](https://user-images.githubusercontent.com/76512851/229567669-c73abb7f-6715-4b1c-bad9-49f5f9e8a01b.png)\r\n\r\nResolve the IPFS CID in the browser (https://ipfs.io/ipfs/QmUfV4m2PUM559LSvDsJkoz1KofTVq25RDXwW5uMdjNb4u)\r\n![image](https://user-images.githubusercontent.com/76512851/229567352-fcae6bd0-2fd2-473e-ae4c-f6122c92e30e.png)\r\n\r\nTo announce the new IPFS CID to the overlay network just, run the Rust project [api-v0-routing-provide](https://github.com/gcp-development/web-application/tree/main/kubo-rpc-api/api-v0-routing-provide).\r\n\r\nList of the peer Ids.\r\n\r\n![image](https://user-images.githubusercontent.com/76512851/229569317-c39f2a62-4b5d-42e2-b6a4-a5cf81edd9b6.png)\r\n      \r\n\u003chr\u003e\r\n\r\n### Conclusion\r\n\r\nIn a life span of 5 years, [90%](https://www.forbes.com/sites/neilpatel/2015/01/16/90-of-startups-will-fail-heres-what-you-need-to-know-about-the-10/?sh=39fb5cda6679) of [technology startups fail](https://www.rocketspace.com/tech-startups/why-tech-startups-fail-and-how-founders-can-bounce-back). Despite of not being the only reason, the common denominator present in all of those, was/is the wrong technical choices made. Those choices limited the time to market, the ability to scale and most important time to innovate. \r\nThe balancing between profitability and growth is extremely difficult to managed by itself. Without having to be limited in our actions by a software that does not scale, was poorly implemented and have an expensive operational cost. \r\n\r\n\u003chr\u003e\r\nReferences:\u003cbr\u003e\r\n\r\n[Actix Web framework](https://actix.rs/docs)\u003cbr\u003e\r\n[SQLx](https://github.com/launchbadge/sqlx)\u003cbr\u003e\r\n[PostgreSQL](https://www.postgresql.org/docs/current/index.html)\u003cbr\u003e\r\n[Asynchronous Programming in Rust](https://rust-lang.github.io/async-book/)\u003cbr\u003e\r\n[Testing](https://doc.rust-lang.org/rust-by-example/testing.html)\u003cbr\u003e\r\n[React TypeScript Cheatsheets](https://react-typescript-cheatsheet.netlify.app/)\u003cbr\u003e\r\n[Type Script Language](https://www.typescriptlang.org/)\u003cbr\u003e\r\n[IPFS](https://docs.ipfs.tech/)\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgcp-development%2Fweb-application","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgcp-development%2Fweb-application","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgcp-development%2Fweb-application/lists"}