100% found this document useful (12 votes)
1K views

Practical Rust Web Projects: Building Cloud and Web-Based Applications Shing Lyu all chapter instant download

Shing

Uploaded by

riftonmaheo
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (12 votes)
1K views

Practical Rust Web Projects: Building Cloud and Web-Based Applications Shing Lyu all chapter instant download

Shing

Uploaded by

riftonmaheo
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 55

Experience Seamless Full Ebook Downloads for Every Genre at textbookfull.

com

Practical Rust Web Projects: Building Cloud and


Web-Based Applications Shing Lyu

https://textbookfull.com/product/practical-rust-web-
projects-building-cloud-and-web-based-applications-shing-
lyu/

OR CLICK BUTTON

DOWNLOAD NOW

Explore and download more ebook at https://textbookfull.com


Recommended digital products (PDF, EPUB, MOBI) that
you can download immediately if you are interested.

Building web and mobile ArcGIS Server applications with


JavaScript Lewin

https://textbookfull.com/product/building-web-and-mobile-arcgis-
server-applications-with-javascript-lewin/

textboxfull.com

Practical Node.js: Building Real-World Scalable Web Apps


Azat Mardan

https://textbookfull.com/product/practical-node-js-building-real-
world-scalable-web-apps-azat-mardan/

textboxfull.com

Programming C 8 0 Build Cloud Web and Desktop Applications


Ian Griffiths

https://textbookfull.com/product/programming-c-8-0-build-cloud-web-
and-desktop-applications-ian-griffiths/

textboxfull.com

Practical Web Penetration Testing Secure Web Applications


Using Burp Suite Nmap Metasploit and More 1st Edition Gus
Khawaja
https://textbookfull.com/product/practical-web-penetration-testing-
secure-web-applications-using-burp-suite-nmap-metasploit-and-more-1st-
edition-gus-khawaja/
textboxfull.com
Blazor Revealed: Building Web Applications in .NET 1st
Edition Peter Himschoot

https://textbookfull.com/product/blazor-revealed-building-web-
applications-in-net-1st-edition-peter-himschoot/

textboxfull.com

Angular 5 Projects: Learn to Build Single Page Web


Applications Using 70+ Projects 1st Edition Mark Clow

https://textbookfull.com/product/angular-5-projects-learn-to-build-
single-page-web-applications-using-70-projects-1st-edition-mark-clow/

textboxfull.com

Web Performance in Action: Building Faster Web Pages 1st


Edition Jeremy Wagner

https://textbookfull.com/product/web-performance-in-action-building-
faster-web-pages-1st-edition-jeremy-wagner/

textboxfull.com

Complete Vue js 2 Web Development Practical guide to


building end to end web development solutions with Vue js
2 1st Edition Mike Street
https://textbookfull.com/product/complete-vue-js-2-web-development-
practical-guide-to-building-end-to-end-web-development-solutions-with-
vue-js-2-1st-edition-mike-street/
textboxfull.com

Flask Web Development Developing Web Applications With


Python 2nd Edition Miguel Grinberg

https://textbookfull.com/product/flask-web-development-developing-web-
applications-with-python-2nd-edition-miguel-grinberg/

textboxfull.com
Shing Lyu

Practical Rust Web Projects


Building Cloud and Web-Based Applications
1st ed.
Shing Lyu
Amsterdam, The Netherlands

Any source code or other supplementary material referenced by the


author in this book is available to readers on GitHub via the book’s
product page, located at www.​apress.​com/​9781484265888. For more
detailed information, please visit http://​www.​apress.​com/​source-code.

ISBN 978-1-4842-6588-8 e-ISBN 978-1-4842-6589-5


https://doi.org/10.1007/978-1-4842-6589-5

© Shing Lyu 2021

This work is subject to copyright. All rights are reserved by the


Publisher, whether the whole or part of the material is concerned,
specifically the rights of translation, reprinting, reuse of illustrations,
recitation, broadcasting, reproduction on microfilms or in any other
physical way, and transmission or information storage and retrieval,
electronic adaptation, computer software, or by similar or dissimilar
methodology now known or hereafter developed.

The use of general descriptive names, registered names, trademarks,


service marks, etc. in this publication does not imply, even in the
absence of a specific statement, that such names are exempt from the
relevant protective laws and regulations and therefore free for general
use.

The publisher, the authors and the editors are safe to assume that the
advice and information in this book are believed to be true and accurate
at the date of publication. Neither the publisher nor the authors or the
editors give a warranty, expressed or implied, with respect to the
material contained herein or for any errors or omissions that may have
been made. The publisher remains neutral with regard to jurisdictional
claims in published maps and institutional affiliations.

Distributed to the book trade worldwide by Apress Media, LLC, 1 New


York Plaza, New York, NY 10004, U.S.A. Phone 1-800-SPRINGER, fax
(201) 348-4505, e-mail [email protected], or visit
www.springeronline.com. Apress Media, LLC is a California LLC and the
sole member (owner) is Springer Science + Business Media Finance Inc
(SSBM Finance Inc). SSBM Finance Inc is a Delaware corporation.
For my wife Wei-Chi, my father Ching-Chuan, and my mother Man-Yun.
Table of Contents
Chapter 1:​Rust in the Web World
Who Is This Book For?​
Who Is This Book Not For?
Criteria for Selecting Libraries
Pure-Rust
Maturity
Popularity
How To Use This Book
Chapter Overview
Source Code
Chapter 2:​Developing Websites
What Are You Building?​
Hello World!
Serving Static Files
Rendering Dynamic Templates
Using a Database
Adding Cats with a Form
Showing the Cat Detail Page
Other Alternatives
Chapter 3:​REST APIs
What Are You Building?​
Converting the Cats List to a REST API
API Testing
Building the Cat Detail API
Input Validation
Error Handling
Using a ResponseBuilder or Response
Using the actix web:​:e
​ rror Helpers
Using a Generic Error That Implemented the ResponseError
Trait
Using a Custom-Built Error Type
Customize the web:​:P
​ ath Extractor Error
Logging
Enabling HTTPS
Other Alternatives
Chapter 4:​Chatting in Real-Time with WebSocket
Introduction to WebSocket
What Are You Building?​
A WebSocket Echo Server
Pushing Notifications from the Server
Cleaning Up Unresponsive Clients
Two-Way Chat
Sending Structural JSON Data
Other Alternatives
Chapter 5:​Going Serverless
What Are You Building?​
Registering an AWS Account
Hello World in Lambda
Making a REST API with Lambda
Using the Serverless Framework
Building the /​cats API
Building the Upload API
Uploading the Image Using S3 Presigned URL
Adding the Frontend
Other Alternatives
Chapter 6:​High-Performance Web Frontend Using WebAssembly
What Is WebAssembly?​
What Are You Building?​
Hello WebAssembly!
Setting Up the Development Environment
Creating the Project
Creating the Frontend
Resizing Images with WebAssembly
Loading an Image File Onto the <canvas>
Passing the Image to Wasm
Writing the Whole Frontend in Rust
Setting Up Yew
A Hello World Example
Reimplement the Image-Processing Frontend with Yew
Other Alternatives
Index
About the Author
Shing Lyu
is a software engineer who is passionate
about open source software. He’s
worked with Rust professionally at
Mozilla, on the Firefox (Gecko) and Servo
browser engine project. Currently, he
works at DAZN, a sports-streaming
platform as a backend developer, with a
focus on AWS and serverless technology.
Shing has worked for many world-
famous brands like Mozilla,
Booking.com, and Intel. He is also active
in the open source community. As one of
the founders of the Taiwan Rust
community, he loves to share his enthusiasm for Rust with others.
About the Technical Reviewer
Carlo Milanesi
is a professional software developer and
expert in C++, graphics programming,
and GUI design. He graduated from the
State University of Milan and has worked
in the financial and CAD/CAM software
industries. He enjoys writing software in
Smalltalk and Rust.
© Shing Lyu 2021
S. Lyu, Practical Rust Web Projects
https://doi.org/10.1007/978-1-4842-6589-5_1

1. Rust in the Web World


Shing Lyu1
(1) Amsterdam, The Netherlands

If you are reading this book, you are probably as excited about Rust as I
am. Since the first stable release in 2015, Rust has come a long way in
terms of features and stability. Developers around the world are
fascinated about how Rust can combine features that were once
thought of as unavoidable trade-offs: performance with memory safety,
low-level control with productivity. Despite its infamous steep learning
curve, Rust has gained popularity over the years. It was named the
“most loved programming language” in a StackOverflow survey four
years in a row, from 2016 to 2020. Many big companies and
organizations—like Facebook, Microsoft, Dropbox, and npm—have
started using Rust in production.
How are people using Rust? If we take a look at crates.io, the official
Rust crates (libraries) registry, there are over 28,900 crates and over a
billion downloads. There are 47 categories on crates.io,1 ranging from
the command-line interfaces, cryptography, databases, games,
operating systems, and many more. But one of the most exciting fields
is web programming. Many people spend most of their waking time
online. There are roughly 1.5 billion websites on the World Wide Web.
So it’s natural that Rusticians are looking for ways to build websites and
web applications with Rust.

Note If you look for web development job postings nowadays,


you’ll come across the terms “frontend developer,” “backend
developer,” and “full-stack developer.” A frontend developer builds
things that run in the frontend; usually, this is the end user’s browser.
A backend developer builds things that run in the backend, usually
the server that acts as an HTTP server, WebSocket server, or other
protocols. A full-stack developer works on both.
The typical technologies these roles need to work with include:
Frontend: HTML, JavaScript, CSS, and WebAssembly (see
Chapter 6).
Backend: Web framework, REST API, database, WebSocket (see
Chapters 2 to 5).

This book focuses on Rust for web applications. Since the backend is
usually more language-agnostic, most of the chapters will be about the
backend. We’ll follow the history of how the backend evolves, starting
with server-side-rendered websites. Then we’ll develop REST APIs and
WebSocket servers. Finally, we’ll deploy this API onto the cloud using
serverless technologies. That doesn’t mean Rust can’t be used in the
frontend. With WebAssembly now available in most mainstream
browsers, we can compile our Rust code to WebAssembly and run it in
browsers. This unlocks a lot of potential for highly-performant
applications in the frontend. After reading this book, you should have a
good grasp of how to build a full-stack application in Rust.
Who Is This Book For?
This book will be useful for:
People who already know basic Rust syntax, but want to learn how to
build web applications in Rust.
People who are considering using Rust to build production-ready
systems.
People who have experience in web development and want to see
how Rust can fit in.
If you already know how to code Rust, this book will help you learn
web development in Rust. You have probably built a few command-line
games and tools while reading The Rust Book2 or other introductory
courses. The final project in The Rust Book teaches you to build a toy
web server. But how do you build production-ready web services? This
book will introduce you to web frameworks and crates in order to apply
your Rust skill on the web. If you already know web development in
other languages (e.g., Node.js, Java, Go, Python, Ruby, etc.), this book
will help you see how Rust makes it more secure and ergonomic to
building web applications.
Who Is This Book Not For?
This book might not be that useful for:
People who want to learn the Rust programming language itself.
People who want to learn the fundamentals of web development.
This book is not a course on the Rust programming language itself,
nor is it trying to teach Rust’s syntax via examples. We’ll focus on how
to apply Rust to web applications, assuming you already know Rust’s
syntax and its language features. There are many excellent books on
Rust, like The Rust Programming Language by Steve Klabnik and Carol
Nichols. You can also find online books, interactive tutorials, and videos
on the Learn Rust section of the official website.3 I try to explain the
fundamental web development concepts before implementing them.
But this book does not focus on teaching general web development
concepts through Rust, so the explanations will be brief. You’ll get more
out of this book if you already have some experience with web
development in other languages.

Criteria for Selecting Libraries


Rust is a relatively young language for web development. Therefore,
although there are many frameworks and libraries out there, it was
hard to decide which one to include in this book. The following sections
cover the criteria for selecting which framework or library to use in this
book.

Pure-Rust
I try to find libraries that are built purely in Rust. Rust’s FFI (foreign
function interface) allows you to call existing C libraries (and many
other languages) from Rust. Therefore, the easiest way to build Rust
applications quickly is to leverage existing libraries in other languages.
These libraries are usually designed with other languages in mind, so
wrapping them in Rust results in a weird and not idiomatic Rust API. So
if there are pure Rust libraries, I tend to choose those.

Maturity
However, not every pure Rust library is mature. Because many Rust
libraries are built from a clean slate, the developers tried to experiment
with the latest technology, but that might mean that the architecture
and API design is very fragile and changes frequently. Some of the
libraries showed great potential in their early days, but then the
development slowed down, and the projects eventually went into
maintenance mode or were even abandoned. We aim to build useful
software rather than experiment with exciting technologies and then
throw the code away. Therefore, we need to be pragmatic and choose a
library that is mature enough and uses widely-accepted design
patterns.

Popularity
If two or more candidates meet the previous criteria, I choose the most
popular one. Popularity is based on a combination of factors, including:
Number of downloads on crates.io
Pace of development and release
Discussions on issue trackers and discussion forums
Media coverage
Although popularity is not a guarantee of success, a popular project
is more likely to have a big enough community that supports it and
keeps it alive. This can help us find a library that has the most potential
to stick around longer in the future. You are also more likely to get
support and answers online.
For backend-heavy chapters, I try to use plain JavaScript, HTML, and
CSS, without additional frameworks like React.js, jQuery, or SCSS. This
helps to keep the focus on the backend and avoid the need to learn a
new framework that might be out of fashion soon.

How To Use This Book


The chapters in this book do not strictly depend on each other.
However, the example website in Chapters 2, 3, and 5 has the same
functionality, but is built with different technologies. Reading these
chapters in sequence will help you compare the pros and cons of each
approach. Chapters 4 and 6 are relatively independent of the other
chapters, so you can read them in any order.

Chapter Overview
In Chapter 2, I started with the traditional form of website architecture:
server-side rendered websites. You’ll learn how to use the actix-web
framework to set up a web server. Then, you’ll learn how to render
dynamic HTML pages using a template engine. To make the website
even more interactive, you’ll set up a database and render the website
using the data in that database. Finally, you’ll learn how to build a page
that adds new information to the database.
In Chapter 3, you’ll learn about a different website architecture that
is popular among modern websites: using JavaScript to render dynamic
data provided by a REST API. You’ll learn how to return JSON-formatted
data from the API. I also introduce other commonly used techniques
that didn’t fit into the previous chapter: input validation, error
handling, logging, and enabling HTTPS.
In Chapter 4, you’ll learn about a different protocol, WebSocket, that
can help you build real-time, bidirectional communication. I’ll show you
how to use WebSocket to push real-time notifications to the client.
Then you’ll build a full-duplex chat application.
In Chapter 5, you’ll learn how to build a REST API using AWS
Lambda and other serverless services. You’ll learn how to use the AWS
SDK to communicate with the DynamoDB database. You’ll also learn
how to deploy the frontend to AWS S3 and connect it to the REST API.
After finishing this chapter, you’ll have a fully-functional website on the
Internet without worrying about server maintenance.
In Chapter 6, I change the focus to the frontend. First, you’ll learn
how to compile your Rust code to WebAssembly (Wasm) so it can run
in browsers. You’ll build a JavaScript-Wasm hybrid image-processing
application in the browser so you can leverage Wasm’s high
performance. Then you’ll learn how to use a frontend framework to
build the whole frontend application using only Rust.

Source Code
All the source code for this book is available on GitHub at
https://github.com/apress/practical-rust-web-
projects. The source code is also accessible via the Download Source
Code button located at
https://www.apress.com/us/book/9781484265888.
When I include source code in the book, I only include the part that
is relevant to the point being discussed. The irrelevant parts are
omitted with comments like this:

// ...

Therefore, not all code examples can be compiled successfully. To


check the fully working examples, use the source code on GitHub.
All the examples are developed and tested on a Linux (Ubuntu
16.04) machine. The Rust version is stable-x86_64-unknown-
linux-gnu unchanged - rustc 1.44.1 (c7087fe00
2020-06-17).

Footnotes
1 https://crates.io/categories

2 https://doc.rust-lang.org/book/

3 https://www.rust-lang.org/learn
© Shing Lyu 2021
S. Lyu, Practical Rust Web Projects
https://doi.org/10.1007/978-1-4842-6589-5_2

2. Developing Websites
Shing Lyu1
(1) Amsterdam, The Netherlands

There is no denying that the web is one of the most popular platforms on
Earth now. There are over 1.7 billion websites on the World Wide Web. And if
you look at job boards for developers, web developers take up a large
proportion of it. There are already many established programming languages
for building the backend: Java, PHP, Python, Ruby, Node.js, and Go, just to
name a few. But Rust fits perfectly into the web domain because of a few
reasons:
Security
Concurrency
Low-level control
Web security has been a big headache for everyone involved in building
websites. But many vulnerabilities are due to bugs that can be caught by
Rust’s type checker and borrow checker. By having Rust check your code at
compile-time, you can prevent many runtime vulnerabilities that might go
undetected and be exploited when you least expect them to.
Nowadays, popular websites need to handle a large number of concurrent
users. Therefore, concurrency and efficiency are crucial for web server
software to handle more and more users. Rust’s focus on ”fearless
concurrency” makes it easier to handle a large number of concurrent
requests. The relatively new async/await syntax also makes async I/O
more accessible to the average Rust programmer. On top of thread safety and
async I/O, Rust’s ability to control low-level CPU and memory opens up the
possibility of squeezing more performance out of the server hardware.
Rust also has a vibrant ecosystem that provides both high-level
frameworks and low-level control over networking, database access, and
type-safe templating. We are going to explore how to build a server-side
rendered website in Rust.
What Are You Building?
In the game Pokémon, there is a device called Pokédex, which is an
index/encyclopedia of all Pokémons. In this chapter, we are going to build a
cat index called Catdex. The Catdex should have the following features:
Show a list of cats. This demonstrates how to render a list of things using a
server-side template.
Read the cats from a database. This demonstrates how to set up a database
with Object Relational Mapping (ORM).
Use a form to add a new cat to the database. This demonstrates how to send
POST requests and insert the data into a database.
Show a specific detail page for each cat. This demonstrates how to read
parameters from the URL path.
There are many ways to architect a website. One important distinction is
server-side rendering versus client-side rendering. In server-side rendering,
the HTML is generated on the server-side when a request comes in. In client-
side rendering, the page is mostly generated in the browser by client-side
frameworks like React, Vue, or Angular. The client-side framework then makes
an HTTP request to a backend API to retrieve data that should go on the page.
We’ll talk about RESTful APIs in Chapter 3 and client-side rendering in
Chapter 6. But in this chapter, we’ll focus on server-side rendering.
We’ll be using the actix-web framework as our web framework.
actix-web doesn’t dictate which template engine and database you should
use. We’ll be choosing the Handlebar for templating. For the database, we’ll be
using a PostgreSQL database through the Diesel ORM and r2d2 connection
pool.

Hello World!
To start an Actix application, you first need to create an empty project with
cargo, then add actix-web as dependencies. Run the following command
in your terminal:

cargo new hello-world


cd hello-world
cargo install cargo-edit
cargo add actix-web
Tip The cargo-edit extension will add a new command called cargo
add. This helps you add new cargo dependencies without manually editing
Cargo.toml.

Once cargo adds the dependencies, your Cargo.toml should look like
Listing 2-1.

[package]
name = "hello-world"
# ...

[dependencies]
actix-web = "3"
Listing 2-1 Cargo.toml for a Hello World Actix Application

Now, open the src/main.rs file and copy Listing 2-2 into it.

use actix_web::{web, App, HttpResponse, HttpServer,


Responder};

async fn hello() -> impl Responder {


HttpResponse::Ok().body("Hello world")
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
println!("Listening on port 8080");
HttpServer::new(|| {
App::new().route("/hello",
web::get().to(hello))
})
.bind("127.0.0.1:8080")?
.run()
.await
}
Listing 2-2 Hello World Actix Application

The core of Listing 2-2 is the App builder in the main() function. The App
struct uses the builder pattern to build a new application instance. When you
call route(), you specify which handler should be called when the user
visits a specific path under the website. In this example, when the user visits
/hello with an HTTP GET method (web::get()), it invokes the hello()
handler.
The hello() handler is an async function that returns something that
implements a Responder trait. A Responder is something that can be
converted into an HTTP response. It’s implemented on common types like
&str, String, and u8 arrays. In this simple example, we respond with an
HttpResponse::Ok() (i.e., status code 200) and a string body “Hello
world”.
An HttpServer wraps the App. The HttpServer handles the incoming
requests and passes them to the App. We bind() an address
(127.0.0.1:8080) to the server so it will listen on the specific IP and port.
Finally, we call run() to start the server and await on it. Notice that the
HttpServer doesn’t take an App instance. Instead, it takes an App factory,
which is a simple closure that creates a new App instance every time. This is
because the HttpServer will create multiple worker threads, each running
one instance of the App. This way, we can better utilize multiple CPU cores
and achieve higher scalability.
You might also notice that the main() function is annotated with an #
[actix_web::main] attribute macro. This attribute tells Actix to execute
the main() function in a special runtime called actix-rt, which is built on
top of the popular Tokio1 runtime.

Note You might be aware that the functions in the “hello world” program
all have async in front, and you need to put .await after them when
calling. This is an important language feature that makes it possible to
build highly-efficient web servers. When you call a normal (i.e., blocking)
function, the whole thread blocks and waits for the function to return. But
if the function is async, it immediately returns a Future instead of
blocking. When you .await on that Future, the program asynchronously
waits for it to complete, which allows other tasks on the same thread to
make progress.
This is extremely important when building web servers. A modern web
server usually needs to handle a large number of clients at the same time. If
the server processes only one thing at a time and blocks whenever it’s
waiting for I/O (input/output) like in a socket communication, it can only
serve one client at a time. One way to solve this is to use an operating
system (OS) construct called a process . A process is an instance of your
server program, and the OS allows you to start multiple processes. This
way, you can have one process handling one client. But processes have a
high overhead so this won’t scale very well.
Another alternative is to use several threads. A thread is a series of
instructions (and their surrounding execution context) that can run
independently of other threads. Threads and processes are implemented
differently in each operating system, but in general, a thread is a
component of a process. Threads in the same process share some common
resources like memory space, so they have a lower overhead to run than a
process. Therefore, we can run more threads than processes on the same
hardware, thus serving more clients.
However, because network I/O is much slower than CPU, most of the
time, the threads are sitting idle, waiting for network I/O. Although threads
are lighter than processes, they still have some overhead. By using
async/await, we can potentially serve multiple clients per thread. When the
server is waiting for a client’s network I/O, it can yield the execution to
other clients served by the same thread.
This is an overly simplified explanation of async/await and how it can
help web development. If you want to learn more about the history and
rationale of Rust’s async/await design, watch Steve Klabnik’s talk called
“Rust’s Journey to Async/Await.”2 You can also read the Asynchronous
Programming in Rust book3.

To run this example, simply run the cargo run command in the terminal
under this project directory. A web server will start on 127.0.0.1:8080, as
we specified. Once the server is running, open a web browser and go to
http://127.0.0.1:8080/hello, and you’ll see the “Hello world” text
(Figure 2-1).

Figure 2-1 Web server responding with “hello world”

Serving Static Files


In the “hello world” example, we respond with a simple string. But most web
pages are built with HTML (HyperText Markup Language). You could write
HTML as a very long string in the Rust code and serve them that way, but it
would be hard to manage. A more common way is to store the HTML as
separate .html files and serve them with the web server. An HTML file
usually also includes other CSS, JavaScript, or media files (e.g., images or
videos). Actix allows you to serve all these files easily without explicitly
writing code to read the file from disk.
First, let’s create the files that will be served. Let’s create a new project
named catdex and add the dependencies. Then we’ll create a folder called
static, which will hold the static files. Under ./static/, we’ll also create
a css folder for CSS and an image folder for images:

cargo new catdex


cd catdex
cargo add actix-web actix-files
mkdir static
mkdir static/css
mkdir static/image

You can put some cat images (in JPEG format) in the static/image
folder. We also need to create an index.css file in static/css that will be
used by static/index.html.

.
+-- Cargo.lock
+-- Cargo.toml
+-- src
| +-- main.rs
+-- static
+-- css
| +-- index.css
+-- image
| +-- british-short-hair.jpg
| +-- persian.jpg
| +-- ragdoll.jpg
+-- index.html

Next, create a file called static/index.html and paste the HTML code
in Listing 2-3 into it.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Catdex</title>
</head>
<body>
<h1>Catdex</h1>
</body>
</html>
Listing 2-3 A Minimal Static HTML
To serve this HTML file, you need to install the actix-files crate. We
already did this in the previous cargo add step. Next, let’s paste the
following code into src/main.rs (Listing 2-4).

use actix_files::{NamedFile};
use actix_web::{web, App, HttpServer, Result};

async fn index() -> Result<NamedFile> {


Ok(NamedFile::open("./static/index.html")?)
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
println!("Listening on port 8080");
HttpServer::new(|| {
App::new()
.route("/", web::get().to(index))
})
.bind("127.0.0.1:8080")?
.run()
.await
Listing 2-4 Serving the index.html File

The code is almost the same as the “hello world” example, except:
The path is now / (root)
The handler, named index(), now returns a NamedFile
The NamedFile::open() function opens the file in read-only mode.
Because NamedFile implements Responder, we can return it directly in
the handler. It’s wrapped in a Result just in case the file reading failed.
If you run cargo run in a terminal, a server should start on port 8080.
Then you can open a browser and go to http://127.0.0.1:8080/ and
see the contents of index.html being rendered.
Since we are building a cat encyclopedia, we need to add some cat
pictures. You can add the following HTML to static/index.html (Listing
2-5).

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Catdex</title>
<link rel="stylesheet" href="static/css/index.css"
type="text/css">
</head>
<body>
<h1>Catdex</h1>
<section class="cats">
<article class="cat">
<h3>British short hair</h3>
<img src="static/image/british-short-
hair.jpg" />
</article>
<article class="cat">
<h3>Persian</h3>
<img src="static/image/persian.jpg" />
</article>
<article class="cat">
<h3>Ragdoll</h3>
<img src="static/image/ragdoll.jpg" />
</article>
</section>
</body>
</html>
)
Listing 2-5 index.html with External Image and CSS

This file now imports four extra resources:


static/css/index.css
static/image/british-short-hair.jpg
static/image/persian.jpg
static/image/ragdoll.jpg
It’s not scalable to write a custom path and handler for each individual
resource. So instead, we need to tell Actix to serve every file under the
static folder automatically. To achieve this, you can use the actix-
file::Files service, which handles static files for you with some simple
configuration. You need to register this service when you create the App. Add
the code in Listing 2-6 to your src/main.rs.

use actix_files::{Files, NamedFile};


use actix_web::{web, App, HttpServer, Result};

async fn index() -> Result<NamedFile> {


Ok(NamedFile::open("./static/index.html")?)
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
println!("Listening on port 8080");
HttpServer::new(|| {
App::new()
.service(
Files::new("/static", "static")
.show_files_listing(),
)
.route("/", web::get().to(index))
})
.bind("127.0.0.1:8080")?
.run()
.await
}
Listing 2-6 Using the Files Service to Serve Static Files

In the App factory, you can use the .service() function to attach a
service to the application. The Files service will serve the static files in a
folder (the second parameter, static) under a certain URL path (the first
parameter, /static). You might notice that we also enabled
.show_files_listing(). When this feature is turned on, you’ll see an
HTML list of all the files under the folder if you open the /static path
(Figure 2-2). This is handy for debugging, but should be turned off in
production to avoid security vulnerabilities4.

Figure 2-2 File listing generated by .show_files_listing()


If you run cargo run and visit http://localhost:8080/ in a
browser, you’ll see the Catdex now has images (Figure 2-3).

Figure 2-3 Catdex with hard-coded images


Rendering Dynamic Templates
You might find that there is a pattern in Listing 2-5: each cat entry is an
<article> containing a <h3> and an <img>. The only differences are the
name and the image path. As you can imagine, when the number of cats goes
up, this approach is not very salable. You end up writing many duplicated
code. We can reuse the HTML structure by using a template. In a template, we
define the HTML structure but fill in the image name and image path
programmatically. Another side-benefit is that you can separate the
presentation from the data. The HTML structure that defines how the page
should look like is stored in the template, so you can focus on processing the
data in Rust.
There are many template engines and syntax available. We choose
Handlebars because of its popularity on crates.io. Handlebars was a JavaScript
template engine, and it was ported to Rust. To install Handlebars, add the
following crates to your Cargo.toml file (Listing 2-7).

[package]
name = "catdex"
Listing 2-7 Cargo.toml for Handlebars

# ...

[dependencies]
# ...
serde_json = "1.0.53"
handlebars = { version = "3.0.1", features =
["dir_source"] }

Then you can turn the static/index.html file into a template, as


shown in Listing 2-8.

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>{{project_name}}</title>
<link rel="stylesheet" href="static/css/index.css"
type="text/css">
</head>
<body>
<h1>{{project_name}}</h1>
<section class="cats">
{{#each cats}}
<article class="cat">
<h3>{{this.name}}</h3>
<img src="{{this.image_path}}" />
</article>
{{/each}}
</section>
</body>
</html>
Listing 2-8 Handlebars Template for Catdex
The variables wrapped by {{}} are variables that we’ll provide from the
Rust code later. Notice that there is a {{#each}}...{{/each}} block. This
#each block loops over an array and renders each element once using the
template.
To use this template in the Actix code, you need to paste the code in Listing
2-9 into src/main.rs.

use actix_files::Files;
use actix_web::{web, App, HttpResponse, HttpServer};

use handlebars::Handlebars;

async fn index(hb: web::Data<Handlebars<'_>>) ->


HttpResponse {
let data = json!({
"project_name": "Catdex",
"cats": [
{
"name": "British short hair",
"image_path": "/static/image/british-
short-hair.jpg"
},
{
"name": "Persian",
"image_path":
"/static/image/persian.jpg"
},
Another Random Scribd Document
with Unrelated Content
seemed charged: it simply legitimated them. A romantic adventure
on so classical a basis would assuredly hurt no one.
"I should like a walk very much," said Ludlow; "a walk with a halt
at the end of it."
"Well, if you will consent to a short halt at the beginning of it," said
Adela, "I will be with you in a very few minutes." When she returned
in her little hat and shawl, she found her friend seated on the
veranda steps. He arose and gave her a card.
"I have been requested, in your absence, to hand you this," he
said.
Adela read with some compunction the name of Mr. Madison
Perkins.
"Has he been here?" she asked. "Why didn't he come in?"
"I told him you were not at home. If it wasn't true then, it was
going to be true so soon that the interval was hardly worth taking
account of. He addressed himself to me, as I seemed from my
position to be quite at home here; but I confess he looked at me as if
he doubted my word. He hesitated as to whether he should confide
his name to me, or whether he should confide it in that shape to the
entry table. I think he wished to show me that he suspected my
veracity, for he was making rather grimly for the table when I, fearing
that once inside the house he might encounter the living truth,
informed him in the most good-humored tone possible that I would
take charge of his little tribute.
"I think, Mr. Ludlow, that you are a strangely unscrupulous man.
How did you know that Mr. Perkins's business was not urgent?"
"I didn't know it. But I knew it could be no more urgent than mine.
Depend upon it, Miss Moore, you have no case against me. I only
pretend to be a man; to have admitted that charming young
gentleman would have been heroic."
Adela was familiar with a sequestered spot, in the very heart of
the fields, as it seemed to her, to which she now proposed to
conduct her friend. The point was to select a goal neither too distant
nor too near, and to adopt a pace neither too rapid nor too slow. But
although Adela's happy valley was a good two miles away, and they
had measured the interval with the very minimum of speed, yet most
sudden seemed their arrival at the stile over which Adela was used
to strike into the meadows. Once on the road, she felt a precipitate
conviction that there could be no evil in an adventure so essentially
wholesome as that to which she had lent herself, and that there
could be no guile in a spirit so deeply sensitive to the sacred
influences of Nature, and to the melancholy aspect of incipient
Autumn as that of her companion. A man with an unaffected relish
for small children is a man to inspire young women with a generous
confidence; and so, in a lesser degree, a man with a genuine feeling
for the simple beauties of a common New England landscape may
not unreasonably be accepted by the daughters of the scene as a
person worthy of their esteem. Adela was a great observer of the
clouds, the trees and the streams, the sounds and colors, the
echoes and reflections native to her adopted home; and she
experienced an honest joy at the sight of Ludlow's keen appreciation
of these modest facts. His enjoyment of them, deep as it was,
however, had to struggle against that sensuous depression natural to
a man who has spent the Summer in a close and fetid laboratory in
the heart of a great city, and against a sensation of a less material
color—the feeling that Adela was a delightful girl. Still, naturally a
great talker, he celebrated his impressions in a generous flow of
good-humored eloquence. Adela resolved within herself that he was
decidedly a companion for the open air. He was a man to make use,
even to abuse, of the wide horizon and the high ceiling of Nature.
The freedom of his gestures, the sonority of his voice, the keenness
of his vision, the general vivacity of his manners, seemed to
necessitate and to justify a universal absence of barriers. They
crossed the stile, and waded through the long grass of several
successive meadows, until the ground began to rise, the stony
surfaces to crop through the turf, when, after a short ascent, they
reached a broad plateau, covered with boulders and shrubs, which
lost itself on one side in a short, steep cliff, whence fields and
marshes stretched down to the opposite river; and on the other, in
scattered clumps of pine and maple, which gradually thickened and
multiplied, until the horizon in that quarter was blue with a long line of
woods. Here was both sun and shade—the unobstructed sky, or the
whispering dome of a circle of pines. Adela led the way to a sunny
seat among the rocks, which commanded the course of the river,
and where a cluster of trees would lend an admonitory undertone to
their conversation.
Before long, however, its muffled eloquence became rather
importunate, and Adela remarked upon the essential melancholy of
the phenomenon.
"It has always seemed to me," rejoined Ludlow, "that the wind in
the pines expresses tolerably well man's sense of a coming change,
simply as a change."
"Perhaps it does," said Adela. "The pines are forever rustling, and
men are forever changing."
"Yes, but they can only be said to express it when there is some
one there to hear them; and more especially some one in whose life
a change is, to his own knowledge, going to take place. Then they
are quite prophetic. Don't you know Longfellow says so?"
"Yes, I know Longfellow says so. But you seem to speak from
your own feeling."
"I do."
"Is there a change pending in your life?"
"Yes, rather an important one."
"I believe that's what men say when they are going to be married,"
said Adela.
"I'm going to be divorced, rather. I'm going to Europe."
"Indeed! soon?"
"To-morrow," said Ludlow, after an instant's pause.
"Oh!" said Adela. "How I envy you!"
Ludlow, who sat looking over the cliff and tossing stones down
into the plain, observed a certain inequality in the tone of his
companion's two exclamations. The first was nature, the second art.
He turned his eyes upon her, but she had turned hers away upon the
distance. Then, for a moment, he retreated within himself and
thought. He rapidly surveyed his position. Here was he, Tom Ludlow,
a hard-headed son of toil, without fortune, without credit, without
antecedents, whose lot was cast exclusively with vulgar males, and
who had never had a mother, a sister nor a well-bred sweetheart to
pitch his voice for the feminine tympanum; who had seldom come
nearer an indubitable young lady than, in a favoring crowd, to
receive a mechanical "thank you" (as if he were a policeman), for
some ingeniously provoked service; here he found himself up to his
neck in a sudden pastoral with the most ladyish young woman in the
land. That it was in him to enjoy the society of such a woman
(provided, of course, she were not a fool), he very well knew; but he
had not yet suspected that it was possible for him (in the midst of
more serious cares) to obtain it. Was he now to infer that this final
gift was his—the gift of pleasing women who were worth the
pleasing? The inference was at least logical. He had made a good
impression. Why else should a modest and discerning girl have so
speedily granted him her favor? It was with a little thrill of satisfaction
that Ludlow reflected upon the directness of his course. "It all comes
back," he said to himself, "to my old theory, that a process can't be
too simple. I used no arts. In such an enterprise I shouldn't have
known where to begin. It was my ignorance of the regulation method
that served me. Women like a gentleman, of course; but they like a
man better." It was the little touch of nature he had discerned in
Adela's tone that had set him thinking; but as compared with the
frankness of his own attitude it betrayed after all no undue emotion.
Ludlow had accepted the fact of his adaptability to the idle mood of a
cultivated woman in a thoroughly rational spirit, and he was not now
tempted to exaggerate its bearings. He was not the man to be
intoxicated by success—this or any other. "If Miss Moore," he
pursued, "is so wise—or so foolish—as to like me half an hour for
what I am, she is welcome. Assuredly," he added, as he gazed at her
intelligent profile, "she will not like me for what I am not." It needs a
woman, however, far more intelligent than (thank heaven!) most
women are—more intelligent, certainly, than Adela was—to guard
her happiness against a strong man's consistent assumption of her
intelligence; and doubtless it was from a sense of this general truth,
as Ludlow still gazed, he felt an emotion of manly tenderness. "I
wouldn't offend her for the world," he thought. Just then, Adela,
conscious of his gaze, looked about; and before he knew it, Ludlow
had repeated aloud, "Miss Moore, I wouldn't offend you for the
world."
Adela glanced at him for a moment with a little flush that subsided
into a smile. "To what dreadful injury is that the prelude?" she asked.
"It's the prelude to nothing. It refers to the past—to any possible
displeasure I may have caused you."
"Your scruples are unnecessary, Mr. Ludlow. If you had given me
offence, I should not have left you to apologize for it. I should not
have left the matter to occur to you as you sat dreaming charitably in
the sun."
"What would you have done?"
"Done? nothing. You don't imagine I would have rebuked you—or
snubbed you—or answered you back, I take it. I would have left
undone—what, I can't tell you. Ask yourself what I have done. I'm
sure I hardly know myself," said Adela, with some intensity. "At all
events, here I am sitting with you in the fields, as if you were a friend
of years. Why do you speak of offence?" And Adela (an uncommon
accident with her) lost command of her voice, which trembled ever
so slightly. "What an odd thought! why should you offend me? Do I
invite it?" Her color had deepened again, and her eyes brightened.
She had forgotten herself, and before speaking had not, as was her
wont, sought counsel of that staunch conservative, her taste. She
had spoken from a full heart—a heart which had been filling rapidly
since the outset of their walk with a feeling almost passionate in its
quality, and which that little blast of prose which had brought her
Ludlow's announcement of his departure, had caused to overflow.
The reader may give this feeling such a name as he pleases. We will
content ourselves with saying that Adela had played with fire so
effectually that she had been scorched. The slight vehemence of the
speech just quoted had covered her sensation of pain.
"You pull one up rather short, Miss Moore," said Ludlow. "A man
says the best he can."
Adela made no reply. For a moment she hung her head. Was she
to cry out because she was hurt? Was she to introduce her injured
soul as an impertinent third into the company? No! Here our
reserved and contemplative heroine is herself again. Her part was
still to be the perfect young lady. For our own part, we can imagine
no figure more bewitching than that of the perfect young lady under
these circumstances; and if Adela had been the most accomplished
coquette in the world she could not have assumed a more becoming
expression than the air of languid equanimity which now covered her
features. But having paid this generous homage to propriety, she felt
free to suffer. Raising her eyes from the ground, she abruptly
addressed her companion with this injunction:
"Mr. Ludlow," said she, "tell me something about yourself."
Ludlow burst into a laugh. "What shall I tell you?"
"Everything."
"Everything? Excuse me, I'm not such a fool. But do you know
that's a delicious request you make? I suppose I ought to blush and
hesitate; but I never yet blushed or hesitated in the right place."
"Very good. There is one fact. Continue. Begin at the beginning."
"Well, let me see. My name you know. I'm twenty-eight years old."
"That's the end," said Adela.
"But you don't want the history of my babyhood, I take it. I imagine
that I was a very big, noisy and ugly baby: what's called a 'splendid
infant.' My parents were poor, and, of course, honest. They belonged
to a very different set—or 'sphere', I suppose you call it—from any
you probably know. They were working people. My father was a
chemist in a small way, and I fancy my mother was not above using
her hands to turn a penny. But although I don't remember her, I am
sure she was a good, sound woman; I feel her occasionally in my
own sinews. I myself have been at work all my life, and a very good
worker I am, let me tell you. I'm not patient, as I imagine your brother
to be—although I have more patience than you might suppose—but
I'm plucky. If you think I'm over-egotistical, remember 'twas you
began it. I don't know whether I'm clever, and I don't much care; that
word is used only by unpractical people. But I'm clear-headed, and
inquisitive, and enthusiastic. That's as far as I can describe myself. I
don't know anything about my character. I simply suspect I'm a pretty
good fellow. I don't know whether I'm grave or gay, lively or severe. I
don't know whether I'm high-tempered or low-tempered. I don't
believe I'm 'high-toned.' I fancy I'm good-natured enough, inasmuch
as I'm not nervous. I should not be at all surprised to discover I was
prodigiously conceited; but I'm afraid the discovery wouldn't cut me
down, much. I'm desperately hard to snub, I know. Oh, you would
think me a great brute if you knew me. I should hesitate to say
whether I am of a loving turn. I know I'm desperately tired of a
number of persons who are very fond of me; I'm afraid I'm
ungrateful. Of course as a man speaking to a woman, there's
nothing for it but to say I'm selfish; but I hate to talk about such windy
abstractions. In the way of positive facts: I'm not educated. I know no
Greek and very little Latin. But I can honestly say that first and last I
have read a great many books—and, thank God, I have a memory!
And I have some tastes, too. I'm very fond of music. I have a good
old voice of my own: that I can't help knowing; and I'm not one to be
bullied about pictures. Is that enough? I'm conscious of an utter
inability to say anything to the point. To put myself in a nutshell, I
suppose I'm simply a working man; I have his virtues and I have his
defects. I'm a very common fellow."
"Do you call yourself a very common fellow because you really
believe yourself to be one, or because you are weakly tempted to
disfigure your rather flattering catalogue with a great final blot?"
"I'm sure I don't know. You show more subtlety in that one
question than I have shown in my whole string of affirmations. You
women are strong on asking witty questions. Seriously, I believe I am
a common fellow. I wouldn't make the admission to every one
though. But to you, Miss Moore, who sit there under your parasol as
impartial as the Muse of History, to you I own the truth. I'm no man of
genius. There is something I miss; some final distinction I lack; you
may call it what you please. Perhaps it's humility. Perhaps you can
find it in Ruskin, somewhere. Perhaps it's patience—perhaps it's
imagination. I'm vulgar, Miss Moore. I'm the vulgar son of vulgar
people. I use the word, of course, in its strictest sense. So much I
grant you at the outset, and then I walk ahead."
"Have you any sisters?"
"Not a sister; and no brothers, nor cousins, nor uncles, nor aunts."
"And you sail for Europe to-morrow?"
"To-morrow, at ten o'clock."
"To be away how long?"
"As long as I possibly can. Five years if possible."
"What do you expect to do in those five years?"
"Study."
"Nothing but study?"
"It will all come back to that, I fancy. I hope to enjoy myself
reasonably, and to look at the world as I go. But I must not waste
time; I'm growing old."
"Where are you going?"
"To Berlin. I wanted to get letters from your brother."
"Have you money? Are you well off?"
"Well off? Not I, no. I'm poor. I travel on a little money that has just
come to me from an unexpected quarter: an old debt owing my
father. It will take me to Germany and keep me for six months. After
that I shall work my way."
"Are you happy? Are you contented?"
"Just now I'm pretty comfortable, thank you."
"But will you be so when you get to Berlin?"
"I don't promise to be contented; but I'm pretty sure to be happy."
"Well!" said Adela, "I sincerely hope you may be."
"Amen!" said Ludlow.
Of what more was said at this moment, no record may be given.
The reader has been put into possession of the key of our friends'
conversation; it is only needful to say that substantially upon this key,
it was prolonged for half an hour more. As the minutes elapsed,
Adela found herself drifting further and further away from her
anchorage. When at last she compelled herself to consult her watch,
and remind her companion that there remained but just time enough
for them to reach home, in anticipation of her brother's arrival, she
knew that she was rapidly floating seaward. As she descended the
hill at her companion's side, she felt herself suddenly thrilled by an
acute temptation. Her first instinct was to close her eyes upon it, in
the trust that when she opened them again it would have vanished;
but she found that it was not to be so uncompromisingly dismissed. It
importuned her so effectually, that before she had walked a mile
homeward, she had succumbed to it, or had at least given it the
pledge of that quickening of the heart which accompanies a bold
resolution. This little sacrifice allowed her no breath for idle words,
and she accordingly advanced with a bent and listening head.
Ludlow marched along, with no apparent diminution of his habitual
buoyancy of mien, talking as fast and as loud as at the outset. He
adventured a prophecy that Mr. Moore would not have returned, and
charged Adela with a humorous message of regrets. Adela had
begun by wondering whether the approach of their separation had
wrought within him any sentimental depression at all commensurate
with her own, with that which sealed her lips and weighed upon her
heart; and now she was debating as to whether his express
declaration that he felt "awfully blue" ought necessarily to remove
her doubts. Ludlow followed up this declaration with a very pretty
review of the morning, and a sober valedictory which, whether
intensely felt or not, struck Adela as at least nobly bare of flimsy
compliments. He might be a common fellow—but he was certainly a
very uncommon one. When they reached the garden gate, it was
with a fluttering heart that Adela scanned the premises for some
accidental sign of her brothers presence. She felt that there would be
an especial fitness in his not having returned. She led the way in.
The hall table was bare of his hat and overcoat. The only object it
displayed was Mr. Perkins's card, which Adela had deposited there
on her exit. All that was represented by that little white ticket seemed
a thousand miles away. Finally, Mr. Moore's absence from his study
was conclusive against his return.
As Adela went back thence into the drawing-room, she simply
shook her head at Ludlow, who was standing before the fire-place;
and as she did so, she caught her reflection in the mantel-glass.
"Verily," she said to herself, "I have travelled far." She had pretty well
unlearned the repose of the Veres of Vere. But she was to break with
it still more completely. It was with a singular hardihood that she
prepared to redeem the little pledge which had been extorted from
her on her way home. She felt that there was no trial to which her
generosity might now be called which she would not hail with
enthusiasm. Unfortunately, her generosity was not likely to be
challenged; although she nevertheless had the satisfaction of
assuring herself at this moment that, like the mercy of the Lord, it
was infinite. Should she satisfy herself of her friend's? or should she
leave it delightfully uncertain? These had been the terms of what has
been called her temptation, at the foot of the hill. But inasmuch as
Adela was by no means strictly engaged in the pursuit of pleasure,
and as the notion of a grain of suffering was by no means repugnant
to her, she had resolved to obtain possession of the one essential
fact of her case, even though she should be at heavy costs to
maintain it.
"Well, I have very little time," said Ludlow; "I must get my dinner
and pay my bill and drive to the train." And he put out his hand.
Adela gave him her own, and looked him full in the eyes. "You are
in a great hurry," said she.
"It's not I who am in a hurry. It's my confounded destiny. It's the
train and the steamer."
"If you really wished to stay you wouldn't be bullied by the train
and the steamer."
"Very true—very true. But do I really wish to stay?"
"That's the question. That's what I want to know."
"You ask difficult questions, Miss Moore."
"I mean they shall be difficult."
"Then, of course, you are prepared to answer difficult ones."
"I don't know that that's of course, but I am."
"Well, then, do you wish me to stay? All I have to do is to throw
down my hat, sit down and fold my arms for twenty minutes. I lose
my train and my ship. I stay in America, instead of going to Europe."
"I have thought of all that."
"I don't mean to say it's a great deal. There are pleasures and
pleasures."
"Yes, and especially the former. It is a great deal."
"And you invite me to accept it?"
"No; I ought not to say that. What I ask of you is whether, if I
should so invite you, you would say 'yes.'"
"That makes the matter very easy for you, Miss Moore. What
attractions do you hold out?"
"I hold out nothing whatever, sir."
"I suppose that means a great deal."
"It means what it seems to mean."
"Well, you are certainly a most interesting woman, Miss Moore—a
charming woman."
"Why don't you call me 'fascinating' at once, and bid me good
morning?"
"I don't know but that I shall have to come to that. But I will give
you no answer that leaves you at an advantage. Ask me to stay—
command me to stay, if that suits you better—and I will see how it
sounds. Come, you must not trifle with a man." He still held Adela's
hand, and they had been looking frankly into each other's eyes. He
paused, waiting for an answer.
"Good-by, Mr. Ludlow," said Adela. "God bless you!" And she was
about to withdraw her hand; but he held it.
"Are we friends?" said he.
Adela gave a little shrug of her shoulders. "Friends of three
hours."
Ludlow looked at her with some sternness. "Our parting could at
best hardly have been sweet," said he; "but why should you make it
bitter, Miss Moore?"
"If it's bitter, why should you try to change it?"
"Because I don't like bitter things."
Ludlow had caught a glimpse of the truth—that truth of which the
reader has had a glimpse—and he stood there at once thrilled and
annoyed. He had both a heart and a conscience. "It's not my fault,"
he cried to the latter; but he was unable to add, in all consistency,
that it was his misfortune. It would be very heroic, very poetic, very
chivalric, to lose his steamer, and he felt that he could do so for
sufficient cause—at the suggestion of a fact. But the motive here
was less than a fact—an idea; less than an idea—a fancy. "It's a very
pretty little romance as it is," he said to himself. "Why spoil it? She is
an admirable girl: to have learned that is enough for me." He raised
her hand to his lips, pressed them to it, dropped it, reached the door
and bounded out of the garden gate.
The day was ended.

IV

A MOST EXTRAORDINARY CASE

Late in the spring of the year 1865, just as the war had come to a
close, a young invalid officer lay in bed in one of the uppermost
chambers of one of the great New York hotels. His meditations were
interrupted by the entrance of a waiter, who handed him a card
superscribed Mrs. Samuel Mason, and bearing on its reverse the
following words in pencil: "Dear Colonel Mason, I have only just
heard of your being here, ill and alone. It's too dreadful. Do you
remember me? Will you see me? If you do, I think you will remember
me. I insist on coming up. M. M."
Mason was undressed, unshaven, weak, and feverish. His ugly
little hotel chamber was in a state of confusion which had not even
the merit of being picturesque. Mrs. Mason's card was at once a
puzzle and a heavenly intimation of comfort. But all that it
represented was so dim to the young man's enfeebled perception
that it took him some moments to collect his thoughts.
"It's a lady, sir," said the waiter, by way of assisting him.
"Is she young or old?" asked Mason.
"Well, sir, she's a little of both."
"I can't ask a lady to come up here," groaned the invalid.
"Upon my word, sir, you look beautiful," said the waiter. "They like
a sick man. And I see she's of your own name," continued Michael,
in whom constant service had bred great frankness of speech; "the
more shame to her for not coming before."
Colonel Mason concluded that, as the visit had been of Mrs.
Mason's own seeking, he would receive her without more ado. "If
she doesn't mind it, I'm sure I needn't," said the poor fellow, who
hadn't the strength to be over-punctilious. So in a very few moments
his visitor was ushered up to his bedside. He saw before him a
handsome, middle-aged blonde woman, stout of figure, and dressed
in the height of the fashion, who displayed no other embarrassment
than such as was easily explained by the loss of breath consequent
on the ascent of six flights of stairs.
"Do you remember me?" she asked, taking the young man's
hand.
He lay back on his pillow, and looked at her. "You used to be my
aunt,—my aunt Maria," he said.
"I'm your aunt Maria still," she answered. "It's very good of you not
to have forgotten me."
"It's very good of you not to have forgotten me," said Mason, in a
tone which betrayed a deeper feeling than the wish to return a civil
speech.
"Dear me, you've had the war and a hundred dreadful things. I've
been living in Europe, you know. Since my return I've been living in
the country, in your uncle's old house on the river, of which the lease
had just expired when I came home. I came to town yesterday on
business, and accidentally heard of your condition and your
whereabouts. I knew you'd gone into the army, and I had been
wondering a dozen times what had become of you, and whether you
wouldn't turn up now that the war's at last over. Of course I didn't
lose a moment in coming to you. I'm so sorry for you." Mrs. Mason
looked about her for a seat. The chairs were encumbered with odds
and ends belonging to her nephew's wardrobe and to his equipment,
and with the remnants of his last repast. The good lady surveyed the
scene with the beautiful mute irony of compassion.
The young man lay watching her comely face in delicious
submission to whatever form of utterance this feeling might take.
"You're the first woman—to call a woman—I've seen in I don't know
how many months," he said, contrasting her appearance with that of
his room, and reading her thoughts.
"I should suppose so. I mean to be as good as a dozen." She
disembarrassed one of the chairs, and brought it to the bed. Then,
seating herself, she ungloved one of her hands, and laid it softly on
the young man's wrist. "What a great full-grown young fellow you've
become!" she pursued. "Now, tell me, are you very ill?"
"You must ask the doctor," said Mason. "I actually don't know. I'm
extremely uncomfortable, but I suppose it's partly my
circumstances."
"I've no doubt it's more than half your circumstances. I've seen the
doctor. Mrs. Van Zandt is an old friend of mine; and when I come to
town, I always go to see her. It was from her I learned this morning
that you were here in this state. We had begun by rejoicing over the
new prospects of peace; and from that, of course, we had got to
lamenting the numbers of young men who are to enter upon it with
lost limbs and shattered health. It happened that Mrs. Van Zandt
mentioned several of her husband's patients as examples, and
yourself among the number. You were an excellent young man,
miserably sick, without family or friends, and with no asylum but a
suffocating little closet in a noisy hotel. You may imagine that I
pricked up my ears, and asked your baptismal name. Dr. Van Zandt
came in, and told me. Your name is luckily an uncommon one; it's
absurd to suppose that there could be two Ferdinand Masons. In
short, I felt that you were my husband's brother's child, and that at
last I too might have my little turn at hero-nursing. The little that the
Doctor knew of your history agreed with the little that I knew, though I
confess I was sorry to hear that you had never spoken of our
relationship. But why should you? At all events you've got to
acknowledge it now. I regret your not having said something about it
before, only because the Doctor might have brought us together a
month ago, and you would now have been well."
"It will take me more than a month to get well," said Mason,
feeling that, if Mrs. Mason was meaning to exert herself on his
behalf, she should know the real state of the case. "I never spoke of
you, because I had quite lost sight of you. I fancied you were still in
Europe; and indeed," he added, after a moment's hesitation, "I heard
that you had married again."
"Of course you did," said Mrs. Mason, placidly. "I used to hear it
once a month myself. But I had a much better right to fancy you
married. Thank Heaven, however, there's nothing of that sort
between us. We can each do as we please. I promise to cure you in
a month, in spite of yourself."
"What's your remedy?" asked the young man, with a smile very
courteous, considering how sceptical it was.
"My first remedy is to take you out of this horrible hole. I talked it
all over with Dr. Van Zandt. He says you must get into the country.
Why, my dear boy, this is enough to kill you outright,—one Broadway
outside of your window and another outside of your door! Listen to
me. My house is directly on the river, and only two hours' journey by
rail. You know I've no children. My only companion is my niece,
Caroline Hofmann. You shall come and stay with us until you are as
strong as you need be,—if it takes a dozen years. You shall have
sweet, cool air, and proper food, and decent attendance, and the
devotion of a sensible woman. I shall not listen to a word of
objection. You shall do as you please, get up when you please, dine
when you please, go to bed when you please, and say what you
please. I shall ask nothing of you but to let yourself be very dearly
cared for. Do you remember how, when you were a boy at school,
after your father's death, you were taken with measles, and your
uncle had you brought to our own house? I helped to nurse you
myself, and I remember what nice manners you had in the very
midst of your measles. Your uncle was very fond of you; and if he
had had any considerable property of his own, I know he would have
remembered you in his will. But, of course, he couldn't leave away
his wife's money. What I wish to do for you is a very small part of
what he would have done, if he had only lived, and heard of your
gallantry and your sufferings. So it's settled. I shall go home this
afternoon. To-morrow morning I shall despatch my man-servant to
you with instructions. He's an Englishman. He thoroughly knows his
business, and he will put up your things, and save you every particle
of trouble. You've only to let yourself be dressed, and driven to the
train. I shall, of course, meet you at your journey's end. Now don't tell
me you're not strong enough."
"I feel stronger at this moment than I've felt in a dozen weeks,"
said Mason. "It's useless for me to attempt to thank you."
"Quite useless. I shouldn't listen to you. And I suppose," added
Mrs. Mason, looking over the bare walls and scanty furniture of the
room, "you pay a fabulous price for this bower of bliss. Do you need
money?"
The young man shook his head.
"Very well then," resumed Mrs. Mason, conclusively, "from this
moment you're in my hands."
The young man lay speechless from the very fulness of his heart;
but he strove by the pressure of his fingers to give her some
assurance of his gratitude. His companion rose, and lingered beside
him, drawing on her glove, and smiling quietly with the look of a long-
baffled philanthropist who has at last discovered a subject of infinite
capacity. Poor Ferdinand's weary visage reflected her smile. Finally,
after the lapse of years, he too was being cared for. He let his head
sink into the pillow, and silently inhaled the perfume of her sober
elegance and her cordial good-nature. He felt like taking her dress in
his hand, and asking her not to leave him,—now that solitude would
be bitter. His eyes, I suppose, betrayed this touching apprehension,
—doubly touching in a war-wasted young officer. As she prepared to
bid him farewell, Mrs. Mason stooped, and kissed his forehead. He
listened to the rustle of her dress across the carpet, to the gentle
closing of the door, and to her retreating footsteps. And then, giving
way to his weakness, he put his hands to his face, and cried like a
homesick schoolboy. He had been reminded of the exquisite side of
life.
Matters went forward as Mrs. Mason had arranged them. At six
o'clock on the following evening Ferdinand found himself deposited
at one of the way stations of the Hudson River Railroad, exhausted
by his journey, and yet excited at the prospect of its drawing to a
close. Mrs. Mason was in waiting in a low basket-phaeton, with a
magazine of cushions and wrappings. Ferdinand transferred himself
to her side, and they drove rapidly homeward. Mrs. Mason's house
was a cottage of liberal make, with a circular lawn, a sinuous
avenue, and a well-grown plantation of shrubbery. As the phaeton
drew up before the porch, a young lady appeared in the doorway.
Mason will be forgiven if he considered himself presented ex officio,
as I may say, to this young lady. Before he really knew it, and in the
absence of the servant, who, under Mrs. Mason's directions, was
busy in the background with his trunk, he had availed himself of her
proffered arm, and had allowed her to assist him through the porch,
across the hall, and into the parlor, where she graciously consigned
him to a sofa which, for his especial use, she had caused to be
wheeled up before a fire kindled for his especial comfort. He was
unable, however, to take advantage of her good offices. Prudence
dictated that without further delay he should betake himself to his
room.
On the morning after his arrival he got up early, and made an
attempt to be present at breakfast; but his strength failed him, and he
was obliged to dress at his leisure, and content himself with a simple
transition from his bed to his arm-chair. The chamber assigned him
was designedly on the ground-floor, so that he was spared the
trouble of measuring his strength with the staircase,—a charming
room, brightly carpeted and upholstered, and marked by a certain
fastidious freshness which betrayed the uncontested dominion of
women. It had a broad high window, draped in chintz and crisp
muslin and opening upon the greensward of the lawn. At this
window, wrapped in his dressing-gown, and lost in the embrace of
the most unresisting of arm-chairs, he slowly discussed his simple
repast. Before long his hostess made her appearance on the lawn
outside the window. As this quarter of the house was covered with
warm sunshine, Mason ventured to open the window and talk to her,
while she stood out on the grass beneath her parasol.
"It's time to think of your physician," she said. "You shall choose
for yourself. The great physician here is Dr. Gregory, a gentleman of
the old school. We have had him but once, for my niece and I have
the health of a couple of dairy-maids. On that one occasion he—well,
he made a fool of himself. His practice is among the 'old families,'
and he only knows how to treat certain old-fashioned, obsolete
complaints. Anything brought about by the war would be quite out of
his range. And then he vacillates, and talks about his own maladies
à lui. And, to tell the truth, we had a little repartee which makes our
relations somewhat ambiguous."
"I see he would never do," said Mason, laughing. "But he's not
your only physician?"
"No: there is a young man, a newcomer, a Dr. Knight, whom I
don't know, but of whom I've heard very good things. I confess that I
have a prejudice in favor of the young men. Dr. Knight has a position
to establish, and I suppose he's likely to be especially attentive and
careful. I believe, moreover, that he's been an army surgeon."
"I knew a man of his name," said Mason. "I wonder if this is he.
His name was Horace Knight,—a light-haired, near-sighted man."
"I don't know," said Mrs. Mason; "perhaps Caroline knows." She
retreated a few steps, and called to an upper window: "Caroline,
what's Dr. Knight's first name?"
Mason listened to Miss Hofmann's answer,—"I haven't the least
idea."
"Is it Horace?"
"I don't know."
"Is he light or dark?"
"I've never seen him."
"Is he near-sighted?"
"How in the world should I know?"
"I fancy he's as good as any one," said Ferdinand. "With you, my
dear aunt, what does the doctor matter?"
Mrs. Mason accordingly sent for Dr. Knight, who, on arrival, turned
out to be her nephew's old acquaintance. Although the young men
had been united by no greater intimacy than the superficial
comradeship resulting from a winter in neighboring quarters, they
were very well pleased to come together again. Horace Knight was a
young man of good birth, good looks, good faculties, and good
intentions, who, after a three years' practice of surgery in the army,
had undertaken to push his fortune in Mrs. Mason's neighborhood.
His mother, a widow with a small income, had recently removed to
the country for economy, and her son had been unwilling to leave
her to live alone. The adjacent country, moreover, offered a
promising field for a man of energy,—a field well stocked with large
families of easy income and of those conservative habits which lead
people to make much of the cares of a physician. The local
practitioner had survived the glory of his prime, and was not,
perhaps, entirely guiltless of Mrs. Mason's charge, that he had not
kept up with the progress of the "new diseases." The world, in fact,
was getting too new for him, as well as for his old patients. He had
had money invested in the South,—precious sources of revenue,
which the war had swallowed up at a gulp; he had grown frightened
and nervous and querulous; he had lost his presence of mind and
his spectacles in several important conjunctures; he had been
repeatedly and distinctly fallible; a vague dissatisfaction pervaded
the breasts of his patrons; he was without competitors: in short,
fortune was propitious to Dr. Knight. Mason remembered the young
physician only as a good-humored, intelligent companion; but he
soon had reason to believe that his medical skill would leave nothing
to be desired. He arrived rapidly at a clear understanding of
Ferdinand's case; he asked intelligent questions, and gave simple
and definite instructions. The disorder was deeply seated and
virulent, but there was no apparent reason why unflinching care and
prudence should not subdue it.
"Your strength is very much reduced," he said, as he took his hat
and gloves to go; "but I should say you had an excellent constitution.
It seems to me, however,—if you will pardon me for saying so,—to
be partly your own fault that you have fallen so low. You have
opposed no resistance; you haven't cared to get well."
"I confess that I haven't,—particularly. But I don't see how you
should know it."
"Why it's obvious."
"Well, it was natural enough. Until Mrs. Mason discovered me, I
hadn't a friend in the world. I had become demoralized by solitude. I
had almost forgotten the difference between sickness and health. I
had nothing before my eyes to remind me in tangible form of that
great mass of common human interests for the sake of which—
under whatever name he may disguise the impulse—a man
continues in health and recovers from disease. I had forgotten that I
ever cared for books or ideas, or anything but the preservation of my
miserable carcass. My carcass had become quite too miserable to
Welcome to our website – the ideal destination for book lovers and
knowledge seekers. With a mission to inspire endlessly, we offer a
vast collection of books, ranging from classic literary works to
specialized publications, self-development books, and children's
literature. Each book is a new journey of discovery, expanding
knowledge and enriching the soul of the reade

Our website is not just a platform for buying books, but a bridge
connecting readers to the timeless values of culture and wisdom. With
an elegant, user-friendly interface and an intelligent search system,
we are committed to providing a quick and convenient shopping
experience. Additionally, our special promotions and home delivery
services ensure that you save time and fully enjoy the joy of reading.

Let us accompany you on the journey of exploring knowledge and


personal growth!

textbookfull.com

You might also like