Web Applications Development Notes
Web Applications Development Notes
Figure 11.1 It takes many roles to build a responsive design in web applications development for multiple system applications.
(credit: modification of “190827-F-ND912-035” by Tech. Sgt. R. J. Biermann/Lt. Col. Wilson/U.S. Air Force, Public Domain)
Chapter Outline
11.1 Modern Web Applications Architectures
11.2 Sample Responsive WAD with Bootstrap and Django
11.3 Sample Responsive WAD with Bootstrap/React and Node
11.4 Sample Responsive WAD with Bootstrap/React and Django
11.5 Sample Native WAD with React Native and Node or Django
11.6 Sample Ethereum Blockchain Web 2.0/Web 3.0 Application
Introduction
TechWorks is creating several web applications this year for a new product line. One application is an AI-image
generator website and auction house for selling images. An outside consultant has been brought in, and they
have determined that a hybrid Web 2.0/3.0 architecture is best suited for this solution. However, the
engineering team who will perform the work needs to gain experience with Web 3.0 technologies. Therefore,
the consultant recommended that TechWorks take a popular internal desktop application for managing to-do
lists and re-create it as a hybrid Web 2.0/3.0-based application so engineers can gain practical experience with
various web application frameworks and technologies, with the added benefit of accessing their to-dos from
anywhere.
The TechWorks engineering team has decided to perform iterative releases of the to-do application, starting
with responsive web apps, as they will render well on various screen sizes, from large monitors to smaller
displays like phones and tablets. Next, they will employ a native web application framework to target specific
devices like Android and iPhones. Lastly, they will explore building a Web 2.0/3.0-based to-do application using
blockchain technology, as they believe this approach will give them the necessary skills for creating future
solutions.
566 11 • Web Applications Development
The World Wide Web, or the Web as it is known today, started as a way to link content (primarily text and
images) stored on different servers or machines. It was invented by Tim Berners-Lee in 1989 while he worked
as a researcher at the European Organization for Nuclear Research (CERN), home to the European Particle
Physics Laboratory. Sir Tim Berners-Lee was knighted by Queen Elizabeth II in 2004 for his pioneering work. He
created the Hypertext Transfer Protocol (HTTP) that operates on top of Transmission Control Protocol/Internet
Protocol (TCP/IP), the principal protocols used on the Internet. Clients (web browsers) transmit HTTP requests
to a web server, which is a software application that runs at a Uniform Resource Locator (URL) that specifies a
location on the Web to access it, and responds by providing pages rendered in the hypertext markup language
(HTML). This simple request and response paradigm, a client-server model, was easy to implement and
allowed for the rapid growth of the Web. This phase of the Web, which began after 1989 and ended around
2004, would become known as Web 1.0, a period where the user’s interaction was limited primarily to reading
and selecting web pages. A web page is a document commonly written in HTML and viewed in a browser.
Figure 11.2 shows a simple Web 1.0 architecture and common usage. An encryption layer was later added to
the HTTP protocol, which resulted in creating the HTTPS protocol. This made it possible to protect the sharing
of sensitive information over the Web from eavesdropping attacks. While web servers only served web pages
initially, a Common Gateway Interface (CGI) was subsequently added after the initial implementation of web
servers to make it possible to link to applications via URLs on the Web.
Figure 11.2 This architecture outlines a user’s interaction with a Web 1.0 website. (attribution: Copyright Rice University, OpenStax,
under CC BY 4.0 license)
As the Web evolved from this basic architecture, the need for more dynamic and interactive experiences
became apparent. Users were no longer content with simply viewing static pages; they wanted to contribute
content and engage with other users. Also called online publishing, web publishing publishes content on the
Web while applying traditional publishing models. It was akin to digitizing an encyclopedia (images and text)
and putting it online with hyperlinks. Today, simple websites with limited functionality, such as early blogs or
static sites, still follow this model. A more interactive model that could scale to meet user demand was needed
to support users’ desire to provide content and interact with other users. A design pattern is a reusable
solution to a common software design problem. Figure 11.3 illustrates the Model-View-Controller (MVC) design
pattern that was employed to separate a traditional web application’s data model, presentation, and business
logic layers into its components.
Figure 11.3 This figure shows a user’s interaction with the Model-View-Controller pattern. (attribution: Copyright Rice University,
OpenStax, under CC BY 4.0 license)
The original implementation of the MVC pattern on the Web was such that the View would send requests to
the Controller and the Controller obtained data from the Model and rendered it within HTML pages that were
passed to browsers for presentation purposes. AJAX technology was later introduced to enable a more
complete implementation of MVC on the Web that allowed asynchronous updates to page components and
did not require refreshing pages in the browser to fetch data.
Following Moore’s law, which states that the number of transistors on an integrated circuit doubles roughly
every two years, the processing power of smaller devices like laptops, tablets, and mobile phones became the
preferred way users interacted on the Web. As Internet data transfer speeds and bandwidth increased through
better hardware, fiber-optic cables, and mobile wireless technology, the rendering of web applications’
interactive interfaces moved from the server side to the client side. This led to being able to run native
applications (apps) on mobile wireless phones that could take advantage of specific device rendering features.
In a paradigm shift that was opposite to web apps, the data model moved off the phone and onto remote
servers. These solutions led to a richer user experience known as Web 2.0, which is a phase of the Web
focused on social interactions. This phase started in 2004, and social media websites using Web 2.0, such as
Facebook (now Meta) and Twitter (now X), are well-known examples of this web phase of social interactivity.
The next phase of the web, Web 3.0, which is a phase of the Web where user activities may focus on
decentralized access to solutions and data, is seeing a shift from the more traditional client-server model to a
peer-to-peer networking model. A peer-to-peer (P2P) network is one in which devices connect and can share
data and processing without needing a centralized server. Peers in this scheme can perform the role of a
traditional client, server, or both. This shift fosters a trusted, decentralized, and open web, where large
companies do not own the data, but rather where data is collectively owned by users. The use of other
technologies like generative artificial intelligence (GenAI), which is powered by machine learning, aims to
568 11 • Web Applications Development
Throughout this section, we will discover how the application architectures found in Web 2.0 apps, native
mobile apps, and Web 3.0 apps are designed.
• hypertext markup language (HTML): a standard markup language used to describe the structure and
content of web pages.
• cascading style sheets (CSS): a standard style sheet language used to alter the presentation style of the
content found in HTML (or other markup languages).
• JavaScript (JS): a scripting language that adds interactivity to web content and server-side functionality.
Various other scripting languages and competing approaches were used prior to the adoption of
JavaScript.
The adoption of HTML was already a given on the Web, and with the introduction of CSS in 1996, a stronger
push for separating content and style was introduced so that the styling of content could be specified solely as
part of style sheets rather than HTML tags. Web pages at this time mostly consisted of static content, which
would be generated and delivered on the web server. Essentially, the user would select an action in their
browser that sent an HTTP request to the server such as the following:
• When clicking a hyperlink on a web page, the browser would send an HTTP GET request to the web server.
This request asked for a specific resource (such as a web page or an image), and the server would respond
by sending the requested data back to the browser.
• When filling out a form on a web page and clicking the submit button, the browser would send an HTTP
POST request to the server. This request included the data that was entered (like a username and
password), and the server processed it and responded accordingly.
1 To learn more, check out Lionbridge’s blog ([Link] post about globalization.
Essentially, the web server performed all the HTML content rendering on the server side, and the client (web
browser) would present what it received. The browser in this model acts as a thin client, as it has minimal
functionality. Figure 11.4 illustrates the components of a traditional Web 2.0 architecture using Java-based
technologies. Notice the shift in user interaction with the website compared with a Web 1.0 website. Also note
that users are able to interact with applications via an application server that can retrieve data from a database
or file system. This enables support for managing web sessions that allow navigation across multiple pages.
Figure 11.4 This illustrates a user’s interaction with a traditional Web 2.0 architecture. (attribution: Copyright Rice University,
OpenStax, under CC BY 4.0 license)
Many of the original web applications were stateless, meaning that prior requests had no bearing on future
requests. For example, it was not possible to create a shopping cart as part of a web session that would keep
track of the session and what was purchased on a site and maintain the state (i.e., content in this case) of the
cart. In contrast, a stateful application is software that maintains the state of an application over time, while
in the case of a stateless application, state is not maintained by the system and previous actions do not
impact future ones. Stateless applications are simpler and easier to implement and maintain but offer limited
functionality.
As previously mentioned, Web 2.0 was partly driven by user demand for more interactive functionality.
Interactivity requires maintaining some state (e.g., the web session and the content of the cart as per the
previous example), thereby increasing the system’s complexity. This increased the demands on the web server
for almost all the processing needed to generate and present the website content. Increased functionality led
to more complex systems, and a clear separation of responsibility between the website’s rendition, business
logic (i.e., the logic implemented as part of the web application), and persistence layers were needed to
improve the quality and performance of the website while leveraging engineering expertise in given domains.
As you learned in Chapter 10 Enterprise and Solution Architectures Management, the Model-View-Controller
pattern is tailored to address this separation of responsibility. In the MVC pattern, the Model is the persistence
layer responsible for data storage and retrieval. It has a well-defined API that the Controller uses. The View is
the presentation layer that handles the user interface. Finally, the Controller acts as the business logic layer
that performs processing and enforces rules to generate applicable content within a given application domain
and separates the user interface from the data. It also has a well-defined API that the View understands. The
best-practice design concept used to create software systems in a way that ensures weak associations with
other components is called loose coupling. This concept allows for separation of concerns between
components, which leads to maintaining high cohesion within websites’ functionalities. MVC components are
loosely coupled in that the various components can interact with one another to access the specific
570 11 • Web Applications Development
functionalities provided by each component. High cohesion ensures that everything that is needed to provide
a specific functionality is included in one of the components. For example, on a banking website, functionality
for deposits and withdrawals may be collocated on the server within the same component to ensure high
cohesion; however, features for applying for a loan may be located within another component. Three popular
server-side web application frameworks that implemented the MVC pattern were Apache Struts, [Link], and
Ruby on Rails.
CONCEPTS IN PRACTICE
How do APIs work? The API architecture is usually explained in terms of client and server. The application
sending the request is called the client, and the application sending the response is called the server. For
example, in the case of an API for a weather service, the weather service database is maintained on the
server side, and the mobile app is running on a client mobile device.
The server side performs the majority of the functionality. It uses a combination of templated HTML, controller
and application server technologies (e.g., [Link], C#), and SQL. JavaScript is sent to the browser using jQuery
for cross-browser support, or it may use Asynchronous JavaScript and XML to communicate with the web
server without refreshing the page. Asynchronous JavaScript and XML (AJAX) exchanges small amounts of
data between a client and server. The engineering team using such a web platform must understand and
enforce the separation of responsibilities between the MVC components to ensure future modifications,
especially significant changes, can be made without rearchitecting the system. Because the engineering team
needs to know different programming languages for different layers, there may be some internal resistance to
this, and it may be tempting to go around a layer to make a quick fix. Essentially, making sure that the
architecture of the web platform is understood and used properly, architectural adherence is predicated on
the expertise of the engineering team members and more on the nature of the tools used.
Figure 11.5 This is a comparison of the life cycles between traditional Web 2.0 applications and SPAs. (attribution: Copyright Rice
University, OpenStax, under CC BY 4.0 license)
LINK TO LEARNING
The World Wide Web Consortium (W3C) ([Link] develops standards and guidelines
for the Web. You can discover more about them and examine some of their current draft standards.
jQuery, an open-source JavaScript library, ensured that web developers could write JavaScript for a generic
browser document object model (DOM) that would run regardless of the user’s browser. The DOM is a
programming interface provided by browsers. It allows scripts, written in JavaScript for example, to interact
with the structure of a web page. When a web page is loaded into the browser, the browser creates a DOM of
the page. The DOM structure is a hierarchical treelike structure that organizes the elements of the page as
objects. The model used by the DOM enables dynamic access and facilitates the manipulation of content,
structure, and style of web pages. Figure 11.6 illustrates a typical SPA architecture where a single web page is
delivered to the browser. Note that in this model, the user’s interaction with the site has increased in the
amount of content generated by the user.
572 11 • Web Applications Development
Figure 11.6 This illustrates a user’s interaction with a single-page application (SPA). (attribution: Copyright Rice University, OpenStax,
under CC BY 4.0 license)
The more sophisticated SPAs required large amounts of JavaScript on the client side. Many end users had
underpowered machines or out-of-date web browsers, and the SPAs performed poorly.
In the early 2010s, web application frameworks were introduced to create complex, client-side web
applications that performed well, gave a native desktop application-like experience, and were easier for
developers to create. These applications followed a Model-View-ViewModel (MVVM) pattern. Figure 11.7
illustrates the relationship between the View, ViewModel, and Model components.
Figure 11.7 Various data binding, events, and actions occur between the components of the Model-View-ViewModel pattern.
(attribution: Copyright Rice University, OpenStax, under CC BY 4.0 license)
This pattern is like the MVC pattern we’ve previously explored; however, several key differences exist. The
following are some of the similarities and differences:
• The View is responsible for the presentation and only interacts with the ViewModel. This is similar in
responsibility to the View role and interaction with the Controller in the MVC pattern. The View here binds
to functions and properties in the ViewModel and receives notifications on operations and changes to the
data. It doesn’t interact directly with the Model.
• The Model is similar to the Model in the MVC pattern and is responsible for data retrieval and storage. It
doesn’t know anything about the ViewModel.
• The ViewModel is similar to the Controller in that it decouples the relationship between the View and
Model and handles data manipulation. The ViewModel responds to notifications from the Model and will
send events to the View if needed. Because the View binds to the ViewModel, the ViewModel doesn’t know
anything about the View. The ViewModel can work with a local Model in the browser, a remote Model, or
both.
Unlike the previous MVC pattern regarding server-side rendering, the MVVM pattern is run entirely in the
client. A Representational State Transfer (REST) API decouples the client-side Model and ViewModel
components from the server-side business logic and persistence store. REST-based (aka RESTful) APIs follow
the architecture style designed for the Web. These APIs use the JavaScript Object Notation (JSON) file format
that represents data as text-based attribute-value information. Figure 11.8 illustrates the MVVM pattern as it
applies to an SPA.
Figure 11.8 This illustrates the Model-View-ViewModel pattern as applied to the SPA architecture. (attribution: Copyright Rice
University, OpenStax, under CC BY 4.0 license)
As you can see from the diagram, this model is more complex than the simpler MVC pattern. The quality of the
APIs partly determines the effectiveness of this pattern. REST-based APIs benefit from being discoverable (i.e.,
all API URIs can be found from the root API node) and should be versioned (i.e., to keep track of changes to
interfaces for compatibility purposes) so that upgrades don’t break API users. Without API versioning, coupling
between client and server increases (due to semantic and syntactic coupling), and upgrades become costly.
Similar to a URL, a Uniform Resource Identifier (URI) is a string of characters that identifies a resource on the
Web.
Regardless of these flaws, early browser-based frameworks proved the value of creating rich client-side apps.
Web standards evolved, and newer frameworks emerged that adhered to the newer standards and solved
many of the problems of their predecessors. Popular SPA frameworks include Angular, [Link], React, and
[Link]. These are often used in conjunction with server-side tools, creating a “full stack” of technologies for
developing the solution. A popular server-side technology in this stack is Node, a runtime environment for
executing JavaScript code.
Approaches to minimizing the data transferred between the APIs and the client to reduce network traffic or
simplifying access to the data resulted in two primary approaches. One was flattening the data model. Instead
of returning data in a nested format (such as from a relational database), the returned data would be
“flattened” to a series of key-value pairs, each resulting in a unique return value. If the specific request could
be made, the flattened data would be preferred to navigating the nested data to improve performance.
However, creating APIs to fit specific requests could be challenging. Another solution was using GraphQL, an
open-source query and manipulation language. With GraphQL, callers of its API could craft specific requests to
return only the needed data, which made access to many services such as the ones provided by microservices
574 11 • Web Applications Development
THINK IT THROUGH
Framework Selection
Given that many web and native application frameworks are available today, is there a process that
facilitates the selection of these frameworks?
However, in the United States in 2023, iOS was the predominant OS with roughly 61% of the market and
Android at 38%. Here, we’ll look at the specifics of native mobile app development by focusing on Android and
3
iOS.
Developers for Android mobile apps have a rich ecosystem composed of development tools, programming
languages, training, and services. The primary developmental tools are:
• Android Studio is the official IDE for Android development, built off JetBrains’ IntelliJ IDEA software.
• Jetpack Compose is a toolkit for building native user interfaces (UI).
• Firebase is an app development platform and a collection of services for authenticating users, integrating
ads, running A/B tests, and more. Firebase includes an A/B testing tool that helps test changes to web
apps to see how changes impact key metrics such as revenue and customer retention. Developers will
likely write software in Java, Kotlin, or C++. Java was historically the primary language for Android
development. It runs on the Java Virtual Machine (JVM), which allows for creating platform-independent
software. Kotlin is the preferred Android development language. It runs on the JVM but also runs on the
Android Native Development Kit (NDK), which is used for performance-critical parts of applications. The
NDK performs better than the JVM, and it provides direct access to physical device components (e.g.,
sensors and touch screen). C and C++ code can also run on the NDK.
Applications developed for Android are distributed through App Stores. Google Play is the principal app store,
but others include Amazon Appstore, HUAWEI AppGallery, and Samsung Galaxy Store.
LINK TO LEARNING
To explore Android app development further, Google offers free training. You can get started by creating
your first “Hello World” ([Link] Android program.
2 Statcounter Global Stats, “Mobile Operating System Market Share Worldwide, Dec 2022–Dec 2023,” January 2, 2024.
[Link]
3 Statcounter Global Stats, “Mobile Operating System Market Share United States Of America, Dec 2022–Dec 2023,” January 2, 2024.
[Link]
Xcode is the primary IDE used for all Apple device development. Developers will code in Objective-C or Swift.
Objective-C was the primary development language for iOS; however, it was challenging to learn. In 2014,
Apple released the Swift programming language specifically designed for iOS development. It offers high-
order language features, making it easier to develop software and built-in memory management, which
makes less prone to crash.
INDUSTRY SPOTLIGHT
Drawbacks to using native application framework include a longer development process, increased cost,
complex maintenance and updates, platform dependency, regulatory and compliance issues, and end-user
barriers.
The Benefits and Drawbacks Between Native, Web, and Hybrid Mobile Application
Development
Native applications have the benefits of accessing device-specific hardware and sensors (e.g., camera,
accelerometer), data (e.g., location, contacts), and are optimized for performance.
However, they have the drawbacks of being device-dependent and available primarily through proprietary app
stores (Google Play for Android and Apple’s App Store for iOS). Developers need to learn different languages
and libraries for the devices. However, cross-platform development is possible with frameworks (e.g., Flutter,
Kotlin Multiplatform Mobile), allowing developers to code in a single language and run solutions on both
platforms.
Web apps can also run in a browser on mobile devices. They have the distinct advantage of responsiveness
and can run on various screen sizes—thus allowing for a single codebase that can increase productivity and
reduce cost. Disadvantages to web apps on mobile devices are limited access to hardware and software
features, lower performance than native apps, and web apps may perform differently depending on the
mobile browser. Traditionally, web apps didn’t look like native apps. In 2017, Google introduced Progressive
Web Apps for Android, allowing web apps to look and feel similar to native apps.
Finally, hybrid apps are web apps wrapped inside a native device framework (e.g., Apache Cordova). These
apps have the advantages of using traditional web application development while accessing and utilizing
device functions and running on multiple mobile platforms. The drawbacks are reduced speed and potential
security vulnerabilities found in the framework.
576 11 • Web Applications Development
CONCEPTS IN PRACTICE
Tim Berners-Lee had referred to Web 3.0 as the Semantic Web, a system of autonomous agents, which are
software programs that respond to events. That model has shifted over the years. While AI (and other
technologies such as AR/VR) will likely form a part of Web 3.0 or Web x.0, the principles that govern the next
phase are expected to be around a web that is decentralized, permissionless, and trusted.
Web 3.0 sees a shift from the more traditional client-server model to a peer-to-peer networking model. A peer-
to-peer network is one in which devices connect and can share data and processing without needing a
centralized server. Peers in this scheme can perform the role of a traditional client, server, or both. This shift
will foster a trusted, decentralized, and open web, where large companies don’t own the data, but everyone
collectively owns it. Technologies such as a smart contract allow a trusted model that is needed in a
decentralized system. Artificial intelligence and machine learning will improve information access through
understanding the meaning of content available on the Web. The exemplar apps of the Web 3.0 phase will be
defined in the future. Still, if the previous phases of the Web are any indication, it will fundamentally change
how we operate in an ever-evolving technological world.
Finally, Web 3.0 apps will run on a web that supports Web 1.0 and 2.0 apps, with the likely result being hybrid
architectures that are partially Web 2.0 and 3.0.
Let’s compare a traditional Web 2.0 application with a 3.0 DApp. In Web 2.0, if you created a website for users
to post pictures and make comments on them, you would need functionality for authenticating users,
authorizing their actions, generating a UI for adding images, browsing images, and posting comments. To do
this, you would need a front-end web server and back-end processing for business logic and data storage.
These servers would run in a company’s data center or on a cloud provider. The company would own all the
code and data, including metadata about how you interact with the website (e.g., what you commented on,
how long you looked at a picture). As a reminder, Figure 11.4 illustrates a traditional Web 2.0 architecture (note:
for our purposes, the SPA architecture could also be used here).
In a Web 3.0 DApp, the functionality for creating an application for posting pictures and commenting on them
would remain the same. The principal differences would be where the code runs and who owns the code and
data. Let’s break this down into a series of steps that shift away from a centralized solution to a distributed
one.
To start, we can keep the web server’s front end and replace the back-end code with the distributed
application. The Ethereum blockchain, as an example, is a deterministic state machine that runs on a peer-to-
peer network. A deterministic state machine has a model of computation that relies on a finite number of
states and transitions between them to respond to inputs. It guarantees a single transition from one state to
another in response to an input. Because it is based on a deterministic state machine, the Ethereum
blockchain is often referred to as a “world computer.” Ethereum blockchain transactions are calls to methods
that are implemented in smart contracts. These method calls result in change to the data (aka, state) that is
maintained by the contracts within the blockchain. The Ethereum blockchain records transactions into blocks
that are added to its blockchain. Changes to the state machine itself (e.g., modify the block or transaction data
structures used in the Ethereum blockchain) require consensus between the node providers that support the
peer-to-peer blockchain network. Anyone in the world can read or write to the machine—a central authority
does not govern it.
Smart contracts form the code and are written in high-level languages like Solidity or Vyper. The high-level
contract code is compiled into bytecode that can be executed on the Ethereum Virtual Machine (EVM). Each
block contains a hash pointer of the previous block, with a time stamp and the transaction data. The hash
pointer includes a cryptographic hash (i.e., a fixed-size digest of the previous block that makes it possible to
verify that the previous block was not changed since it was stored in the blockchain; the cryptographic part
ensures that the hash value has some special properties and, in particular, that the original data cannot be
derived from the hash value).
Figure 11.9 replaces the traditional back-end components of a website with a blockchain. The user’s interaction
with the website is consistent with a traditional Web 2.0 website, as the back-end processing is hidden from
the user, though it has been replaced with a blockchain node.
578 11 • Web Applications Development
Figure 11.9 Here is a traditional Web 2.0 website with back-end components replaced with a DApp. (attribution: Copyright Rice
University, OpenStax, under CC BY 4.0 license)
In the figure, the web server talks to a node of the blockchain, referred to as a full node. A full node is a
computer that maintains a copy of the blockchain and runs blockchain software. Operating a full node can
become expensive because you need to provide the hardware and pay a fee to join the Ethereum network.
Blockchain end users typically use a software wallet such as MetaMask to access nodes in the blockchain or
use a third-party wallet offered by providers like Infura, Alchemy, or QuickNode. MetaMask is a wallet
technology that stores a user’s private keys in their browser.
Blockchain providers use the JSON-RPC specification for managing communication from clients/end users. This
remote procedure call (RPC) is lightweight and transport agnostic.
As previously mentioned, any client can access the blockchain via a wallet provider, which requires creating an
account and obtaining a wallet ID. Once logged into their wallets, clients can perform blockchain transactions,
which end up reading and/or writing to the blockchain and changing the state of smart contracts. The wallet
ID is used to sign transactions so they can be traced to the client wallet. In our example, browsing photos on
the Web 3.0 application is a read transaction that would not require signing anything; however, adding photos
and comments would.
Adding data to the blockchain incurs a cost as nodes now need to store that data. The user incurs this
expense. Imagine paying every time you upload a photo to your favorite social media app. Instead of storing
the data on the blockchain, a cost-effective approach would be to store the data using the InterPlanetary File
System (IPFS) protocol. IPFS is a peer-to-peer distributed file-sharing protocol. You can go through a provider
like Pinata to get a hash value for the data (i.e., a fixed length digest of the data that cannot be used to obtain
the original data) you upload to the IPFS and store that hash value in the blockchain via a smart contract
interface, thereby reducing the storage cost of data within the blockchain.
Figure 11.10 This architecture has added a signer, provider, and IPFS. (attribution: Copyright Rice University, OpenStax, under CC BY
4.0 license)
Up to this point, we’ve kept the front-end logic on a web server hosted in a centralized location. This is a good
temporary approach for an organization that wants to transition a legacy solution to a DApp over time.
Because IPFS will host some of the data of the DApp, let’s move the front-end HTML, CSS, and JavaScript there
and load it into the browser like an SPA app.
Like an SPA, we want the application to run asynchronously and respond to events (like changing data) as they
occur. [Link] is a JavaScript library that uses the JSON-RPC to respond to events fired when smart contracts
execute. Alternatively, The Graph is a solution that uses GraphQL to make it easier to query data on the
blockchain.
Figure 11.11 shows the updated architecture with the front-end residing in IPFS and the addition of The Graph
(listed as GraphQL) for improved querying of the blockchain.
580 11 • Web Applications Development
Figure 11.11 The front-end web page has been moved to IPFS, and graphing query capabilities have been added. (attribution:
Copyright Rice University, OpenStax, under CC BY 4.0 license)
This results in a Web 3.0 application; however, there are problems with this architecture that we will examine
next.
One approach to help with scaling is the use of sidechains. A sidechain is a secondary (i.e., level 2 or L2)
blockchain that increases the blockchain network performance by aggregating transactions off-chain (i.e., off
the mainnet/Ethereum network) and committing them to the mainnet at once. Polygon is a popular L2 scaling
system for sidechaining. Other L2 scaling techniques include blockchain rollups, which are protocols designed
to enable high throughput and lower costs. They address scaling by bundling transactions and reducing data
sizes to increase transaction efficiency and limit storage costs. Examples of blockchain rollups include
optimistic and zero-knowledge rollups. An optimistic rollup is a protocol that increases transaction output by
bundling multiple transactions into batches, which are processed off-chain. In this case, transaction data is
recorded on the mainnet via data compression techniques that lower cost and increase transaction speed.
Optimistic rollups on Ethereum can improve scalability by a factor of 10 to 100. A zero-knowledge rollup (zk-
rollup) is a protocol that bundles transactions into batches that are executed off the mainnet. For every batch,
a zk-rollup operator submits a summary of required changes once the transactions in the batch have been
executed. Operators have also produced validity proofs that demonstrate that the changes are accurate. These
proofs are significantly smaller than transaction data so it is quicker and cheaper to verify them. Additionally,
zk-rollups are used on Ethereum to reduce transaction data size via compression techniques, which ends up
reducing user fees.
Figure 11.12 shows the addition of sidechains to the architecture to mitigate some of the challenges
associated with Web 3.0 DApps. Notice how the user’s interaction with the Web 3.0 app has grown from mostly
reading content in a Web 1.0 model to more fully participating in the content and functionality of the Web 3.0
app.
Figure 11.12 The user’s interaction with the full Web 3.0 application is highlighted here. (attribution: Copyright Rice University,
OpenStax, under CC BY 4.0 license)
As you can see, the architecture has become rather complex to support DApps effectively. However, Web 3.0 is
still in a nascent phase, and currently there are several solutions and tools being developed to make building
and deploying Web 3.0 DApps even easier. Hardhat is a developer ecosystem for building and deploying smart
contracts on a local network for testing.
582 11 • Web Applications Development
This architecture focused on blockchains and used Ethereum as the principal implementation. However, there
are other DLT solutions. Hashgraph is an approach where only selected nodes store the entire blockchain, and
voting mechanisms are introduced to validate if the blocks are correct. Stacks is another DLT where only the
smart contracts are decentralized, and the data is controlled by its owner. Owners can share or remove
it—ensuring data privacy.
Use of Frameworks
Web applications are used today to power commercial websites that are accessed by people to complete
online transactions to buy goods of any kind. Mobile web applications and native versions of such are also
available on smartphones and watches to help do the same. How does using web and native application
frameworks help people in everyday life? Provide a couple of illustrative scenarios to explain your opinion.
Your scenarios should not be limited to describing how the frameworks are used, but rather describe
situations where these frameworks are applied in real life.
Let’s consider an app for generating AI artwork. Many solutions exist today for doing this; however, we want
our app to give “ownership” to the digital artwork a person generates. AI models are trained to recognize
existing artwork (e.g., paintings available via the [Link] API) that may be copyrighted—so ownership is still
being determined in the courts. Here, the term ownership is used to attribute AI image creation and nothing
more. While AI models are very popular, some companies do not want to share data with AI model creators
and prefer to have the AI models deployed in their own infrastructure to ensure full privacy. A non-fungible
token (NFT) is a unique digital identifier on a blockchain that a user may want to create of their image and
possibly sell (i.e., transfer ownership) on a marketplace. A common use case for this app might be:
As you can imagine, running an AI image generator on a blockchain might not perform well. Likewise, creating
NFTs without blockchain technologies is counterintuitive. Therefore, the architecture for this solution needs to
encompass both Web 2.0 and 3.0 approaches.
Figure 11.13 shows how the APIs will do the heavy lifting of working with the AI model to generate the
artwork. Once the user is satisfied, they will interact with aspects of the UI that execute smart contracts to
generate and add the NFT to the blockchain. Transactions will happen on the blockchain. APIs may interact
directly with the blockchain, looking for similar works.
Figure 11.13 This outlines the user’s interaction with a hybrid Web 2.0/3.0 application. (attribution: Copyright Rice University,
OpenStax, under CC BY 4.0 license)
This model still has a centralized Web 2.0 server for artwork generation and account management; however,
portions that deal with NFT ownership and selling of that ownership are managed within the Web 3.0
blockchain infrastructure. This approach serves the needs of many businesses that want to take advantage of
Web 3.0 features while preserving their original Web 2.0 websites.
LINK TO LEARNING
In this module, you will create a simple, responsive Todo application. To accomplish this, you will use Bootstrap
and Django. Bootstrap is an open-source, responsive web application framework, and Django is a Python-
based web application development framework. Both frameworks are highly popular due to their ease of use.
Prerequisites
To build the Todo application, you must install Python, PIP, Django, Django REST Framework, Bootstrap, and
jQuery. The Todo application on the following pages was developed and tested with specific software versions.
To avoid errors, please ensure you install the same versions: Python v3.9.4, PIP v21.3.1, Django v4.0.1, Django
REST Framework v3.13.1, Bootstrap v4.5.0, and jQuery v3.5.1.
Figure 11.14 This is what appears when adding Python and its Scripts folders to the environment variables path on Windows.
(Used with permission from Microsoft.)
Figure 11.15 shows the sequence of steps needed to install the Python environment for working with Django
and the Django REST Framework.
586 11 • Web Applications Development
Figure 11.15 This screenshot displays the sequence of steps needed to install the Python environment. (Used with permission from
Microsoft)
$ mkdir BootstrapDjangoToDoApp
$ cd BootstrapDjangoToDoApp
$ django-admin startproject ToDoApp.
The period at the end of the last command is very important to ensure that Django-dependent files are
generated in the current directory. By following these commands, the directory, BootstrapDjangoToDoApp/,
will be created and Django-dependent files will be generated as shown in Figure 11.16.
Figure 11.16 The directory BootstrapDjangoToDoApp/ includes these Django-dependent files. (rendered in Django, a registered
trademark of the Django Software Foundation; attribution: Copyright Rice University, OpenStax, under CC BY 4.0 license)
Django built-in database tables are used to manage users, groups, migrations, and so forth in a web
application. To generate these tables, run the migrate command:
The final step to creating a Django project is to confirm that the setup was completed. To do this, run the
runserver command shown here:
To further confirm that the Django project setup was completed, launch a browser and navigate to
[Link] Figure 11.17 shows the Django page.
Figure 11.17 Once the Django project setup is successfully completed, this page should appear at [Link] (credit:
Django is a registered trademark of the Django Software Foundation.)
588 11 • Web Applications Development
LINK TO LEARNING
Django ([Link] is a free and open-source Python web framework that can make
web development more efficient and less time-consuming. With an emphasis on streamlining web
development and making it easier for web developers to meet deadlines, Django also requires less code.
The todo/ directory will be generated under the Django project directory, BootstrapDjangoToDoApp/. Files
related to the Todo application will be generated as shown in Figure 11.18.
Figure 11.18 This shows the todo/ directory, which is generated under the Django project directory, BootstrapDjangoToDoApp/.
(rendered in Django, a registered trademark of the Django Software Foundation; attribution: Copyright Rice University, OpenStax,
under CC BY 4.0 license)
Next, the Todo application must be registered in the Django project as an installed app so that Django can
recognize it. To do this, open the ToDoApp/[Link] file. Look for the INSTALLED_APPS variable as seen in
Figure 11.19. Add ‘todo’ to the list as shown. Because the Django REST Framework will be used, also add
‘rest_framework’ to the list.
Figure 11.19 To register the Todo application in the Django project as an installed app, the list of installed apps should include
‘rest_framework’ and ‘todo’. (rendered in Django, a registered trademark of the Django Software Foundation; attribution: Copyright
Rice University, OpenStax, under CC BY 4.0 license)
name = [Link](max_length=100)
class Meta:
verbose_name = ("Category")
verbose_name_plural = ("Categories")
def __str__(self):
return [Link]
class TodoList([Link]):
title = [Link](max_length=250)
content = [Link](blank=True)
created = [Link](default=[Link]().strftime("%Y-%m-%d"))
due_date = [Link](default=[Link]().strftime("%Y-%m-%d"))
category = [Link](Category, default="General",
on_delete=models.DO_NOTHING)
class Meta:
ordering = ["-created"] # order by most recently created
def __str__(self):
return [Link]
590 11 • Web Applications Development
The Category and TodoList Python classes describe the properties for the models for Category and TodoList
tables, respectively. The TodoList model contains a ForeignKey field to the Category model. Each todo item will
be associated with one category. After creating the models, a migration file needs to be generated to create
the physical tables in the database. To generate the migration file, run the following command:
This command will generate a migration file in todo/migrations/, which will look like the following code.
class Migration([Link]):
initial = True
dependencies = [
]
operations = [
[Link](
name='Category',
fields=[
('id', [Link](auto_created=True, primary_key=True,
serialize=False, verbose_name='ID')),
('name', [Link](max_length=100)),
],
options={
'verbose_name': 'Category',
'verbose_name_plural': 'Categories',
},
),
[Link](
name='TodoList',
fields=[
('id', [Link](auto_created=True, primary_key=True,
serialize=False, verbose_name='ID')),
('title', [Link](max_length=250)),
('content', [Link](blank=True)),
('created', [Link](default='2022-01-30')),
('due_date', [Link](default='2022-01-30')),
('category', [Link](default='General',
on_delete=[Link].DO_NOTHING, to='[Link]')),
],
options={
'ordering': ['-created'],
},
),
]
The next step is to apply the changes in the migration file to the database, which is accomplished by running
the following command:
For this application, Django uses the default sqlite3 (db.sqlite3) database. Please note that Django supports
other databases as well, including MySQL and PostgreSQL. To define the Todo model, you can use the default
Django admin interface to perform CRUD operations on the database. To use the admin interface, open the
todo/[Link] file and register the models as seen in the following code snippet.
class CategoryAdmin([Link]):
list_display = ("name",)
[Link]([Link], TodoListAdmin)
[Link]([Link], CategoryAdmin)
The next step is to create a superuser account that allows access to the admin interface. To do this, run the
following command and follow the prompts to enter a username, email address, and password for the
superuser.
Once this step is complete, restart the server using the following command:
After this is complete, open a browser and navigate to [Link] To access the admin
interface, log in with the credentials that you set up for the superuser. When you log in to the admin interface,
you should see the following page from Figure 11.20. On this page, you will have the ability to create, edit, and
delete categories and todo items.
592 11 • Web Applications Development
Figure 11.20 The admin interface is where superusers can create, edit, and delete categories and todo items in the Todo web
application. (rendered in Django, a registered trademark of the Django Software Foundation; attribution: Copyright Rice University,
OpenStax, under CC BY 4.0 license)
# todo/[Link]
class CategorySerializer([Link]):
class Meta:
model = Category
fields = "__all__"
class TodoSerializer([Link]):
class Meta:
model = TodoList
fields = "__all__"
serializer and the Todo serializer. To do this, open todo/[Link] and add the code shown in the code snippet
that follows. The viewsets class, which provides a default implementation of the CRUD operations, is imported
from rest_framework. The CategoryView and TodoView classes provide a queryset of categories and todo
items, respectively. They also specify the serializer_class defined in the previous section.
class CategoryView([Link]):
queryset = [Link]()
serializer_class = CategorySerializer
class TodoView([Link]):
queryset = [Link]()
serializer_class = TodoSerializer
router = [Link]()
[Link](r'categories', CategoryView, basename='Categories')
[Link](r'todos', TodoView, basename='Todos')
urlpatterns = [
path('', index, name="TodoList"),
path(r'api/', include([Link])),
]
Once you complete this step, launch the Django server using the following command:
To access the API, launch a browser and navigate to [Link] As shown in Figure 11.21, you
should see two API paths listed, one for categories and another for todo items.
594 11 • Web Applications Development
Figure 11.21 Once the URL paths for the API are created, two API paths are listed—one path for categories and the other for todo.
(rendered in Django, a registered trademark of the Django Software Foundation; attribution: Copyright Rice University, OpenStax,
under CC BY 4.0 license)
Todo items are dependent on categories. To perform CRUD operations on the Category table, click on the
categories API path, as shown in Figure 11.22.
Figure 11.22 The API path can be used to perform CRUD operations on the Category table. (rendered in Django, a registered
trademark of the Django Software Foundation; attribution: Copyright Rice University, OpenStax, under CC BY 4.0 license)
Once you access the Category List page, enter a category name in the field near the bottom of the page and
click the Post button to save it. You can add additional category names. Once you save each name using the
Post button, the categories will appear in JSON format, as illustrated in Figure 11.23.
Figure 11.23 The Category List is created in JSON format after saving category names. (rendered in Django, a registered trademark
of the Django Software Foundation; attribution: Copyright Rice University, OpenStax, under CC BY 4.0 license)
To ensure that categories can be updated or deleted as needed, the primary key, which is “id”, must be
included in the API path (e.g., /api/categories/{id}/). For example, to update or delete the category with id=3,
the API path is /api/categories/3/. As shown in Figure 11.24, once this category is pulled up on the Category
Instance page, the DELETE button is visible at the top to delete the category. If the category needs to be
updated, the PUT button visible near the bottom can be used for updates.
Figure 11.24 The Category Instance page provides DELETE and PUT buttons, which, respectively, can be used to delete or update a
category. (rendered in Django, a registered trademark of the Django Software Foundation; attribution: Copyright Rice University,
OpenStax, under CC BY 4.0 license)
Next, navigate back to the API root. Click on the todos API path to see, as outlined in Figure 11.25, that a Todo
596 11 • Web Applications Development
item has a Category field that appears as a drop-down list of categories. The CRUD operations also can be
performed on the TodoList table. This will be done next through the user interface via templates.
Figure 11.25 After the routers are created, a Todo item has a Category field that appears as a drop-down list of categories, such as
“Work” and “Personal.” (rendered in Django, a registered trademark of the Django Software Foundation; attribution: Copyright Rice
University, OpenStax, under CC BY 4.0 license)
Installing Bootstrap
The first step to create a UI is to install Bootstrap, which, as an open-source, responsive web application
framework, can be used in web applications like Django to create UIs. To install Bootstrap in a Django
application, you have several options. In this scenario, an efficient method is to download the Bootstrap CSS
and JS files and add them to the static/ directory, as shown in Figure 11.26. To do this, first create the static/
directory in the Django project directory. In addition, to install jQuery, download the JS file and add it to the
static/ directory. Finally, add a custom CSS file to include individual style in the Django web application.
Figure 11.26 An efficient method to install Bootstrap in a Django application is to download the Bootstrap CSS and JS files and add
them to the static/ directory. (rendered in Django, a registered trademark of the Django Software Foundation; attribution: Copyright
Rice University, OpenStax, under CC BY 4.0 license)
After adding the CSS and JS files to the static/ directory, the next step is to open the ToDoApp/[Link] file,
navigate to the bottom of the file, and add the path variables shown in the following code snippet.
STATIC_URL = 'static/'
PROJECT_ROOT = [Link]([Link](__file__))
STATIC_ROOT = [Link](PROJECT_ROOT, 'static')
To create the View, open the todo/[Link] file and add the code shown in the following code snippet. This
code takes an HTTP request object. If the request method is POST, a todo item is either created or deleted,
depending on which button is clicked. Otherwise, the request method is GET and the todo items are displayed
to the user.
category=[Link](name=category))
[Link]() # save todo item
return redirect("/") # reload page
if "taskDelete" in [Link]: # check if request is to delete a todo
checkedlist = [Link]["checkedbox"] # checked todos to be deleted
for todo_id in checkedlist:
todo = [Link](id=int(todo_id)) # get todo id
[Link]() # delete todo
return render(request, "[Link]", {"todos": todos, "categories":categories})
/* basic reset */
*,
*:before,
*:after {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
/* app */
html {
font-size: 100%;
}
body {
background: #e6f9ff;
font-family: "Open Sans", sans-serif;
}
/* super basic grid structure */
.container {
width: 600px;
margin: 0 auto;
background: #ffffff;
padding: 20px 0;
-webkit-box-shadow: 0 0 2px rgba(0, 0, 0, 0.2);
box-shadow: 0 0 2px rgba(0, 0, 0, 0.2);
}
.row {
display: block;
padding: 10px;
text-align: center;
width: 100%;
clear: both;
overflow: hidden;
.half {
width: 50%;
float: left;
}
.content {
background: #fff;
}
/* logo */
h1 {
font-family: "Rokkitt", sans-serif;
color: #666;
text-align: center;
font-weight: 400;
margin: 0;
}
.tagline {
margin-top: -10px;
text-align: center;
padding: 5px 20px;
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
color: #777;
}
/* inputs */
.inputContainer {
height: 60px;
border-top: 1px solid #e5e5e5;
position: relative;
overflow: hidden;
}
.[Link] {
border-bottom: 1px solid #e5e5e5;
margin-bottom: 20px;
}
.[Link] {
border-left: 1px solid #efefef;
}
input[type="date"],
input[type="text"],
select {
600 11 • Web Applications Development
height: 100%;
width: 100%;
padding: 0 20px;
position: absolute;
top: 0;
vertical-align: middle;
display: inline-block;
border: none;
border-radius: none;
font-size: 13px;
color: #777;
margin: 0;
font-family: "Open Sans", sans-serif;
font-weight: 600;
letter-spacing: 0.5px;
-webkit-transition: background 0.3s;
transition: background 0.3s;
}
input[type="date"] {
cursor: pointer;
}
input[type="date"]:focus,
input[type="text"]:focus,
select:focus {
outline: none;
background: #ecf0f1;
}
::-webkit-input-placeholder {
color: lightgrey;
font-weight: normal;
-webkit-transition: all 0.3s;
transition: all 0.3s;
}
::-moz-placeholder {
color: lightgrey;
font-weight: normal;
transition: all 0.3s;
}
::-ms-input-placeholder {
color: lightgrey;
font-weight: normal;
transition: all 0.3s;
}
input:-moz-placeholder {
color: lightgrey;
font-weight: normal;
transition: all 0.3s;
input:focus::-webkit-input-placeholder {
color: #95a5a6;
font-weight: bold;
}
input:focus::-moz-input-placeholder {
color: #95a5a6;
font-weight: bold;
}
.inputContainer label {
padding: 5px 20px;
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
color: #777;
display: block;
position: absolute;
}
button {
font-family: "Open Sans", sans-serif;
background: transparent;
border-radius: 2px;
border: none;
outline: none;
height: 50px;
font-size: 14px;
color: #fff;
cursor: pointer;
text-transform: uppercase;
position: relative;
-webkit-transition: all 0.3s;
transition: all 0.3s;
padding-left: 30px;
padding-right: 15px;
}
.icon {
position: absolute;
top: 30%;
left: 10px;
font-size: 20px;
}
.taskAdd {
background: #444;
padding-left: 31px;
602 11 • Web Applications Development
.taskAdd:hover {
background: #303030;
}
.taskDelete {
background: #e74c3c;
padding-left: 30px;
}
.taskDelete:hover {
background: #c0392b;
}
/* task styles */
.taskList {
list-style: none;
padding: 0 20px;
}
.taskItem {
border-top: 1px solid #e5e5e5;
padding: 15px 0;
color: #777;
font-weight: 600;
font-size: 14px;
letter-spacing: 0.5px;
}
.taskList .taskItem:nth-child(even) {
background: #fcfcfc;
}
.taskCheckbox {
margin-right: 1em;
}
.complete-true {
text-decoration: line-through;
color: #bebebe;
}
.taskList .taskDate {
color: #95a5a6;
font-size: 10px;
font-weight: bold;
text-transform: uppercase;
display: block;
margin-left: 41px;
.fa-calendar {
margin-right: 10px;
font-size: 16px;
}
[class*="category-"] {
display: inline-block;
font-size: 10px;
background: #444;
vertical-align: middle;
color: #fff;
padding: 10px;
width: 75px;
text-align: center;
border-radius: 2px;
float: right;
font-weight: normal;
text-transform: uppercase;
margin-right: 20px;
}
.category- {
background: transparent;
}
.category-Personal {
background: #2980b9;
}
.category-Work {
background: #8e44ad;
}
.category-School {
background: #f39c12;
}
.category-Cleaning {
background: #16a085;
}
.category-Other {
background: #d35400;
}
footer {
text-align: center;
font-size: 11px;
604 11 • Web Applications Development
font-weight: 600;
text-transform: uppercase;
color: #777;
}
footer a {
color: #f39c12;
}
/* custom checkboxes */
.taskCheckbox {
-webkit-appearance: none;
appearance: none;
-webkit-transition: all 0.3s;
transition: all 0.3s;
display: inline-block;
cursor: pointer;
width: 19px;
height: 19px;
vertical-align: middle;
}
.taskCheckbox:focus {
outline: none;
}
.taskCheckbox:before,
.taskCheckbox:checked:before {
font-family: "FontAwesome";
color: #444;
font-size: 20px;
-webkit-transition: all 0.3s;
transition: all 0.3s;
}
.taskCheckbox:before {
content: "\f096";
}
.taskCheckbox:checked:before {
content: "\f14a";
color: #16a085;
}
/* custom select menu */
.taskCategory {
-webkit-appearance: none;
appearance: none;
cursor: pointer;
padding-left: 16.5px; /*specific positioning due to difficult behavior of select
element*/
background: #fff;
.selectArrow {
position: absolute;
z-index: 10;
top: 35%;
right: 0;
margin-right: 20px;
color: #777;
pointer-events: none;
}
.taskCategory option {
background: #fff;
border: none;
outline: none;
padding: 0 100px;
}
The first template file is [Link], which is the file that includes links to Bootstrap and jQuery. To illustrate
these links, a snippet of the [Link] file is shown in the code. The Bootstrap navigation bar is implemented
in this file.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>TodoApp - Django</title>
{% load static %}
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="/static/css/[Link]" />
<link
rel="stylesheet"
type="text/css"
href="[Link]
[Link]"
/>
<link
rel="stylesheet"
type="text/css"
href="{% static 'css/[Link]' %}"
/>
<!-- jQuery -->
<script
type="text/javascript"
src="{% static 'js/[Link]' %}"></script>
<!-- Popper -->
<script
type="text/javascript"
src="{% static 'js/[Link]' %}"></script>
606 11 • Web Applications Development
<body>
<nav class="navbar navbar-dark bg-dark justify-content-between">
<a class="navbar-brand">ToDo</a>
<form class="form-inline">
<input
class="form-control mr-sm-2"
type="search"
placeholder="Search"
aria-label="Search"
/>
<button class="btn btn-outline-info my-2 my-sm-0" type="submit">
Search
</button>
</form>
</nav>
<div>{% block content %} {% endblock content %}</div>
</body>
</html>
The second template file is [Link], which lists any existing todo items and includes the form to create or
delete a todo item. A snippet of the [Link] file is shown in the following code. The [Link] file also
extends the [Link] template, which allows the Bootstrap navigation bar implemented in [Link] to be
inserted in this page and every page that extends it.
{% endblock %}
The first step to access the Todo Django web application is to restart the Django server using the following
command:
Next, launch a browser and navigate to [Link] The page highlighted in Figure 11.27 should
appear.
Figure 11.27 Once the Django server is restarted, this page should appear at [Link] (rendered in Django, a registered
trademark of the Django Software Foundation; attribution: Copyright Rice University, OpenStax, under CC BY 4.0 license)
To create a todo list, fill out the form and click the Add Task button as shown in Figure 11.28.
Figure 11.28 This figure shows how the Todo List should appear after using the Add Task button to create a todo list. (rendered in
Django, a registered trademark of the Django Software Foundation; attribution: Copyright Rice University, OpenStax, under CC BY 4.0
license)
In addition, the todo item should also be viewable in the API that was created. This should appear as outlined
in Figure 11.29.
610 11 • Web Applications Development
Figure 11.29 Once the todo item is created, it should be viewable in the API. (rendered in Django, a registered trademark of the
Django Software Foundation; attribution: Copyright Rice University, OpenStax, under CC BY 4.0 license)
In the previous section, you created a simple Todo application using Bootstrap and Django. In this section, you
will continue to use Bootstrap to create another simple Todo application. But instead of working with Django,
you will use React and Node. React, or [Link], is a JavaScript library popular to build user interfaces. Node, or
[Link], is a JavaScript runtime environment that provides users with the tools to develop web applications, as
well as servers, scripts, and command-line tools.
Creating a Todo Web Application with Bootstrap and React and Node
When creating a Todo web application using React and Node, React serves as the front end, handling the user
interface, as well as getting and setting data via HTTP requests using Axios. Node serves as the back end,
using a REST API built with ExpressJS and the MongooseJS Object Data Modeling (ODM) to interact with a
MongoDB database.
Prerequisites
To build the Todo application using Bootstrap, React, and Node, you will need the following software
components: React v17.0.2, Bootstrap v4.5.0, Node v14.17.5, ExpressJS v4.17.2, MongooseJS v6.1.9, and Axios
v0.21.0. To begin, download and install Node.
LINK TO LEARNING
Node ([Link] is a JavaScript runtime environment that provides users with the
tools to develop web applications, as well as servers, scripts, and command-line tools. Node, which is free,
is open-source and cross-platform. It was designed to develop network applications that are scalable,
managing many connections simultaneously. Unlike the typical inefficient concurrency model, with Node, a
callback is fired with each connection, and Node sleeps unless work needs to be done.
$ npm init
After running this command, follow the prompt, which is highlighted in Figure 11.30.
Figure 11.30 This prompt appears when the Node application is initialized. (attribution: Copyright Rice University, OpenStax, under
CC BY 4.0 license)
612 11 • Web Applications Development
After the Node application initialization is completed, a [Link] file is generated, as shown in the
following code.
{
"name": "nodebackend",
"version": "1.0.0",
"description": "Todo Web application with Bootstrap, ReactJS and NodeJS",
"main": "[Link]",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"bootstrap",
"reactjs",
"nodejs",
"express",
"mongodb",
"rest",
"api"
],
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.19.1",
"cors": "^2.8.5",
"express": "^4.17.2",
"mongoose": "^6.1.9"
}
}
Next, create the Express web server by going to the nodebackend/ directory, create the [Link] file, and add
the following code.
var corsOptions = {
origin: "[Link]
};
[Link](cors(corsOptions));
// routes
[Link]("/", (req, res) => {
[Link]({ message: "Welcome to the Todo Web App." });
});
require("./routes/[Link]")(app);
Once you use the code to import Express, you can build the REST APIs. The body-parser package is used to
create and parse the request object. The cors package is used to serve as middleware for Express that enables
CORS. The Express web server will run on port 8080 as the default port. Use the following command to start
the server:
$ node [Link]
In a browser, navigate to [Link] The following page shown in Figure 11.31 renders.
Figure 11.31 Once the Express web server is started, this page should appear at [Link] (rendered in Node;
attribution: Copyright Rice University, OpenStax, under CC BY 4.0 license)
[Link] = {
url: "mongodb://localhost:27017/todo_db"
};
614 11 • Web Applications Development
Once the MongoDB connection URL is configured, the next step is to add code to connect to the database
using Mongoose. To do this, in the nodebackend/ directory, create the models/ directory. In the models/
directory, create the [Link] file and add the following.
const db = {};
[Link] = mongoose;
[Link] = [Link];
[Link] = require("./[Link]")(mongoose);
[Link] = db;
Next, the nodebackend/[Link] file needs to be updated to enable the Express web server to establish a
connection with the MongoDB. The code for this is shown in the following snippet.
const db = require("./models");
[Link]([Link], {
useNewUrlParser: true
}).then(() => {
[Link]("Connected to the database successfully!")
}).catch(err => {
[Link]("Cannot connect to the database: " , err);
[Link]();
});
Once the database connection code is completed, the next step is to create the Mongoose model. To do this, in
the nodebackend/models/ directory, create the file [Link] and add the following code. This code
defines a Mongoose schema for the todos model, which results in the creation of a todos collection in the
MongoDB database.
required: true,
},
category: {
type: String,
required: true,
},
});
[Link]("toJSON", function() {
const { __v, _id, ...object } = [Link]();
[Link] = _id;
return object;
});
const Todos = [Link]("todos", schema);
return Todos;
};
const db = require("../models");
const Todos = [Link];
[Link](condition)
.then(data => {
[Link](data);
})
.catch(err => {
[Link](500).send({
message:
[Link] || "An error occurred while retrieving todo items."
});
});
};
[Link](id)
.then(data => {
if (!data)
[Link](404).send({ message: "Error finding todo item with id " + id });
else [Link](data);
})
.catch(err => {
res
.status(500)
.send({ message: "Error retrieving todo item with id=" + id });
});
};
const id = [Link];
.then(data => {
[Link]({
message: `${[Link]} All todo items were deleted successfully!`
});
})
.catch(err => {
[Link](500).send({
message:
[Link] || "An error occurred while deleting all todo items."
});
});
};
[Link]("/api/todos", router);
};
The next step is to update nodebackend/[Link] to import the routes shown in the following code.
// routes
[Link]("/", (req, res) => {
require("./routes/[Link]")(app);
The next step is to run the Express web server to test the CRUD functions and interact with the MongoDB
database. To do this, run the following command:
$ node [Link]
LINK TO LEARNING
To test the REST API, use Postman, which is an API platform testing tool that can be used as a client. To
accomplish this, follow these steps:
After you follow these steps, the bottom frame should receive a response with status “200 OK” indicating the
request was handled successfully. The body of the created todo item will also display along with a generated id
field. You can use this method to test all the CRUD functions.
LINK TO LEARNING
Once you run the command, it will generate the React application files in the reactfrontend/ directory, which is
shown in Figure 11.32.
Figure 11.32 This shows the React application files in the reactfrontend/ directory. (rendered in React by Meta Open Source;
attribution: Copyright Rice University, OpenStax, under CC BY 4.0 license)
The next step is to navigate into the reactfrontend/ directory and launch the React application to confirm the
React front-end application was created successfully. At this point, this application is not connecting to the
Node back end, so it launches a default React page. Run the command, which will automatically launch a
browser page to [Link]
$ npm start
Figure 11.33 When the React front-end application is created successfully, this page launches at [Link] (credit: React
by Meta Open Source)
4
Next, import the Bootstrap CSS file into the React application. To do this, open reactfrontend/src/[Link] and
add the following Bootstrap import.
[Link](
<[Link]> <App /> </[Link]>,
[Link]('root')
);
To compare with the Django web application in 11.2 Sample Responsive WAD with Bootstrap and Django,
customized CSS rules were added to the [Link] file in the static/ directory, as described in Creating the
Templates.
Next, look at the following code, which shows App is a class component that extends React’s Component class.
All state data is added to the [Link] variable in the constructor.
The next code snippet shows that every class component must include a render() function. This function
returns the components that construct the user interface for the Todo web application.
render () {
return(
<main> <Nav /> <div className="container mt-5 pl-3">
<h1>Todo List</h1> <Form> <div
className="inputContainer"> <FormGroup> <Label
htmlFor="description">Description</Label> <Input type="text"
id="description" name="description" placeholder="Description"
value={[Link]} />
</FormGroup> </div> <div
className="inputContainer half last"> <FormGroup>
<Label htmlFor="category">Category</Label> <Input
id="category" className="taskCategory" type="select" name="category_select"
value={[Link]} >
<option className="disabled" value="">Choose a category</option>
<option>Work</option>
<option>Personal</option> </Input>
</FormGroup> </div> <div
className="inputContainer half last right"> <FormGroup>
<Label htmlFor="description">Due Date</Label>
<Input type="text" id="description" name="description"
placeholder="Due Date (mm/dd/yyyy)"
value={[Link]} />
</FormGroup> </div> <div className="row">
<Button className="taskAdd"
name="taskAdd" type="submit" >
Edit </Button> <Button
className="taskDelete ml-1" name="taskDelete"
type="submit"
>
Delete </Button> </div>
Next, add a proxy to the Node application. The proxy will help tunnel API requests from the React application
to [Link] where the Node application will receive and handle the requests. To do this, open the
reactfrontend/[Link] file and add the following proxy.
{
"name": "reactfrontend",
"version": "0.1.0",
"private": true,
"proxy": "[Link]
"dependencies": {
The next step is to create a service on the front end to send HTTP requests to the back end. This process uses
Axios and is similar to how routes were created on the back-end side. The service will export CRUD functions
and a finder method to interact with the MongoDB database. To do this, in the reactfrontend/ directory, create
the services/ directory. Then, in the services/ directory, create the tile [Link] and add the following
code.
};
export default {
getAll,
get,
create,
update,
remove,
removeAll
};
Finally, to complete this step, update reactfrontend/[Link] to the following to call the services.
[Link](data)
.then((res) => [Link]())
.catch((err) => [Link](err));
};
handleUpdate = (item) => {
var data = {
id: [Link],
title: [Link],
content: [Link],
due_date: item.due_date,
category: [Link]
};
[Link]([Link], data)
.then((res) => [Link]())
.catch((err) => [Link](err));
};
handleDelete = (item) => {
[Link]([Link])
.then((res) => [Link]())
.catch((err) => [Link](err));
};
refreshList = () => {
[Link]()
.then((res) => [Link]({ todoList: [Link] }))
Once this is completed, run both the Express web server and the React app using the following commands:
$ node [Link]
$ npm start
When this is done, use the form shown in Figure 11.34 to create a new todo item.
Figure 11.34 Once the Todo web application is created using Bootstrap with React and Node, this form can be used to create todo
items. (rendered using Bootstrap, under MIT license copyrighted 2018 Twitter, with React by Meta Open Source and Node;
attribution: Copyright Rice University, OpenStax, under CC BY 4.0 license)
Previously, you learned how to build a Todo web application using Bootstrap and Django and then using
Bootstrap with React and Node. This section will review the steps required to update the Todo web application
using Bootstrap with React and Django.
Updating the Todo Web Application with Bootstrap, React, and Django
In this section, the Todo web application implemented will build on the Django application covered in 11.2
Sample Responsive WAD with Bootstrap and Django, as well as the React application explored in 11.3 Sample
Responsive WAD with Bootstrap/React and Node. For this version of the Todo web application, React serves as
the front end handling the user interface to get and set data via HTTP requests. Django serves as the back end.
626 11 • Web Applications Development
Prerequisites
To build this version of the Todo application, you need Python v3.9.4, PIP v21.3.1, Django v4.0.1, Django REST
Framework v3.13.1, Bootstrap v4.5.0, Django-cors-headers v3.11.0, React v17.0.2, and Axios v0.21.0. To begin,
complete the following steps:
LINK TO LEARNING
Extending the Django Back End to Support the React Front End
To create a Todo web application using React as a front end to the Django back end, the Django project
requires a couple of configurations. Open TodoApp/[Link] and add ‘corsheaders’ to INSTALLED_APPS as in
the following code.
INSTALLED _APPS = [
'[Link]',
'[Link]',
'[Link]',
'[Link]',
'[Link]',
'[Link]',
'corsheaders',
'rest_framework',
'todo',
]
By configuring the Django project with CORS, the Django application will be allowed to accept in-browser
requests that come from other origins. To add CORS, add the CORS middleware to MIDDLEWARE, as shown in
the following code.
MIDDLEWARE = [
'[Link]',
'[Link]',
'[Link]',
'[Link]',
'[Link]',
'[Link]',
'[Link]',
'[Link]',
After completing this step, scroll to the bottom of the [Link] file and add the following variable.
# add CORS whitelist for localhost:3000 since the React frontend will be served on
port 3000
CORS_ORIGIN_WHITELIST = [
'[Link]
]
LINK TO LEARNING
Axios is an HTTP client for Node that manages asynchronous HTTP requests. Axios is free and open-source,
with built-in security measures. Axios uses clean, efficient syntax to manage promises, and works well with
Node, as well as browser environments. Visit this page on Axios ([Link] to learn
more.
Next, add a proxy to the Django application. The proxy will help tunnel API requests from the React application
to [Link] where the Django application will receive and handle the requests. To add the proxy,
open the reactfrontend/[Link] file and add the following code.
{
"name": "reactfrontend",
"version": "0.1.0",
"private": true,
"proxy": "[Link]
"dependencies": {
After completing this step, open the reactfrontend/src/[Link] file and import Axios, as shown in the following
code.
import './[Link]';
import React, { Component } from "react";
import Modal from "./components/Modal";
import Nav from "./components/NavComponent";
import axios from "axios";
import { Button, Form, FormGroup, Label, Input } from 'reactstrap';
To update the reactfrontend/src/[Link] file, add the following code. The handleSubmit() function will use
Axios to make requests to the Django API endpoints to create and delete todo items.
if ([Link]) {
axios
.put(`/api/todos/${[Link]}/`, item)
.then((res) => [Link]());
return;
}
axios
.post("/api/todos/", item)
.then((res) => [Link]());
};
When these steps are complete, start up the Django server and then start up the React application, using the
following commands, respectively.
To access the Django REST API, navigate to [Link] This is similar to the steps completed in
11.2 Sample Responsive WAD with Bootstrap and Django. Click on the categories API path to enter two
categories, as seen in Figure 11.35.
Figure 11.35 After navigating to [Link] and following the instructions provided, this page will appear to allow
access to the Django REST API. (rendered in React by Meta Open Source; attribution: Copyright Rice University, OpenStax, under CC
BY 4.0 license)
When the React application starts up, a browser page will automatically launch for navigating to
[Link] and the user interface should render. Figure 11.36 shows the page on which to create a
todo item.
Figure 11.36 After the React application starts up, this user interface will appear. (rendered in React by Meta Open Source;
attribution: Copyright Rice University, OpenStax, under CC BY 4.0 license)
At this point, revisit the Django REST API. Figure 11.37 shows that the todo item should be accessible via the
todos API path.
630 11 • Web Applications Development
Figure 11.37 Once the Todo web application is updated using Bootstrap with Django and React, this page should appear to allow
users to create a Todo List. (rendered using Bootstrap under MIT license copyrighted 2018 Twitter; with Django, a registered
trademark of the Django Software Foundation; and React by Meta Open Source; attribution: Copyright Rice University, OpenStax,
under CC BY 4.0 license)
11.5 Sample Native WAD with React Native and Node or Django
Learning Objectives
By the end of this section, you will be able to:
• Create a Todo native mobile application with React Native or Node
• Create a React Native app and its components
• Connect the front-end Native app with the back-end Node app
In the previous sections, you worked with Bootstrap, Django, React, and Node to build versions of a Todo web
application. In this section, you will learn how to use React Native and Node to develop a Todo application for
mobile devices. You are already familiar with Node. Like React, React Native is an open-source JavaScript
framework used to build native applications for mobile devices.
LINK TO LEARNING
React Native ([Link] uses the React JavaScript library to enable native
development and build user interfaces for mobile devices. React Native has the flexibility to work with
Xcode, which is the IDE for various platforms. Released by Facebook (now Meta) in 2015, React Native has
become increasingly popular among developers.
Prerequisites
To build the Todo mobile application using React Native and Node, you need React Native v0.67, Node
v14.17.5, ExpressJS v4.17.2, MongooseJS v6.1.9, and Axios v0.21.0. This Todo application will run using the
Android emulator and will use Android Studio v2021.1.1.
LINK TO LEARNING
Xcode ([Link] is the IDE for the Apple platform. For Apple, React Native provides
developers with the tools needed for cross-platform development that creates user-friendly apps on mobile
devices.
• To begin, download and install an emulator for your intended platform (iOS or Android).
• If you plan to run the native app on an iOS device or emulator, download and install Xcode, which is
Apple’s IDE that enables application development for Apple’s platforms.
• If you plan to run the native app on an Android device or emulator, download and install Android Studio,
which enables application development for Android mobile operating systems.
• Figure 11.38 shows how to set up the Android emulator. Launch Android Studio. From the top navigation,
select Tools > Device Manager. Click on Create device. In the Select Hardware pop-up, select Pixel 5 and
click Next. On the next page, select Pie Download. Click on the Download link to obtain an image as
shown. Click Next followed by Finish.
632 11 • Web Applications Development
Figure 11.38 This shows how to set up the Android emulator. (Android Studio is a trademark of Google LLC.)
Once the image has been created, it will appear in the Device Manager. Next, click on the Start button to
launch the emulator. When the emulator is launched, it will turn on, as shown in Figure 11.39.
Figure 11.39 This is how the emulator will appear after it is launched. (Android Studio is a trademark of Google LLC.)
LINK TO LEARNING
Xcode also integrates well with Android Studio ([Link] for developing
Android apps. Android Studio is the IDE for Android devices.
Figure 11.40 When the React Native app is created, it will generate the React Native application files in the reactnativefrontend/
directory. (rendered in React Native, under MIT license; attribution: Copyright Rice University, OpenStax, under CC BY 4.0 license)
Next, navigate into the reactnativefrontend/ directory and launch the React Native application to confirm that
the React Native front-end application has been created successfully. At this point, the application is not
connected to the Node back end and will launch the Metro bundler, which bundles the JavaScript code that is
deployed on the mobile device or emulator when the React Native front-end application is successfully
completed. When this is done, run the command. Figure 11.41 shows the page in the terminal.
Figure 11.41 This page will appear when the react-native start command is run. (credit: React Native, under MIT license)
The next step is to open another terminal, navigate to the reactnativefrontend/ directory, and run the
following command. This will build the front-end code and deploy it on the emulator, which may take a few
minutes.
When the application is successfully built, Figure 11.42 shows what should appear in the second terminal.
636 11 • Web Applications Development
Figure 11.42 This code should appear in the second terminal when the React Native application is successfully built. (attribution:
Copyright Rice University, OpenStax, under CC BY 4.0 license)
Figure 11.43 shows how the native application should appear in the emulator.
Figure 11.43 Once the React Native application is successfully built, this is how the native application should appear in the emulator.
(Android Studio is a trademark of Google LLC.)
The first step is to create the Todo component. In the reactnativefrontend/ directory, create the directory src/
Screens/. In the src/Screens/ directory, create the file [Link]. The following code shows the imports
required to create the screen components.
638 11 • Web Applications Development
Once this is done, the following code includes the return() function that renders the screen components.
return (
<View style={[Link]}> <StatusBar backgroundColor={[Link]} />
<Text style={[Link]}>Welcome to Todo List App!</Text> <Text
style={[Link]}>Your Tasks</Text> {[Link] == 0 ? ( <View
style={[Link]}> <MaterialCommunityIcon name="note-multiple"
size={90} color={[Link]} /> <Text
style={[Link]}>No Tasks Added</Text> </View> ) : ( <>
<View style={[Link]}> <FlatList
data={todos} renderItem={({item}) => ( <View
style={[Link]}> <Text style={[Link] ?
[Link] : [Link]}> {[Link]}
</Text> <TouchableOpacity
style={[Link]} =>
deleteTodo(item._id)}> <Text style={{color: [Link]}}>X</Text>
</TouchableOpacity> </View> )} />
</View> <TouchableOpacity style={[Link]}
=> { setModalActive(true); }}>
<MaterialIcon name="add" size={32} color={[Link]} />
</TouchableOpacity> </>
)}
<Modal
isVisible={modalActive}
animationIn={'slideInUp'}
animationOut={'slideInDown'}>
<View style={[Link]}> <TouchableOpacity
style={[Link]} =>
setModalActive(false)}> <Text style={[Link]}>X</Text>
The following code creates the modal pop-up screen that is used to create a Todo list.
<Modal
isVisible={modalActive}
animationIn={'slideInUp'}
animationOut={'slideInDown'}>
<View style={[Link]}> <TouchableOpacity
style={[Link]} => setModalActive(false)}>
<Text style={[Link]}>X</Text> </TouchableOpacity>
<Text style={[Link]}>Add Task</Text> <TextInput
style={[Link]} placeholder="Enter task here.."
=> setNewTodo(text)} value={newTodo} />
<TouchableOpacity style={[Link]} => addTodo()}> <Text
style={[Link]}>Create Task</Text> </TouchableOpacity> </View>
</Modal>
Next, update the reactnativefrontend/[Link] file, as shown in the following code, to render the screen
components declared in the [Link] file.
When this is done, relaunch the Metro bundler and deploy the native application by running the following
commands:
Figure 11.44 After relaunching the Metro bundler and deploying the native application, this screen allows users to create a Todo
item. (Android studio is a trademark of Google LLC.)
After the Todo item is created, it should appear on the main screen as seen in Figure 11.45.
Figure 11.45 Here is how the Todo item should appear on the main screen. (Android studio is a trademark of Google LLC.)
Connecting the Front-End Native App with the Back-End Node App
The next step is to connect the front-end React Native app with the back-end Node app. To do this, open
reactnativefrontend/src/Screens/[Link]. Add the API_BASE variable and configure the IP address to the
local computer, running the Express web server, as shown in the following code.
Next, add the Axios calls to interact with the REST API provided via the Express web server to interact with the
MongoDB database.
642 11 • Web Applications Development
useEffect(() => {
GetTodos();
}, [todos]);
setTodos(todos =>
[Link](todo => {
if (todo._id === data._id) {
[Link] = [Link];
}
return todo;
}),
);
};
await axios
.post(`${API_BASE}/todo/new`, {
text: newTodo,
})
.then(function (response) {
const data = [Link];
setTodos([...todos, data]);
setModalActive(false);
setNewTodo('');
})
.catch(function (error) {
[Link]('Error: ', error);
});
}
};
So far, this chapter has explored how to develop a Todo web application, as well as a Todo mobile application,
using Bootstrap, Django, React, React Native, and Node. In this final section, you will learn how to create a
simple Todo application using React with Web 3.0 powered by Ethereum smart contracts on the blockchain.
LINK TO LEARNING
Prerequisites
To build the Todo Ethereum blockchain Web 3.0 application, you should use React v17.0.2, Bootstrap v4.5.0,
Node v14.17.5, Web [Link] v1.2.2, Truffle v5.0.2, and Solidity v0.8.11. In addition, Ganache is used as the personal
blockchain for development. To begin, do the following:
644 11 • Web Applications Development
• Download and install Ganache. Launch Ganache and choose the quick start Ethereum option as seen in
Figure 11.46.
Figure 11.46 This is the quick start Ethereum option that is available after installing Ganache. (credit: Ganache, under MIT
license)
• The next step is to install the MetaMask Chrome plug-in. Configure the MetaMask account and log in.
Next, import the Bootstrap CSS file into the React application. Open ethreact/src/[Link] and add the following
Bootstrap import.
import 'bootstrap/dist/css/[Link]';
import './[Link]';
import App from './App';
import reportWebVitals from './reportWebVitals';
[Link](
<[Link]> <App /> </[Link]>,
[Link]('root')
);
LINK TO LEARNING
Truffle ([Link] provides a suite of tools that can be used to develop smart
contracts. Truffle offers end-to-end development that includes the ability to develop, test, and implement
smart contracts, while using Truffle to manage the workflow.
To set up the React app to use Truffle, in the ethreact/ directory, run the following command, which may take
several minutes.
$ truffle init
When the initialization is completed, the contracts/ directory and [Link] file will be generated. In
addition, the [Link] file will be generated, as highlighted in Figure 11.47.
646 11 • Web Applications Development
Figure 11.47 Here is the [Link] file. (rendered with Truffle by Truffle Security Co., under MIT license; attribution: Copyright
Rice University, OpenStax, under CC BY 4.0 license)
To create the smart contract, in the ethreact/contracts/ directory, create the file [Link] and add the
following code.
struct Task {
uint id;
string content;
bool completed;
}
event TaskCreated(
uint id,
string content,
bool completed
);
event TaskCompleted(
uint id,
bool completed
);
constructor () public {
createTask("Check out [Link]");
}
Next, compile the smart contract. In the ethreact/ directory, run the following command:
$ truffle compile
This command should provide a status confirming that the smart contract has been successfully compiled as
seen in the following code:
Figure 11.48 shows how this process will generate a few files, including two JSON files in the build/contracts/
directory and a migration file in the migrations/ directory.
Figure 11.48 These are the JSON and migration files generated when the smart contract is compiled. (rendered using JSON;
attribution: Copyright Rice University, OpenStax, under CC BY 4.0 license)
The [Link] file in the build/contracts/ directory is the smart contract Abstract Binary Interface (ABI) file.
This file contains the following:
648 11 • Web Applications Development
• compiled bytecode from the Solidity smart contract code that can run on the Ethereum Virtual Machine
(EVM)
• a JSON representation of the smart contract.
Next, configure the React app to connect to the Ganache blockchain network. To do this, open the ethreact/
[Link] file and uncomment the two sections shown. Under “networks,” enable the connection host
and port to the Ganache blockchain network. Ensure that the host and port are in sync with the following
settings in Ganache.
development: {
host: "[Link]", // Localhost (default: none)
port: 7545, // Standard Ethereum port (default: none)
network_id: "*", // Any network (default: none)
},
Next, create a migration script to deploy the smart contract to the Ganache blockchain network. In the
ethreact/migrations/ directory, create the file 2_deploy_contracts.js and add the following code.
[Link] = function(deployer) {
[Link](TodoList);
};
The next step is to migrate the contract. In the ethreact/ directory, run this command.
$ truffle migrate
Figure 11.49 displays how the contract will be migrated and provides the transaction details. You should make
a note of the contract address in the output because it will be added to the [Link] file later.
Figure 11.49 Here are the transaction details for migrating the contract. (attribution: Copyright Rice University, OpenStax, under CC
BY 4.0 license)
LINK TO LEARNING
render() {
return (
<div id="content"> <form => {
[Link]() [Link]([Link])
}}> <input id="newTask" ref={(input) => {
[Link] = input }} type="text"
className="form-control" placeholder="Add task..."
required /> <input type="submit" hidden={true} />
</form> <ul id="taskList" className="list-unstyled"> {
[Link]((task, key) => { return( <div
className="taskTemplate" className="checkbox" key={key}> <label>
<input type="checkbox"
name={[Link]} defaultChecked={[Link]}
650 11 • Web Applications Development
render() {
return (
<div> <nav className="navbar navbar-dark fixed-top bg-dark flex-md-nowrap
p-0 shadow"> <a className="navbar-brand col-sm-3 col-md-2 mr-0"
href="#">ToDo</a> <ul className="navbar-nav px-3"> <li
className="nav-item text-nowrap d-none d-sm-none d-sm-block"> <small><a
className="nav-link" href="#"><span id="account"></span></a></small> </li>
</ul> </nav> <div className="container-fluid"> <div
className="row"> <main role="main" className="col-lg-12 d-flex justify-
content-center"> { [Link] ? <div id="loader"
className="text-center"><p className="text-center">Loading...</p></div>
: <TodoList tasks={[Link]}
createTask={[Link]}
toggleCompleted={[Link]} /> }
</main> </div> </div> </div>
);
}
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "id",
"type": "uint256"
},
{
"indexed": false,
"internalType": "bool",
"name": "completed",
"type": "bool"
}
],
"name": "TaskCompleted",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "id",
"type": "uint256"
},
{
"indexed": false,
"internalType": "string",
"name": "content",
"type": "string"
},
{
"indexed": false,
"internalType": "bool",
"name": "completed",
"type": "bool"
}
],
"name": "TaskCreated",
"type": "event"
},
{
"constant": true,
"inputs": [],
"name": "taskCount",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "tasks",
"outputs": [
{
"internalType": "uint256",
"name": "id",
"type": "uint256"
},
{
"internalType": "string",
"name": "content",
"type": "string"
},
{
"internalType": "bool",
"name": "completed",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"internalType": "string",
"name": "_content",
"type": "string"
}
],
"name": "createTask",
"outputs": [],
"payable": false,
654 11 • Web Applications Development
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"internalType": "uint256",
"name": "_id",
"type": "uint256"
}
],
"name": "toggleCompleted",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
}
]
Next, update ethreact/src/[Link]. Import [Link] and add the following code to the
componentDidMount() life cycle method. This will connect to the blockchain network and load the contract
before the React components renders in the browser.
// Set web3, accounts, and contract to the state, and then proceed with an
// example of interacting with the contract's methods.
[Link]({ web3, accounts, todoListContract: todoListInstance },
[Link]);
} catch (error) {
// Catch any errors for any of the above operations.
alert(
'Failed to load web3, accounts, or contract. Check console for details.',
);
[Link](error);