0% found this document useful (0 votes)
3 views

Pro Kotlin Web Apps from Scratch: Building Production-Ready Web Apps Without a Framework 1st Edition August Lilleaas pdf download

The document promotes the book 'Pro Kotlin Web Apps from Scratch' by August Lilleaas, which focuses on building production-ready web applications without a framework. It provides links to download the book and other related resources from ebookmass.com. Additionally, it includes a detailed table of contents outlining various chapters and topics covered in the book.

Uploaded by

calidosaura
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views

Pro Kotlin Web Apps from Scratch: Building Production-Ready Web Apps Without a Framework 1st Edition August Lilleaas pdf download

The document promotes the book 'Pro Kotlin Web Apps from Scratch' by August Lilleaas, which focuses on building production-ready web applications without a framework. It provides links to download the book and other related resources from ebookmass.com. Additionally, it includes a detailed table of contents outlining various chapters and topics covered in the book.

Uploaded by

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

Visit https://ebookmass.

com to download the full version and


browse more ebooks or textbooks

Pro Kotlin Web Apps from Scratch: Building


Production-Ready Web Apps Without a Framework 1st
Edition August Lilleaas

_____ Press the link below to begin your download _____

https://ebookmass.com/product/pro-kotlin-web-apps-from-
scratch-building-production-ready-web-apps-without-a-
framework-1st-edition-august-lilleaas/

Access ebookmass.com now to download high-quality


ebooks or textbooks
We believe these products will be a great fit for you. Click
the link to download now, or visit ebookmass.com
to discover even more!

Pro Kotlin Web Apps from Scratch August Lilleaas

https://ebookmass.com/product/pro-kotlin-web-apps-from-scratch-august-
lilleaas/

High-Performance Web Apps with FastAPI: The Asynchronous


Web Framework Based on Modern Python 1st Edition Malhar
Lathkar
https://ebookmass.com/product/high-performance-web-apps-with-fastapi-
the-asynchronous-web-framework-based-on-modern-python-1st-edition-
malhar-lathkar/

High-Performance Web Apps with FastAPI: The Asynchronous


Web Framework Based on Modern Python 1st Edition Malhar
Lathkar
https://ebookmass.com/product/high-performance-web-apps-with-fastapi-
the-asynchronous-web-framework-based-on-modern-python-1st-edition-
malhar-lathkar-2/

Kotlin for Web Development and Kotlin Collections: A


Beginner's Odyssey in Web Development 2 Books in 1 Jp
Parker
https://ebookmass.com/product/kotlin-for-web-development-and-kotlin-
collections-a-beginners-odyssey-in-web-development-2-books-in-1-jp-
parker/
Learn Enough Ruby to Be Dangerous Michael Hartl

https://ebookmass.com/product/learn-enough-ruby-to-be-dangerous-
michael-hartl/

Pro ASP.NET Core 3: Develop Cloud-Ready Web Applications


Using MVC, Blazor, and Razor Pages

https://ebookmass.com/product/pro-asp-net-core-3-develop-cloud-ready-
web-applications-using-mvc-blazor-and-razor-pages/

Pro .NET on Amazon Web Services: Guidance and Best


Practices for Building and Deployment 1st Edition William
Penberthy
https://ebookmass.com/product/pro-net-on-amazon-web-services-guidance-
and-best-practices-for-building-and-deployment-1st-edition-william-
penberthy-2/

Pro .NET on Amazon Web Services: Guidance and Best


Practices for Building and Deployment 1st Edition William
Penberthy
https://ebookmass.com/product/pro-net-on-amazon-web-services-guidance-
and-best-practices-for-building-and-deployment-1st-edition-william-
penberthy/

Beginning Azure Functions: Building Scalable and


Serverless Apps 2nd Edition Rahul Sawhney

https://ebookmass.com/product/beginning-azure-functions-building-
scalable-and-serverless-apps-2nd-edition-rahul-sawhney/
Pro Kotlin
Web Apps
from Scratch
Building Production-Ready Web Apps
Without a Framework

August Lilleaas
Pro Kotlin Web Apps from
Scratch
Building Production-Ready Web
Apps Without a Framework

August Lilleaas
Pro Kotlin Web Apps from Scratch: Building Production-Ready Web Apps Without a
Framework
August Lilleaas
Oslo, Norway

ISBN-13 (pbk): 978-1-4842-9056-9 ISBN-13 (electronic): 978-1-4842-9057-6


https://doi.org/10.1007/978-1-4842-9057-6

Copyright © 2023 by August Lilleaas


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.
Trademarked names, logos, and images may appear in this book. Rather than use a trademark symbol with
every occurrence of a trademarked name, logo, or image we use the names, logos, and images only in an
editorial fashion and to the benefit of the trademark owner, with no intention of infringement of the
trademark.
The use in this publication of trade names, trademarks, service marks, and similar terms, even if they are not
identified as such, is not to be taken as an expression of opinion as to whether or not they are subject to
proprietary rights.
While the advice and information in this book are believed to be true and accurate at the date of publication,
neither the authors nor the editors nor the publisher can accept any legal responsibility for any errors or
omissions that may be made. The publisher makes no warranty, express or implied, with respect to the
material contained herein.
Managing Director, Apress Media LLC: Welmoed Spahr
Acquisitions Editor: Jonathan Gennick
Development Editor: Laura Berendson
Coordinating Editor: Jill Balzano
Cover Photo by George Tasios on Unsplash
Distributed to the book trade worldwide by Springer Science+Business Media LLC, 1 New York Plaza,
Suite 4600, New York, NY 10004. Phone 1-800-SPRINGER, fax (201) 348-4505, e-mail orders-ny@springer-
sbm.com, 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 information on translations, please e-mail booktranslations@springernature.com; for reprint,
paperback, or audio rights, please e-mail bookpermissions@springernature.com.
Apress titles may be purchased in bulk for academic, corporate, or promotional use. eBook versions and
licenses are also available for most titles. For more information, reference our Print and eBook Bulk Sales
web page at http://www.apress.com/bulk-sales.
Any source code or other supplementary material referenced by the author in this book is available
to readers on GitHub (https://github.com/Apress). For more detailed information, please visit
http://www.apress.com/source-code.
Printed on acid-free paper
Dedicated to my mother and father, who made it all happen,
and
in loving memory of Ann-Cecilie Saltnes (11.03.1980–04.07.2022)
Table of Contents
About the Author�����������������������������������������������������������������������������������������������������xv

About the Technical Reviewer�������������������������������������������������������������������������������xvii


Acknowledgments��������������������������������������������������������������������������������������������������xix

Introduction������������������������������������������������������������������������������������������������������������xxi

Part I: Up and Running with a Web App���������������������������������������������������������� 1


Chapter 1: Setting Up a Development Environment�������������������������������������������������� 3
Get Started with IntelliJ IDEA Community Edition������������������������������������������������������������������������� 3
Download and Run IntelliJ IDEA���������������������������������������������������������������������������������������������� 4
Create a New Kotlin Project with IntelliJ IDEA������������������������������������������������������������������������� 4
Kotlin Hello, World!������������������������������������������������������������������������������������������������������������������������ 9
Kotlin Naming Conventions����������������������������������������������������������������������������������������������������� 9
Write Some Code��������������������������������������������������������������������������������������������������������������������� 9
Run Your Code with IntelliJ IDEA������������������������������������������������������������������������������������������� 11
Run Your Code with Gradle���������������������������������������������������������������������������������������������������� 12
IntelliJ IDEA Tips and Tricks�������������������������������������������������������������������������������������������������������� 13
Look Out for the Progress Bar����������������������������������������������������������������������������������������������� 14
Remember to Refresh the Gradle Project in IntelliJ IDEA������������������������������������������������������ 15
Embrace Auto-completion in IntelliJ IDEA����������������������������������������������������������������������������� 16

Chapter 2: Setting Up the Web App Skeleton���������������������������������������������������������� 19


Web Server Hello, World!������������������������������������������������������������������������������������������������������������ 20
Choosing Ktor������������������������������������������������������������������������������������������������������������������������ 20
Add the Ktor Library�������������������������������������������������������������������������������������������������������������� 20
Start a Web Server���������������������������������������������������������������������������������������������������������������� 21
Extracting to a Separate Function����������������������������������������������������������������������������������������� 22

v
Table of Contents

Using Lambdas���������������������������������������������������������������������������������������������������������������������� 23
Named Arguments Instead of Magic Numbers and Booleans����������������������������������������������� 24
Run Your Web App����������������������������������������������������������������������������������������������������������������� 25
Logging��������������������������������������������������������������������������������������������������������������������������������������� 26
Loggers on the Java Platform������������������������������������������������������������������������������������������������ 26
Configure Logging in Your Web App��������������������������������������������������������������������������������������� 27
Write to the Log from Your Own Code����������������������������������������������������������������������������������� 30
A Note on “Magic” XML Config Files������������������������������������������������������������������������������������� 32
Useful Error Pages���������������������������������������������������������������������������������������������������������������������� 33

Chapter 3: Configuration Files�������������������������������������������������������������������������������� 37


Create a Configuration File��������������������������������������������������������������������������������������������������������� 38
The Configuration File Anatomy��������������������������������������������������������������������������������������������� 38
Reading Values from Your Configuration File������������������������������������������������������������������������� 39
Make the Configuration Fail Early and Type-Safe����������������������������������������������������������������������� 40
Store Configuration in a Data Class��������������������������������������������������������������������������������������� 41
Load Config into the Data Class��������������������������������������������������������������������������������������������� 42
Kotlin Null Safety������������������������������������������������������������������������������������������������������������������� 42
Kotlin Platform Types������������������������������������������������������������������������������������������������������������� 43
Use the Data Class in Your Web App�������������������������������������������������������������������������������������� 44
Use let Blocks to Avoid Intermediate Variables��������������������������������������������������������������������� 45
Provide Different Default Values for Different Environments������������������������������������������������������ 46
Environment-Specific Config Files���������������������������������������������������������������������������������������� 46
Define the Web App Environment������������������������������������������������������������������������������������������ 47
Override Defaults with Environment-Specific Config������������������������������������������������������������ 47
Secret Config Values������������������������������������������������������������������������������������������������������������������� 48
Don’t Store Secrets in Version Control���������������������������������������������������������������������������������� 48
Logging Config on Web App Startup�������������������������������������������������������������������������������������������� 51
Format the Output����������������������������������������������������������������������������������������������������������������� 52
Masking Secrets�������������������������������������������������������������������������������������������������������������������� 52
Writing to the Log������������������������������������������������������������������������������������������������������������������ 53

vi
Table of Contents

Chapter 4: Decoupling Web Handlers from Specific Libraries�������������������������������� 55


Your Own HTTP Response Abstraction���������������������������������������������������������������������������������������� 56
Representing HTTP Responses���������������������������������������������������������������������������������������������� 56
Multiple Response Types������������������������������������������������������������������������������������������������������� 57
Convenience Functions for Headers�������������������������������������������������������������������������������������� 59
Case-Insensitive Headers������������������������������������������������������������������������������������������������������ 64
The fold Function������������������������������������������������������������������������������������������������������������������� 65
Destructuring Assignment����������������������������������������������������������������������������������������������������� 66
Connecting to Ktor���������������������������������������������������������������������������������������������������������������������� 67
Ktor Route Mapping��������������������������������������������������������������������������������������������������������������� 67
Extension Functions�������������������������������������������������������������������������������������������������������������� 68
Functions Returning Functions���������������������������������������������������������������������������������������������� 69
Map Headers������������������������������������������������������������������������������������������������������������������������� 70
Map TextWebResponse and Status Code������������������������������������������������������������������������������ 71
Map JsonWebResponse�������������������������������������������������������������������������������������������������������� 72
Using the New Mapping�������������������������������������������������������������������������������������������������������� 74
A Note on Overengineering��������������������������������������������������������������������������������������������������������� 75

Part II: Libraries and Solutions��������������������������������������������������������������������� 77


Chapter 5: Connecting to and Migrating SQL Databases���������������������������������������� 79
Connecting to a SQL Database���������������������������������������������������������������������������������������������������� 80
The Connection Pool�������������������������������������������������������������������������������������������������������������� 80
Installing the Database Driver����������������������������������������������������������������������������������������������� 81
Setting Up H2������������������������������������������������������������������������������������������������������������������������� 82
Updating WebappConfig�������������������������������������������������������������������������������������������������������� 82
Set Up the Connection Pool��������������������������������������������������������������������������������������������������� 84
Creating a Connection����������������������������������������������������������������������������������������������������������� 85
The Initial Schema���������������������������������������������������������������������������������������������������������������������� 86
Installing Flyway�������������������������������������������������������������������������������������������������������������������� 86
Running Flyway During Startup��������������������������������������������������������������������������������������������� 86
Creating the Initial Schema��������������������������������������������������������������������������������������������������� 88

vii
Table of Contents

Managing Schema Changes������������������������������������������������������������������������������������������������������� 89


Don’t Edit Migrations After Run��������������������������������������������������������������������������������������������� 89
Adding More Schema������������������������������������������������������������������������������������������������������������ 90
Adding Non-nullable Columns����������������������������������������������������������������������������������������������� 90
Backward-Compatible Migrations����������������������������������������������������������������������������������������� 92
Insert Seed Data������������������������������������������������������������������������������������������������������������������������� 93
Repeatable Migrations���������������������������������������������������������������������������������������������������������� 93
Updating Repeatable Migrations������������������������������������������������������������������������������������������� 94
Handling Failed Migrations��������������������������������������������������������������������������������������������������������� 95
Failed Migrations Locally������������������������������������������������������������������������������������������������������� 95
Failed Migrations in Production��������������������������������������������������������������������������������������������� 95
Rerunning Failed Migration��������������������������������������������������������������������������������������������������� 96
Manually Performing Migration��������������������������������������������������������������������������������������������� 96

Chapter 6: Querying a SQL Database���������������������������������������������������������������������� 97


Setting Up Querying�������������������������������������������������������������������������������������������������������������������� 97
Use SQL Directly�������������������������������������������������������������������������������������������������������������������� 98
Installing Kotliquery��������������������������������������������������������������������������������������������������������������� 99
Mapping Query Results��������������������������������������������������������������������������������������������������������� 99
Execute SQL Queries����������������������������������������������������������������������������������������������������������������� 100
Creating a Session��������������������������������������������������������������������������������������������������������������� 100
Querying for Single Rows���������������������������������������������������������������������������������������������������� 101
Querying for Multiple Rows������������������������������������������������������������������������������������������������� 101
Inserting Rows��������������������������������������������������������������������������������������������������������������������� 103
Updating and Deleting��������������������������������������������������������������������������������������������������������� 104
Positional vs. Named Parameters���������������������������������������������������������������������������������������� 104
Additional Operations���������������������������������������������������������������������������������������������������������� 105
Querying from Web Handlers���������������������������������������������������������������������������������������������������� 105
Creating a Helper Function�������������������������������������������������������������������������������������������������� 105
A Note on Architecture��������������������������������������������������������������������������������������������������������� 107
Avoid Long-Running Connections���������������������������������������������������������������������������������������� 107

viii
Table of Contents

Maps vs. Data Classes�������������������������������������������������������������������������������������������������������������� 108


Passing Around Maps���������������������������������������������������������������������������������������������������������� 108
Passing Individual Properties���������������������������������������������������������������������������������������������� 109
Mapping to a Data Class������������������������������������������������������������������������������������������������������ 110
Database Transactions�������������������������������������������������������������������������������������������������������������� 113
Creating Transactions���������������������������������������������������������������������������������������������������������� 113
Transactions in Web Handlers��������������������������������������������������������������������������������������������� 114
Type-Safe Transactional Business Logic����������������������������������������������������������������������������� 115
Nested Transactions������������������������������������������������������������������������������������������������������������ 116

Chapter 7: Automated Tests with jUnit 5�������������������������������������������������������������� 119


Setting Up Your Environment���������������������������������������������������������������������������������������������������� 119
Adding jUnit 5 and kotlin.test���������������������������������������������������������������������������������������������� 120
Writing a Failing Test����������������������������������������������������������������������������������������������������������� 121
Running a Failing Test��������������������������������������������������������������������������������������������������������� 121
Making the Test Pass����������������������������������������������������������������������������������������������������������� 123
Writing Web App Tests��������������������������������������������������������������������������������������������������������������� 125
Setting Up the Basics���������������������������������������������������������������������������������������������������������� 125
Writing a Failing Test����������������������������������������������������������������������������������������������������������� 126
Making the Test Pass����������������������������������������������������������������������������������������������������������� 128
Avoiding Leaky Tests����������������������������������������������������������������������������������������������������������������� 129
Leaky Tests�������������������������������������������������������������������������������������������������������������������������� 129
Avoiding Leaks with Transactions��������������������������������������������������������������������������������������� 130
Avoiding Leaks with Relative Asserts���������������������������������������������������������������������������������� 133
Test-Driven Development���������������������������������������������������������������������������������������������������������� 135
Design and Verification�������������������������������������������������������������������������������������������������������� 135
Writing a Failing Test����������������������������������������������������������������������������������������������������������� 135
Making the Test Pass����������������������������������������������������������������������������������������������������������� 137
Notes on Methodology�������������������������������������������������������������������������������������������������������������� 137
What About Front-End Tests?���������������������������������������������������������������������������������������������� 137
Real Database Writes vs. Mocks����������������������������������������������������������������������������������������� 138
Unit vs. Integration Tests����������������������������������������������������������������������������������������������������� 139

ix
Table of Contents

Chapter 8: Parallelizing Service Calls with Coroutines���������������������������������������� 141


Preparing Your Web App������������������������������������������������������������������������������������������������������������ 141
Implementing a Fake Service���������������������������������������������������������������������������������������������� 142
Adding a Second Server������������������������������������������������������������������������������������������������������ 142
Understanding Coroutines�������������������������������������������������������������������������������������������������������� 144
The delay Coroutine������������������������������������������������������������������������������������������������������������� 144
The Problem with Threads��������������������������������������������������������������������������������������������������� 144
Suspending Instead of Locking������������������������������������������������������������������������������������������� 145
Coroutine Contexts�������������������������������������������������������������������������������������������������������������� 145
Coroutines in Ktor���������������������������������������������������������������������������������������������������������������� 147
Parallelizing Service Calls��������������������������������������������������������������������������������������������������������� 148
Adding Dependencies���������������������������������������������������������������������������������������������������������� 148
Performing Parallelized Calls���������������������������������������������������������������������������������������������� 149
Handling Race Conditions���������������������������������������������������������������������������������������������������� 151
Adding to Ktor���������������������������������������������������������������������������������������������������������������������� 151
Mixing Coroutines and Blocking Calls��������������������������������������������������������������������������������������� 152
Wrapping Blocking Calls������������������������������������������������������������������������������������������������������ 152
Coroutine Internals�������������������������������������������������������������������������������������������������������������������� 153
Kotlin vs. KotlinX������������������������������������������������������������������������������������������������������������������ 153
Comparing with Arrow��������������������������������������������������������������������������������������������������������� 154
Using Low-Level Continuations������������������������������������������������������������������������������������������� 157
Java Platform Implementation Details�������������������������������������������������������������������������������� 158

Chapter 9: Building Traditional Web Apps with HTML and CSS���������������������������� 161
Patterns and Organization�������������������������������������������������������������������������������������������������������� 162
Generating HTML���������������������������������������������������������������������������������������������������������������������� 162
Using the kotlinx.html DSL�������������������������������������������������������������������������������������������������� 162
Using the Ktor HTML DSL���������������������������������������������������������������������������������������������������� 163
The Power of the DSL���������������������������������������������������������������������������������������������������������� 164
Operator Overloading���������������������������������������������������������������������������������������������������������� 165
Adding Custom Tags������������������������������������������������������������������������������������������������������������ 166

x
Table of Contents

CSS and Assets������������������������������������������������������������������������������������������������������������������������� 167


Serving Static Files�������������������������������������������������������������������������������������������������������������� 167
Instant Reloading����������������������������������������������������������������������������������������������������������������� 170
Reusable Layouts���������������������������������������������������������������������������������������������������������������������� 171
Adding a Layout������������������������������������������������������������������������������������������������������������������� 172
Using the Layout������������������������������������������������������������������������������������������������������������������ 173
Adding WebResponse for HTML������������������������������������������������������������������������������������������������ 174
Implementing HtmlWebResponse��������������������������������������������������������������������������������������� 174
Extension Function Precedence������������������������������������������������������������������������������������������ 175
Responding with HtmlWebResponse����������������������������������������������������������������������������������� 176
A Note on Abstractions�������������������������������������������������������������������������������������������������������� 178
User Security����������������������������������������������������������������������������������������������������������������������������� 178
Password Hashing��������������������������������������������������������������������������������������������������������������� 178
Using Bcrypt for Hashing����������������������������������������������������������������������������������������������������� 179
Updating Your Migrations���������������������������������������������������������������������������������������������������� 182
Adding a Login Form����������������������������������������������������������������������������������������������������������������� 183
Wiring Up Your Web App������������������������������������������������������������������������������������������������������ 183
Different Types of Sessions������������������������������������������������������������������������������������������������� 185
Adding a New Ktor Extension Function������������������������������������������������������������������������������� 186
Configuring Session Cookies����������������������������������������������������������������������������������������������� 187
Logging In���������������������������������������������������������������������������������������������������������������������������� 189
Protecting Routes with Authentication�������������������������������������������������������������������������������� 191
Logging Out������������������������������������������������������������������������������������������������������������������������� 194

Chapter 10: Building API-Based Back Ends���������������������������������������������������������� 197


Handling API Calls��������������������������������������������������������������������������������������������������������������������� 197
Parsing Input����������������������������������������������������������������������������������������������������������������������� 197
Validating and Extracting Input�������������������������������������������������������������������������������������������� 198
Avoid Automatic Serialization���������������������������������������������������������������������������������������������� 200
Internal vs. External APIs����������������������������������������������������������������������������������������������������� 202

xi
Table of Contents

Single-Page Apps���������������������������������������������������������������������������������������������������������������������� 202


Hosting Alongside API���������������������������������������������������������������������������������������������������������� 202
Hosting Separately with CORS�������������������������������������������������������������������������������������������� 204
Authenticating Users����������������������������������������������������������������������������������������������������������� 206
Native Apps������������������������������������������������������������������������������������������������������������������������������� 207
Using Cookies for Authentication���������������������������������������������������������������������������������������� 207
Using JWTs for Authentication�������������������������������������������������������������������������������������������� 207
Performing Authentication��������������������������������������������������������������������������������������������������� 211

Chapter 11: Deploying to Traditional Server Based Environments����������������������� 213


Packaging as Self-Contained JAR Files������������������������������������������������������������������������������������ 213
What’s a JAR File����������������������������������������������������������������������������������������������������������������� 213
Self-Contained JAR Files����������������������������������������������������������������������������������������������������� 214
Packaging with Gradle��������������������������������������������������������������������������������������������������������� 215
Building the JAR File����������������������������������������������������������������������������������������������������������� 215
Executing the JAR File��������������������������������������������������������������������������������������������������������� 216
Packaging for Production���������������������������������������������������������������������������������������������������������� 217
Building Docker Images������������������������������������������������������������������������������������������������������� 217
Running Docker Images Locally������������������������������������������������������������������������������������������ 219
Deploying to Production������������������������������������������������������������������������������������������������������ 220

Chapter 12: Building and Deploying to Serverless Environments������������������������ 223


Detaching Your Code����������������������������������������������������������������������������������������������������������������� 224
Separating Handlers from Ktor�������������������������������������������������������������������������������������������� 224
Basic Structure�������������������������������������������������������������������������������������������������������������������� 225
Detached Web Handlers������������������������������������������������������������������������������������������������������ 227
Run Web Handlers on AWS Lambda������������������������������������������������������������������������������������������ 227
Making AWS Lambda Web Handlers������������������������������������������������������������������������������������ 227
Deploying to AWS Lambda��������������������������������������������������������������������������������������������������� 229
Calling Your Existing Handlers��������������������������������������������������������������������������������������������� 237
Improving Performance������������������������������������������������������������������������������������������������������������ 243
Performance and Cold Starts���������������������������������������������������������������������������������������������� 244
Initialization Time vs. Execution Time���������������������������������������������������������������������������������� 244

xii
Table of Contents

Lazy Loading������������������������������������������������������������������������������������������������������������������������ 245


Initializing Correctly������������������������������������������������������������������������������������������������������������� 246
Migrations and H2��������������������������������������������������������������������������������������������������������������� 248
Java Runtime Flags������������������������������������������������������������������������������������������������������������� 248
GraalVM, Kotlin/JS, and Kotlin Native���������������������������������������������������������������������������������� 249

Chapter 13: Setup, Teardown, and Dependency Injection with Spring Context���� 251
Why Spring and Dependency Injection?����������������������������������������������������������������������������������� 252
Setting Up Spring Context��������������������������������������������������������������������������������������������������������� 253
Adding Your Data Source���������������������������������������������������������������������������������������������������������� 254
lateinit in Kotlin������������������������������������������������������������������������������������������������������������������������� 256
Starting Your Web App��������������������������������������������������������������������������������������������������������������� 257
Extended Usage������������������������������������������������������������������������������������������������������������������������ 258

Chapter 14: Enterprise Authentication Using Spring Security������������������������������ 261


Preparing Your Web App������������������������������������������������������������������������������������������������������������ 261
Setting Up Embedded Jetty������������������������������������������������������������������������������������������������� 261
Initializing the Servlet���������������������������������������������������������������������������������������������������������� 264
Adding Ktor to Your Servlet�������������������������������������������������������������������������������������������������� 265
Using Spring Security��������������������������������������������������������������������������������������������������������������� 267
Setting Up the Servlet Filter������������������������������������������������������������������������������������������������ 267
Configuring Spring Security������������������������������������������������������������������������������������������������ 269
Authenticating Users����������������������������������������������������������������������������������������������������������� 271
Filtering Requests��������������������������������������������������������������������������������������������������������������� 273
Accessing the Logged-In User��������������������������������������������������������������������������������������������� 274

Part III: Tools of the Trade��������������������������������������������������������������������������� 277


Chapter 15: Choosing the Right Library���������������������������������������������������������������� 279
What’s a Library?���������������������������������������������������������������������������������������������������������������������� 279
Popularity Is Largely Irrelevant������������������������������������������������������������������������������������������������� 280
Documentation and Stability Are Important������������������������������������������������������������������������������ 281

xiii
Table of Contents

Avoid Following the “X Way”����������������������������������������������������������������������������������������������������� 281


Don’t Shy Away from Platform Libraries����������������������������������������������������������������������������������� 282
Boundaries and Layers������������������������������������������������������������������������������������������������������������� 283

Chapter 16: An Assortment of Kotlin Tricks��������������������������������������������������������� 285


Delegation (by lazy)������������������������������������������������������������������������������������������������������������������� 285
Inline Functions������������������������������������������������������������������������������������������������������������������������� 286
Reified Generics������������������������������������������������������������������������������������������������������������������������ 288
Contracts����������������������������������������������������������������������������������������������������������������������������������� 289
And So Much More�������������������������������������������������������������������������������������������������������������������� 290

Appendix A: Using Jooby Instead of Ktor������������������������������������������������������������� 293

Appendix B: Using Hoplite Instead of Typesafe Config����������������������������������������� 303

Appendix C: Using Spek Instead of jUnit 5����������������������������������������������������������� 307

Index��������������������������������������������������������������������������������������������������������������������� 313

xiv
About the Author
August Lilleaas has been building web apps, user interfaces,
and real-time systems since 2004 and mobile apps since the
app stores opened in the late 2000s. After picking up Clojure
in 2012, he left the frameworks and ORMs behind and
started to build web apps from scratch and has shipped to
production using Clojure, Groovy, Node.js, Elixir, and Kotlin.
He has worked as a consultant for a decade and is now an
independent contractor and startup founder.

xv
About the Technical Reviewer
Andres Sacco has been a professional developer since 2007,
working with a variety of languages, including Java, Scala,
PHP, Node.js, and Kotlin. Most of his background is in Java
and the libraries or frameworks associated with it, like Spring,
JSF, iBATIS, Hibernate, and Spring Data. He is focused on
researching new technologies to improve the performance,
stability, and quality of the applications he develops.
In 2017 he started to find new ways to optimize the
transference of data between applications to reduce the
cost of infrastructure. He suggested some actions, some of them applicable in all the
microservices and others in just a few of them. As a result of these actions, the cost was
reduced by 55%. Some of these actions are connected directly with the bad use of the
databases.

xvii
Acknowledgments
Thanks to my fiancée, Tina, who believes in me and lets me know. Thanks to Jonathan
Gennick for giving me the opportunity to become a technical writer. Thanks to everyone
else at Apress for being a pleasure to work with. Thanks to Marius Mårnes Mathisen
for catapulting my career way back when, despite my complete lack of programming
education and professional experience. Thanks to Kolbjørn Jetne for further catapulting
my career, despite my complete lack of consulting experience. Thanks to Magnar Sveen,
Christian Johansen, and Alf Kristian Støyle for all the discussions, input, and inspiration
through the years. A special thanks to Finn Johnsen, who helped form most of the
patterns in this book and was a vital fellow traveler in my initial quest for escaping the
framework and bridging the gap between the old and the new.
Finally, thanks to my son, Tobias, and my daughter, Lone, who are awesome. And, at
my daughter’s request/demand, “Pappa er en bok.”

xix
Introduction
Welcome to Pro Kotlin Web Apps from Scratch! In this book, you’ll learn how to build
professional and production-grade web apps, completely from scratch, without the use
of big and unwieldy frameworks.
My personal web app journey started with frameworks, but when I learned more
about what goes on under the hood and grew weary of fighting framework bugs and
limitations, I started teaching myself how to build web apps from scratch instead. As it
turns out, frameworks aren’t a requirement!
You’re in good hands when you’re building from scratch, thanks to modern
programming languages like Kotlin and amazing third-party open source libraries. Back
in the day, you needed thousands of lines of boilerplate and XML configuration to wire
up a framework-less web app. No wonder people preferred frameworks! Nowadays,
though, all you need is a couple of handfuls of explicit code, completely free of bloat and
magic, that only does what you tell it to.
In Part I, you’ll set up a web app skeleton, completely from scratch. This code
base forms the basis for Part II, where you’ll learn a handful of patterns and practical
solutions that build on the skeleton from Part I. Part III covers how to choose the right
library and Kotlin tips and tricks that I didn’t get to cover in the preceding parts. Finally,
three appendixes explain how to replace some of the libraries chosen in Parts I and II, to
demonstrate that you have free rein to choose different libraries than me and still write
pro Kotlin web apps from scratch.
I’ve deliberately kept the chapter about Kotlin tips and tricks in Part III as short as
I’ve been able to manage. Instead, you’ll learn Kotlin tips and tricks in Parts I and II, and
you’ll learn how to build web apps from scratch alongside explanations of the various
Kotlin language constructs you’re using.

xxi
PART I

Up and Running with a


Web App
CHAPTER 1

Setting Up a Development
Environment
In this chapter you’ll set up a development environment for Kotlin. You’ll install IntelliJ
IDEA, a Java Development Kit (JDK), you’ll write a small Kotlin program, and you’ll
compile and run it using the Gradle build system.
This chapter explains how to do everything using IntelliJ IDEA. For the other
chapters in this book, though, using IntelliJ IDEA is not a requirement. For example,
both the Eclipse IDE (integrated development environment) and Visual Studio Code
have Kotlin plugins available, made by the Kotlin community. If you choose to use
another editor, make sure that it supports auto-completion and automatic imports.
Extension functions are prevalent in Kotlin, and you must import them before you can
use them. You’ll avoid lots of tedious manual work if your editor can search and match
all available extension functions (auto-completion) and automatically add an import
statement when you select one of the auto-completed options (automatic imports).

Get Started with IntelliJ IDEA Community Edition


You’ll need an editor to write your code and a way to compile and run your code. IntelliJ
IDEA gives you both.
IntelliJ IDEA is the canonical integrated development environment (IDE) for
static languages on the Java platform. The free community edition of IntelliJ IDEA has
everything you need, both for this book and for production-grade Kotlin development.
Additionally, JetBrains makes both Kotlin and IntelliJ IDEA, making IntelliJ IDEA
uniquely well suited for Kotlin work.

3
© August Lilleaas 2023
A. Lilleaas, Pro Kotlin Web Apps from Scratch, https://doi.org/10.1007/978-1-4842-9057-6_1
Chapter 1 Setting Up a Development Environment

Download and Run IntelliJ IDEA


You can download and use IntelliJ IDEA Community for free from JetBrains. Go to the
IntelliJ IDEA download page, shown in Figure 1-1, at the address www.jetbrains.com/
idea/download/ and download the community edition from there. JetBrains provides a
.dmg file for macOS, an .exe file for Windows, and a tarball with a shell script in bin/idea.
sh for Linux.

Figure 1-1. Download IntelliJ IDEA Community Edition for your platform

For more details on how to install and run IntelliJ IDEA, refer to the JetBrains
website. For example, the download page has a link with installation instructions in the
left sidebar, as seen in Figure 1-1.

Create a New Kotlin Project with IntelliJ IDEA


There are many ways to create a new Kotlin project. For this book, you’ll be using IntelliJ
IDEA to do it. It’s nice to have a GUI to hold your hand through the process if you’re not
familiar with Kotlin and/or the JVM.

4
Chapter 1 Setting Up a Development Environment

When you launch IntelliJ IDEA, you should see the splash screen shown in
Figure 1-2.

Figure 1-2. Your first taste of IntelliJ IDEA

Click “New Project” to create a new Kotlin project using the built-in wizard in IntelliJ
IDEA, shown in Figure 1-3.

5
Chapter 1 Setting Up a Development Environment

Figure 1-3. The New Project screen in IntelliJ IDEA

Use your good taste and judgment to name the project, and adjust the options as
follows:

• Make sure you select “New Project” in the left sidebar.

• Set Language to Kotlin.

• Set Build system to Gradle.

• Set Gradle DSL to Kotlin.

• Uncheck Add sample code.

You need a JDK, and the easiest way to get one is to have IntelliJ IDEA download
one for you. Click the red “<No SDK>” dropdown in the New Project dialog shown
in Figure 1-3 and choose an appropriate JDK from the popup that appears, shown in
Figure 1-4. JDK 17 or JDK 11 is a good choice, as those are stable Long-Term Support
(LTS) releases.

6
Chapter 1 Setting Up a Development Environment

Figure 1-4. Use IntelliJ IDEA to download a JDK

There are multiple vendors available. They are all full-fledged JDKs that adhere to
the JDK specifications. For the most part, it doesn’t matter which one you choose. The
differences lie in a handful of edge cases and different defaults. For most web apps, you’ll
be able to switch between vendors and not notice any differences. I personally prefer
Amazon Corretto, mostly out of habit. But I’ve used other vendors in real-world web
apps, such as Azul Zulu. I tend to choose whichever vendor is most convenient on the
platform I use, such as Azul Zulu on Azure, Amazon Corretto on AWS, and so on.
Make sure you choose a JDK of version 11 or newer. Versions 11 and 17 are both
Long-Time Support (LTS) releases, which means they’ll receive security updates longer
than other versions. And later in this book, you’ll use libraries that require at least
version 11 to work.
You can also choose an existing JDK if you have one installed. Alternatively, you can
manage JDK installations yourself, by using something like sdkman (https://sdkman.io/)
on macOS and Linux and Jabba (https://github.com/shyiko/jabba) on Windows.

Tip You can have bad luck and choose a JDK version that’s incompatible with the
Gradle version used by IntelliJ IDEA. For example, the 2021 version of IntelliJ uses
Gradle 7.1, which only works with JDK versions lower than 16. If this happens,
delete your project and start over, using a different JDK or Gradle version.

After IntelliJ IDEA finishes downloading the JDK, click the “Create” button at the
bottom of the New Project dialog shown in Figure 1-3, and your brand-new project
appears, as shown in Figure 1-5.

7
Chapter 1 Setting Up a Development Environment

Figure 1-5. IntelliJ IDEA after it has finished with project initialization

With this setup, IntelliJ IDEA won’t create sample code or pre-generated files, other
than a Gradle build system skeleton. All you have now is a way to compile and run Kotlin
code. And that’s all you need in this book. There’s no framework with tens of thousands
of lines of code that needs to run first to get anything done.

Tip Gradle is a build system for the Java platform. This is where you add third-­
party code as dependencies, configure production builds, set up automated testing,
and more. Maven is also an excellent choice for building production-grade Kotlin
web apps. Most examples you’ll see in books and online documentation use
Gradle, though, and I’ve only used Gradle in real-world Kotlin apps, so that’s why I
use it in this book.

8
Chapter 1 Setting Up a Development Environment

Kotlin Hello, World!


It’s common when learning a new language to make one’s first program to be one that
outputs “Hello, World!” This ensures that everything is up and running, that you can
compile Kotlin code, and that you can run it and see that it outputs something.

Kotlin Naming Conventions


Before you create your first file, you need to know where to put it and what to name it.
Kotlin is very flexible about the naming of files and folders and doesn’t enforce a
specific structure. However, it’s common to follow the Java conventions, and this is what
the official Kotlin style guide recommends. This is especially helpful in team situations,
so that everyone knows where to find and place things.
The conventions go as follows:

• Place Kotlin code in src/main/kotlin.

• Create a package named after the project itself and put all your files
in it. A package is a namespace that tells code apart. This helps avoid
name conflicts with third-party code.

• The directory structure matches the package names. The package


myapp.foo exists in src/main/kotlin/myapp/foo.

• File names are in upper camel case, also known as PascalCase, the
same as Java. Note that in the wild, it’s relatively common to see
underscores too, underscore_case. This book uses PascalCase
throughout.

In this book, you’ll place all your code in the package kotlinbook.

Write Some Code


You are now ready to create your first Kotlin file. Taking the preceding conventions into
account, the file name to use is src/main/kotlin/kotlinbook/Main.kt.
To create the file in IntelliJ IDEA, follow these steps:

• Expand src/main/kotlin in the left sidebar in IntelliJ.

• Right-click src/main/kotlin and choose New ➤ Package.

9
Chapter 1 Setting Up a Development Environment

• Name it kotlinbook and hit Enter on your keyboard.

• Right-click the newly created package/folder kotlinbook, and choose


New ➤ Kotlin Class/File.

• Choose File, choose the file template named simply “File,” name it
Main (IDEA will automatically add the .kt extension), and hit Enter
on your keyboard.

IntelliJ IDEA should now look like what’s shown in Figure 1-6.

Figure 1-6. A Kotlin file inside a package in IntelliJ IDEA

Kotlin is a multi-paradigm language and has support for object-oriented, functional,


and data-oriented programming (Sharvit, 2022, Manning). This book will use functional
and data-oriented styles as much as possible and only use the object-oriented style
when third-party libraries require it.
In your first file, write a top-level function with the name main, as seen in Listing 1-1.
This is a special function name, which tells the Kotlin compiler and the Java runtime to
call that function as the entry point to your program.

10
Chapter 1 Setting Up a Development Environment

Listing 1-1. Print “Hello, World!” in src/main/kotlinbook/Main.kt

package kotlinbook

fun main() {
    println("Hello, World!")
}

Tip You can also declare your function as fun main(args: Array<String>)
{ ... } if you want to read the command-line arguments passed to your
application. Java requires that your main function takes an array of strings, but
Kotlin does not have this requirement.

Run Your Code with IntelliJ IDEA


IntelliJ IDEA can run your code directly. This is the fastest way to run your code and
takes maximum advantage of the fact that you’re using an IDE.
The little green arrow next to a function, as shown in Figure 1-7, indicates that IntelliJ
IDEA can run that function directly. Click it, and IntelliJ IDEA will do as you command
and run the function.

11
Chapter 1 Setting Up a Development Environment

Figure 1-7. A green play button next to the function name in IntelliJ IDEA shows a
runnable function

Run Your Code with Gradle


You can also configure Gradle to run your code. Later, you’ll use Gradle to build
deployable JAR (Java archive) files, and Gradle needs to know where your main function
is to be able to build them. Additionally, even if you’re not going to run the code with
Gradle, developers unfamiliar with the project can look at the Gradle config to find the
main function. This helps understand where the main entry point is in the project and is
a good place to start reading code to become familiar with it.
You’ll use the application plugin in Gradle to specify a runnable application with a
main entry point. In the file build.gradle.kts, add the application plugin:

plugins {
  kotlin("jvm") version "..."
  application
}

12
Chapter 1 Setting Up a Development Environment

The application plugin needs to know where to find the main function. At the
top-level of build.gradle.kts (not inside the plugins block), declare the name of the
main class:

application {
  mainClass.set("kotlinbook.MainKt")
}

Tip Did you notice the leaky abstraction? The application plugin is not aware
of Kotlin, and it needs to know the name of the compiled Java class file. To be
compatible and interoperable with the Java platform at large, the Kotlin compiler
turns Main into MainKt. A file Foo.kt that only declares the class Foo is compiled
to Foo.class. Any other scenario will generate FooKt.class.

To run the function with Gradle, use either of the two following methods:

• In a terminal (either stand-alone or the Terminal tab at the bottom of


IntelliJ), type ./gradlew application.

• In the Gradle panel in IntelliJ (found in the rightmost sidebar), click


Tasks ➤ application ➤ run.

You should now see the output of your application, either in your terminal or in the
IntelliJ “Run” output panel.

IntelliJ IDEA Tips and Tricks


IntelliJ IDEA is a vast tool filled with features. This book is not about IntelliJ IDEA, and
you might have chosen to use another editor entirely. But here are some tips that can
help you become familiar with IntelliJ IDEA and avoid common beginner mistakes that
pro IntelliJ IDEA users know how to avoid.
If you want to dig deeper and learn more about the vast world of IntelliJ IDEA, you
should check out the book Beginning IntelliJ IDEA by Ted Hagos ­(www.amazon.com/dp/
1484274458).

13
Chapter 1 Setting Up a Development Environment

Look Out for the Progress Bar


IntelliJ IDEA will sometimes show a progress bar to the right in the bottom toolbar,
as shown in Figure 1-8. When this progress bar is visible, IntelliJ IDEA is busy doing
something important in the background.

Figure 1-8. IntelliJ IDEA is running background analysis of a project, shown by a


blue progress bar to the right in the bottom toolbar

When you see this progress bar, you should wait until it’s gone before you start
editing code.
IntelliJ IDEA knows a lot about your code. To gain that knowledge, it needs to analyze
your code first. When you type in new code, this will happen automatically (and so
quick you probably won’t notice). But when you create a new project or open an existing
project for the first time, IntelliJ IDEA might spend many minutes running analysis in the
background.
The editor is still active while analysis is running, so you assume that IntelliJ IDEA is
ready to go. But many core features won’t be available until the analysis is complete.
When the progress bar is gone, IntelliJ IDEA is ready to go, and you can now edit
code with all the features IntelliJ IDEA provides.

14
Chapter 1 Setting Up a Development Environment

Remember to Refresh the Gradle Project in IntelliJ IDEA


As you grow your project, you will make changes to build.gradle.kts, such as adding
additional third-party code as dependencies, configuring how to build JAR files for
production, and so on.
IntelliJ IDEA has deep knowledge of the contents of build.gradle.kts. For example,
IntelliJ IDEA will auto-complete functions from all third-party code added as
dependencies to your Gradle project.
When you make changes to build.gradle.kts, IntelliJ IDEA requires that you refresh
its knowledge of the Gradle project. If you make changes to build.gradle.kts and don’t
perform a refresh, you can easily end up in a situation where you pull your hair out
in frustration, since IntelliJ IDEA’s knowledge of your project doesn’t match your
expectations.
Fortunately, IntelliJ IDEA is here to help. When there are changes that are not
refreshed yet, IntelliJ IDEA will display a small but vital button, shown in Figure 1-9.
The button shows the Gradle logo and a small refresh arrow. Click this icon to perform a
Gradle refresh.

Figure 1-9. Popup for refreshing Gradle project settings

15
Chapter 1 Setting Up a Development Environment

The icon will only be visible when there are changes made to build.gradle.kts that
IntelliJ IDEA is not yet aware of. But it’s easy to miss, so make sure you refresh your
Gradle project in IntelliJ IDEA every time you change build.gradle.kts.

Embrace Auto-completion in IntelliJ IDEA


IntelliJ IDEA has powerful auto-completion features. Maybe you noticed it as you were
typing in the main function earlier. As you type in code with your keyboard, a dropdown
appears near your cursor. This dropdown contains all the viable symbols you can add
at the location you’re writing currently, limited to symbols that match what you’re
currently typing.
Auto-completion is particularly useful when combined with auto-importing, as
seen in Figure 1-10 and 1-11. If you select an auto-completion in IntelliJ IDEA and
your choice is not imported in the file you’re editing, IntelliJ IDEA will import it for you
automatically.

Figure 1-10. Partially typing LocalTime in IntelliJ IDEA and getting auto-­
completion

16
Chapter 1 Setting Up a Development Environment

Figure 1-11. Hit the Enter key, and the auto-completion will add the full class
name and add an import automatically

By embracing auto-completion, you’ll save yourself from manually typing


everything, as well as having to manually add import statements for code in other
packages, be it from the standard library, third-party code, or your own modules.

17
CHAPTER 2

Setting Up the Web App


Skeleton
Look at all the things I’m not doing!
—David Heinemeier Hansson

This chapter will give you superpowers. You will get all the way to a working web app
with routing, views/templates, and logging. You’ll set the stage for what’s to come in later
chapters. It will just be you and your IDE, no starter kits or frameworks.
If you’re new to Kotlin, here are some language features you’ll see examples of in this
chapter:

• Lambdas

• Named arguments

Also in this chapter, you will learn the following about creating web apps:
• Setting up a web server, powered by Ktor, listening on port 4207

• Logging setup, using SLF4J and Logback, configurable with standard


logback.xml setup

• Tweaking Ktor to display useful error messages when your


application throws unexpected errors

You’ll wire up all these things yourself, instead of having a framework do it for you.
If you’ve only used frameworks before, I envy you. Prepare to be surprised how little
manual wiring you need to do to get it done.

19
© August Lilleaas 2023
A. Lilleaas, Pro Kotlin Web Apps from Scratch, https://doi.org/10.1007/978-1-4842-9057-6_2
Chapter 2 Setting Up the Web App Skeleton

Web Server Hello, World!


In Chapter 1, you wrote a small program that printed “Hello, World!” It’s time to take it
to the next level: a full-fledged working web app that starts a server, sets up URL routing,
and outputs “Hello, World!” over HTTP.

Choosing Ktor
You need a library to handle URL routing and to start up a web server to host your web
app. In this book, you’ll use Ktor. You can swap out Ktor for something else later if you
want, and in Appendix A you’ll learn how to use Jooby instead of Ktor. But in the rest of
the book, all the code you’ll write will use Ktor.
Ktor is one of the most popular libraries for web app routing in Kotlin. It has
everything you need to build production-grade web apps, and it’s written in Kotlin,
so it’s both convenient and powerful to use and makes use of all the relevant features
that Kotlin has to offer for building web apps. It’s also built to be highly scalable and
performant and is battle proven across a large number of real-world web apps.
And, most importantly, Ktor is a library, not a framework. Frameworks, such as
Spring Boot, typically start a web server automatically and use inversion of control to call
your code, somewhere deep down in tens of thousands of lines of framework code. The
point of this book is to learn how to do everything yourself, from scratch.
Interestingly, Ktor labels itself a framework. There aren’t any widely accepted
definitions of libraries vs. frameworks. The one I use in this book is that frameworks
automatically and implicitly do things for you, whereas libraries do nothing unless you
explicitly tell them to. Ktor nicely fits this definition of a library.

Add the Ktor Library


Add Ktor as a dependency in build.gradle.kts, inside the dependencies block. Ktor needs
two dependencies to work: the server core, and the specific server implementation (Netty
in this case):

dependencies {
  implementation("io.ktor:ktor-server-core:2.1.2")
  implementation("io.ktor:ktor-server-netty:2.1.2")
}

20
Chapter 2 Setting Up the Web App Skeleton

Tip Remember to refresh the Gradle project in IntelliJ when you update build.
gradle.kts. Use the small popup that appears when there are changes that
Gradle hasn’t refreshed yet or open the Gradle tab and click the refresh button.

Gradle automatically downloads the dependencies and makes them available to


your own code.

Start a Web Server


You’ll start the web server manually in the application entry point – the main function.
Instead of just printing “Hello, World!”, you’ll change it to start a Ktor web server.
In Listing 2-1, you can see the full working main function needed to start it all up.

Listing 2-1. Start a web server in the application main function at src/main/
kotlinbook/Main.kt

package kotlinbook

import io.ktor.server.application.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.server.response.*
import io.ktor.server.routing.*

fun main() {
  embeddedServer(Netty, port = 4207) {
    routing {
      get("/") {
        call.respondText("Hello, World!")
      }
    }
  }.start(wait = true)
}

21
Chapter 2 Setting Up the Web App Skeleton

The code is plain and straightforward. You create an embedded Ktor server
that is using Netty for the server implementation under the hood and starts at port
4207. You set up routing, which means HTTP verb and path matching. Each route
has an implementation that generates a HTTP response. And finally, you start the
embedded server.
You don’t need to manually write the import statements. For example, when
you write embeddedSe and pause, IntelliJ IDEA will suggest embeddedServer. If you
choose the auto-completion from the dropdown, IntelliJ IDEA will also add an import
statement.
For clarity, the code in Listing 2-1 contains all the import statements needed to
make the code compile. For the remainder of this book, I’ll omit them unless there are
ambiguities (e.g., when there are two extension functions available with the same name,
but in different packages.)

Tip Embedding a HTTP server is standard practice on the Java platform, even


if you use a framework. A proxy such as Nginx or a cloud service like Azure Web
Apps or Amazon Application Load Balancer will sit in front of the embedded HTTP
server in your application and take care of SSL, load balancing, and other web
server tasks. In Chapter 14 you will learn how to build a servlet-style WAR file that
doesn’t start its own server but is embedded into an application server container
such as Tomcat.

Extracting to a Separate Function


Extracting your routes to a separate function is not strictly necessary at this point. But
later in the book, you’ll use your Ktor routing definitions in multiple separate places.
So you need to have it available as a separate function that you can call from anywhere,
instead of locking it into the embeddedServer call.
It’s also common to separate the Ktor server configuration to a separate function
in open source apps and in the Ktor documentation itself, so it’s nice to follow the
conventions in your own web app to make your code more readable.
Listing 2-2 shows how to set this up.

22
Chapter 2 Setting Up the Web App Skeleton

Listing 2-2. Configuring Ktor in a separate isolated function

fun main() {
  embeddedServer(Netty, port = 4207) {
    createKtorApplication()
  }.start(wait = true)
}

fun Application.createKtorApplication() {
  routing {
    get("/") {
      call.respondText("Hello, World!")
    }
  }
}

The function createKtorApplication is an extension function. You’ll learn more


about those in Chapter 3, but the gist of it is that the "this" inside the embeddedServer
lambda is an instance of io.ktor.server.application.Application. And by making
createKtorApplication() an extension function of Application, it will have the
same "this" available when it’s a separate function, as when it’s in-line inside the
embeddedServer lambda.

Using Lambdas
Lambdas are everywhere in Kotlin. In fact, you’ve already written a few of them. The
functions embeddedServer, routing, and get all take lambdas as arguments.
Lambdas are blocks of code, just like functions. They are created using curly
brackets, { and }. The main difference between lambdas and regular functions is that a
lambda does not have a name, but a function does.

Tip Another name for lambdas is anonymous functions. There are a few


differences in syntax between lambdas and functions (you’ll see more about that
throughout the book), but logically they are identical.

23
Chapter 2 Setting Up the Web App Skeleton

There’s a convention in Kotlin for functions that take a lambda as their last
argument. Let’s look at the function get to demonstrate. It takes two arguments: a string,
denoting the path that triggers the route, and a lambda, which holds the code that
should execute when the web app handles a request at that path. One way of calling get
would be like this:

get("/", { ... })

Because it’s so common in Kotlin for functions to take a lambda as their last
argument, there’s a more convenient way to pass them to functions. Instead of placing
the lambda inside the parentheses of the function, you can place it after:

get("/") { ... }

This is particularly useful for functions that only take a lambda. An example of this is
the routing function. It’s nice to be able to skip the parentheses entirely.
It’s common for Kotlin programmers to put the lambda outside the parentheses. In
fact, IntelliJ IDEA will out of the box show a warning if you put a tailing lambda inside
of the parentheses. You can disable this warning if you want to, but it’s a good idea to
follow this convention if you want to make your code as readable as possible to other
programmers.

 amed Arguments Instead of Magic Numbers


N
and Booleans
The function start() takes a Boolean as its only argument. The function
embeddedServer() takes the port number that the server should use. You can call both
like this:

embeddedServer(Netty, 4207) {
  createKtorApplication()
}.start(true)

A common name for Booleans and numbers passed to functions in this manner is
magic Booleans and magic numbers. It’s not immediately obvious to the reader what a
Boolean means when it’s passed to the function start() and what a number means in
the second argument passed to embeddedServer().

24
Chapter 2 Setting Up the Web App Skeleton

To make it easier to understand what these numbers and Booleans mean, you can
pass them as named arguments instead:

embeddedServer(Netty, port = 4207) {


  createKtorApplication()
}.start(wait = true)

You can’t name it anything you want. It must be the same as the name of the
argument in the implementation of the function.

Run Your Web App


Run your application with IntelliJ IDEA or Gradle. Open http://localhost:4207 in your
browser, and you’ll be politely greeted by your code. You should see results like those in
Figure 2-1. Behold! You have a working web app.

Figure 2-1. Your web app is up and running and responding to the port defined in
your code

25
Chapter 2 Setting Up the Web App Skeleton

Logging
High-quality logging is a vital component of production-grade web apps. It can make or
break your ability to find out what happened when errors happen in production.
When you run your application, the console prints the error messages shown in
Figure 2-2.

Figure 2-2. SLF4J issues an error message when your application runs

In this section, you’ll learn about logging and configure your application to output
useful information from third-party code, as well as logging from your own code.

Loggers on the Java Platform


There are several terms and concepts to be aware of when it comes to logging on the Java
platform.
The error messages in Figure 2-2 mention something called “SLF4J.” SLF4J is a
logging façade. SLF4J is short for Simple Logging Façade for Java. A logging façade is not
able to produce any actual log output; it’s only able to receive log statements. When you
start a Ktor server, Ktor tries to log information about the startup process, using instances

26
Chapter 2 Setting Up the Web App Skeleton

of SLF4J loggers. But you haven’t configured logging yet, so SLF4J prints the error
messages seen in Figure 2-2 to let you know that SLF4J received log statements but isn’t
able to output them.
The Java platform has standardized on using SLF4J, and libraries and frameworks
will pull in the SLF4J library and use it to perform its logging.
To see actual log output, you need to add a logging implementation. There are many
different implementations available. The most widely used ones are Logback and Log4j.
SLF4J searches the class path for a logging implementation. The class path is where
the Java platform runtime can find all compiled code from your own source code, as
well as code from third-party dependencies. SLF4J will scan the class path for the class
file org/slf4j/impl/StaticLoggerBinder.class. The logging implementation you choose will
provide this file so that SLF4J can find it and wire it up. SLF4J will then forward all the log
statements it receives to the logging implementation, so that the logging implementation
can display the log messages.
Log levels are a hierarchy of severity levels. A logging statement always has a log
level. The available log levels are trace, debug, info, warning, error, and fatal. The log
levels separate debugging output and information about what your system is up to from
important warnings and critical errors.
You can use log levels to differentiate output from distinct parts of your code. For
example, you can tell the logging implementation to use the warning level for a given
module. The log level hierarchy then dictates that it will hide all levels below warning
(trace, debug, and info) and that the only visible log messages will be those at the
warning level and above (warning, error, and fatal).

Configure Logging in Your Web App


To enable log output for your own code as well as third-party dependencies, you need
to add a logging implementation. For this book, you’ll use Logback. You also need to
configure Logback, so that its output is as useful as possible.
To add Logback to your web app, add Logback and SLF4J as dependencies. In build.
gradle.kts, add the following to the dependencies block that’s already present:

dependencies {
  implementation("ch.qos.logback:logback-classic:1.4.4")
  implementation("org.slf4j:slf4j-api:2.0.3")

27
Chapter 2 Setting Up the Web App Skeleton

Tip You don’t have to add SLF4J as a dependency. Ktor already depends on
SLF4J, and the Gradle build system will make all transitive dependencies (i.e.,
dependencies of dependencies) available to your own code as well. But later,
you’ll call code from SLF4J directly, and it’s considered good hygiene to add direct
dependencies in build.gradle.kts to all code you call directly.

When you restart your web app, you’ll no longer see a warning from SLF4J. Instead,
you’ll see actual log output, like what you can see in Figure 2-3.

Figure 2-3. Logback fills your logs with verbose information because you haven’t
configured Logback yet

The log output visible in Figure 2-3 is from Netty, the server implementation used by
Ktor. In other words, what you see is the log output from a dependency of a dependency,
multiple steps away from your own code. The ability to investigate what all parts of the
system are up to is what makes logging so useful.
The most common way to set up a logging implementation is to use the info level
for all third-party code and the debug level for your own code. Debug log statements
from third-party code are usually not relevant unless you’re working on changes to that

28
Chapter 2 Setting Up the Web App Skeleton

code or you’re debugging an issue with an unknown cause. For your own code, the
debug level log output is truly relevant, as you are in fact working actively on changing
that code.
To configure Logback, you need to add an XML config file to src/main/resources/
logback.xml. Listing 2-3 shows an example of a valid Logback config file.

Listing 2-3. Logback configuration, stored in src/main/resources/logback.xml

<configuration>
  <appender
    name="STDOUT"
    class="ch.qos.logback.core.ConsoleAppender"
  >
    <encoder>
      <pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} -
%msg%n</pattern>
    </encoder>
  </appender>
  <root level="INFO">
    <appender-ref ref="STDOUT"/>
  </root>

  <logger name="kotlinbook" level="DEBUG"/>


</configuration>

The <appender> in Listing 2-3 tells Logback where to write the log output. You can
tell Logback to write to files and even send emails. Here, you configure Logback to
simply write logging output to the console. This is the most common configuration for
production setups as well, as most production environments will have facilities to make
console output available to developers.
The <root> logger in Listing 2-3 is the default logger that Logback will use for all
code – your own, as well as third-party dependencies – that does not have a specific
logger configuration. It’s set to the info level, which means Logback will only show
statements at info, warn, error, and fatal.
The statement <logger name="kotlinbook" level="DEBUG"/> in Listing 2-3
overrides the <root> logger for all logging statements coming from kotlinbook. This
means Logback will show all log statements for your own code at the debug level
and above.
29
Other documents randomly have
different content
It was, as I have said, a fine autumnal day. The sky was clear and serene.
The forests had put on their sober brown and yellow, while some trees of
the tenderer kind had been nipped by the frost into brilliant dyes of orange,
purple, and scarlet. Streaming files of wild ducks began to make their
appearance high in the air. The bark of the squirrel might be heard from the
groves of beech and hickory, and the pensive whistle of the quail at
intervals from the neighboring stubblefields.
The small birds fluttered, chirping and
frolicking from bush to bush, and tree to tree,
gay and happy because of the plenty and
variety around them. There were the twittering
blackbirds, flying in sable clouds; and the
golden-winged woodpecker, with his crimson
crest and splendid plumage; and the cedar
bird, with its red-tipped wings and yellow-
tipped tail; and the blue jay, in his gay, light-
blue coat and white underclothes, screaming
and chattering, nodding and bowing, and
pretending to be on good terms with every
songster of the grove.
As Ichabod jogged slowly on his way, his
eye ranged with delight over the treasures of
jolly autumn, On all sides he beheld vast store
of apples,—some still hanging on the trees, Ichabod and Gunpowder.
some gathered into baskets and barrels for the
market, others heaped up in rich piles for the cider press. Farther on he
beheld great fields of Indian corn, with its golden ears peeping from their
leafy coverts, and holding out the promise of cakes and hasty pudding.
There, too, were multitudes of yellow pumpkins turning up their yellow
sides to the sun, and giving ample prospects of the most luxurious of pies.
And anon he passed the fragrant buckwheat fields, breathing the odor of the
beehive; and as he beheld them, he dreamed of dainty slapjacks, well
buttered, and garnished with honey, by the delicate little dimpled hand of
Katrina, the daughter of Mynheer Van Tassel.
Thus feeding his mind with many sweet thoughts and “sugared
suppositions,” he journeyed along the sides of a range of hills which look
out upon some of the goodliest scenes of the mighty Hudson. The sun
gradually wheeled his broad disk down into the west. A few amber clouds
floated in the sky, without a breath of air to move them. The horizon was of
a fine, golden tint, changing gradually into a pure apple-green, and from
that into the deep-blue of the midheaven. A slanting ray lingered on the
woody crests of the precipices that overhung some parts of the river, giving
greater depth to the dark gray and purple of their rocky sides.

III. THE “QUILTING FROLIC.”


It was toward evening when Ichabod arrived at the castle of the Herr Van
Tassel. He found it thronged with the pride and flower of the adjacent
country,—old farmers, in homespun coats and breeches, blue stockings,
huge shoes, and magnificent pewter buckles; their brisk little dames, in
close-crimped caps, long-waisted gowns, homespun petticoats, with
scissors and pincushions, and gay calico pockets hanging on the outside;
buxom lasses, almost as antiquated as their mothers, excepting where a
straw hat, a fine ribbon, or perhaps a white frock, showed signs of city
innovations; the sons, in short, square-skirted coats with rows of huge brass
buttons, and their hair generally queued in the fashion of the times,
especially if an eel-skin could be had for that purpose, it being esteemed as
a potent nourisher and strengthener of the hair.
What a world of charms burst upon the gaze of my hero, as he entered
the state parlor of Van Tassel’s mansion—the ample charms of a Dutch
country tea table, in the sumptuous time of autumn! Such heaped-up
platters of cakes, of various and indescribable kinds, known only to
experienced Dutch housewives! There was the doughty doughnut, and the
crisp, crumbling cruller; sweet cakes and short cakes, ginger cakes and
honey cakes, and the whole family of cakes; and then there were apple pies,
and peach pies, and pumpkin pies; and slices of ham and smoked beef; and
dishes of preserved plums, and peaches, and pears, and quinces; not to
mention broiled shad and roasted chickens, together with bowls of milk and
cream; all mingled, higgledy-piggledy,—with the motherly teapot sending
up its clouds of vapor from the midst! I want breath and time to describe
this banquet as I ought, and am too eager to get on with my story. Happily,
Ichabod Crane was not in so great a hurry, but did ample justice to every
dainty.
And now, supper being ended, the sound of music from the common
room summoned to the dance. The musician was an old, gray-headed negro,
who had been the itinerant orchestra of the neighborhood for more than half
a century. His instrument was as old and battered as himself. The greater
part of the time he scraped away on two or three strings, moving his head
with every movement of the bow, and stamping his foot whenever a fresh
couple were to start.
Ichabod prided himself on his dancing. Not a limb, not a fiber about him
was idle. How could the flogger of urchins be otherwise than animated and
joyous? And pretty Katrina Van Tassel, the lady of his heart, was his partner
in the dance, smiling graciously in reply to all his gallant remarks. When
the dance was over, Ichabod joined a circle of the older folks, who, with
Mynheer Van Tassel, sat smoking at one end of the piazza, and told stories
of the war and wild and wonderful legends of ghosts and other supernatural
beings. Some mention was made of a woman in white that haunted the dark
glen at Raven Rock, and was often heard to shriek on wintry nights before a
storm, having perished there in the snow. The chief part of the stories,
however, turned upon the favorite specter of Sleepy Hollow, the headless
horseman, who had been heard several times of late, patrolling the country.
One man told how he had once met the horseman returning from a foray
into Sleepy Hollow, and was obliged to get up behind him; how they
galloped over bush and brake, over hill and swamp, until they reached the
bridge by the church, when the horseman suddenly turned into a skeleton,
threw him into the brook, and sprang away over the treetops with a clap of
thunder. A wild, roystering young man, who was called Brom Bones,
declared that the headless horseman was, after all, no rider compared with
himself. He said that returning one night from the neighboring village of
Sing Sing, he had been overtaken by this midnight trooper; that he had
offered to race with him for a bowl of punch, and would have won it, too,
but just as they came to the church bridge, the specter bolted and vanished
in a flash of fire.
The party now gradually broke up. The old
farmers gathered together their families in their
wagons, and were heard for some time rattling along
the hollow roads, and over the distant hills. Some of
the damsels mounted on pillions behind their
favorite swains; and their light-hearted laughter,
mingling with the clatter of hoofs, echoed along the
silent woodlands, growing fainter and fainter till
they gradually died away, and the late scene of noise
and frolic was all silent and deserted. Ichabod alone
lingered behind, to have a parting word with the
pretty Katrina. What he said to her, and what was her
reply, I do not know. Something, however, must
have gone wrong; for he sallied forth, after no great
length of time, with an air quite desolate and
chopfallen.

Katrina Van Tassel.

IV. THE HEADLESS HORSEMAN.


It was the very witching time of night that Ichabod pursued his travel
homewards. In the dead hush of midnight he could hear the barking of a
dog on the opposite shore of the Hudson, but it was so vague and faint as
only to give an idea of the distance between them. No signs of life occurred
near, but now and then the chirp of a cricket, or perhaps the guttural twang
of a bullfrog from a neighboring marsh, as if sleeping uncomfortably, and
turning suddenly in his bed.
All the stories that Ichabod had heard about ghosts and goblins, now
came crowding into his mind. The night grew darker and darker. The stars
seemed to sink deeper in the sky, and driving clouds occasionally hid them
from his sight. He had never felt so lonely and dismal. He was, moreover,
approaching the very place where many of the scenes of the ghost stories
had been laid. In the center of the road stood an enormous tulip tree, which
towered like a giant above all the other trees of the neighborhood, and
formed a kind of landmark. Its limbs were gnarled and fantastic, large as the
trunks of ordinary trees, twisting down almost to the ground, and rising
again into the air.
As Ichabod approached this tree, he began to whistle. He thought his
whistle was answered: it was but a blast sweeping sharply through the dry
branches. Coming a little nearer, he thought he saw something white
hanging in the midst of the tree. He paused, and ceased whistling, but, on
looking more narrowly, perceived that it was a place where the tree had
been struck by lightning, and the white wood laid bare. Suddenly he heard a
groan. His teeth chattered, and his knees smote against the saddle. It was
but the rubbing of one huge bough upon another, as they were swayed about
by the breeze. He passed the tree in safety, but new perils lay before him.
About two hundred yards from the tree a small brook crossed the road,
and ran into a marshy and thickly wooded glen. A few rough logs laid side
by side served for a bridge over this stream. To pass this bridge was the
severest trial; for it was here that the unfortunate André had been captured,
and under covert of the thicket of chestnuts and vines by the side of the
road, had the sturdy yeomen, who surprised him, lain concealed. The stream
has ever since been considered a haunted stream, and fearful are the
feelings of the schoolboy who has to pass it alone after dark.
As Ichabod approached the stream his heart began to thump. He gave his
horse half a score of kicks in the ribs, and tried to dash briskly across the
bridge; but instead of starting forward, the perverse old animal made a
lateral movement, and ran broadside against the fence. Ichabod jerked the
rein on the other side, and kicked lustily with the contrary foot. It was all in
vain. His steed started, it is true, but it was only to plunge to the opposite
side of the road into a thicket of brambles. The schoolmaster now bestowed
both whip and heel upon the ribs of old Gunpowder, who dashed forward
but came to a stand just by the bridge with a suddenness that had nearly sent
his rider sprawling over his head. Just at this moment a plashy tramp by the
side of the bridge caught the sensitive ear of Ichabod. In the dark shadow of
the trees, he beheld something huge, black, and towering. It stirred not, but
seemed gathered up in the gloom, like some gigantic monster ready to
spring upon the traveler.
The hair of the affrighted pedagogue rose upon his head with terror.
What was to be done? Summoning up a show of courage, he called out in
stammering accents, “Who are you?” He received no reply. He repeated his
demand in a still more agitated voice. Still there was no answer. Once more
he cudgeled the sides of Gunpowder, and, shutting his eyes, broke forth into
a psalm tune. Just then the shadowy object of alarm put itself in motion,
and, with a scramble and a bound, stood at once in the middle of the road.
Though the night was dark and dismal, yet the form of the unknown might
now in some degree be ascertained. He appeared to be a horseman of large
dimensions, and mounted on a horse of powerful frame. He made no offer
of molestation or sociability, but kept aloof on one side of the road, jogging
along on the blind side of old Gunpowder, who had now got over his fright
and waywardness.
Ichabod, who had no relish for this strange midnight companion, and
bethought himself of the adventure of Brom Bones and the headless
horseman, now quickened his steed, in hopes of leaving him behind. The
stranger, however, quickened his horse to an equal pace. Ichabod drew up,
and fell into a walk, thinking to lag behind; the other did the same. His heart
began to sink within him. There was something in the moody and dogged
silence of his companion that was mysterious and appalling. It was soon
fearfully accounted for.
On mounting a rising ground, which brought the figure of his fellow-
traveler in relief against the sky, Ichabod was horror-struck on perceiving
that he was headless; but his horror was still more increased on observing
that the head, which should have rested on his shoulders, was carried before
him on the pommel of his saddle. His terror rose to desperation. He rained a
shower of kicks and blows upon Gunpowder, hoping, by a sudden
movement, to give his companion the slip; but the specter started full jump
with him. Away then they dashed, through thick and thin; stones flying, and
sparks flashing, at every bound. Ichabod’s flimsy garments fluttered in the
air, as he stretched his long, lank body away over his horse’s head, in the
eagerness of his flight.
They had now reached the road which turns off to Sleepy Hollow; but
Gunpowder, who seemed possessed with a demon, instead of keeping up it,
made an opposite turn, and plunged headlong down hill to the left. This
road leads through a sandy hollow, shaded by trees for about a quarter of a
mile, where it crosses the bridge famous in goblin story; and just beyond
swells the green knoll on which stands the whitewashed church.
Just as he had got halfway through the hollow, the girths of the saddle
gave way, and Ichabod felt it slipping from under him. He seized it by the
pommel, and tried to hold it firm, but in vain. He had just time to save
himself by clasping Gunpowder round the neck, when the saddle fell to the
earth, and he heard it trampled under foot by his pursuer. For a moment the
terror of its owner’s wrath passed across his mind, for it was his Sunday
saddle; but this was no time for petty fears. He had much ado to keep his
seat, sometimes slipping on one side, sometimes on another, and sometimes
jolted on the high ridge of his horse’s backbone with a violence that was far
from pleasant.
An opening in the trees now cheered him with the hope that the church
bridge was at hand. “If I can but reach that bridge,” thought Ichabod, “I am
safe.” Just then he heard the black steed panting and blowing close behind
him. He even fancied that he felt his hot breath. Another kick in the ribs,
and old Gunpowder sprang upon the bridge; he thundered over the
resounding planks; he gained the opposite side; and now Ichabod cast a
look behind to see if his pursuer should vanish in a flash of fire and
brimstone. Just then he saw the goblin rising in his stirrups, and in the very
act of hurling his head at him. Ichabod tried to dodge the horrible missile,
but too late. It encountered his cranium with a tremendous crash. He was
tumbled headlong into the dust; and Gunpowder, the black steed, and the
goblin rider, passed by like a whirlwind.
The next morning the old horse was found without his saddle, and with
the bridle under his feet, soberly cropping the grass at his master’s gate.
Ichabod did not make his appearance at breakfast. Dinner hour came, but no
Ichabod. The boys assembled at the schoolhouse, and strolled idly about the
banks of the brook; but no schoolmaster. An inquiry was set on foot, and
after much investigation they came upon his traces. In one part of the road
by the church was found the saddle trampled in the dirt. The tracks of
horses’ hoofs deeply dented in the road, and evidently at furious speed,
were traced to the bridge, beyond which, on the bank of a broad part of the
brook, where the water ran deep and black, was found the hat of the
unfortunate Ichabod, and close beside it a shattered pumpkin. The brook
was searched, but the body of the schoolmaster was not to be discovered.
As Ichabod was a bachelor, and in nobody’s debt, nobody troubled his
head any more about him. It is true, an old farmer, who went down to New
York on a visit several years after, brought home the intelligence that
Ichabod Crane was still alive; that he had left the neighborhood, partly
through fear of the goblin and the farmer whose horse he had ridden, and
partly for other reasons; that he had changed his quarters to a distant part of
the country, had kept school and studied law at the same time, had written
for the newspapers, and finally had been made a justice of the Ten Pound
Court. Brom Bones, too, who, shortly after the schoolmaster’s
disappearance, had married the blooming Katrina Van Tassel, was observed
to look very knowing whenever the story of Ichabod was related, and
always burst into a hearty laugh at the mention of the pumpkin, which led
some to suppose that he knew more about the matter than he chose to tell.
THE MARINER’S DREAM.
In slumbers of midnight the sailor boy lay;
His hammock swung loose at the sport of the wind;
But, watchworn and weary, his cares flew away,
And visions of happiness danced o’er his mind.

He dreamed of his home, of his dear native bowers,


And pleasures that waited on life’s merry morn;
While Memory stood sideways, half covered with flowers,
And restored every rose, but secreted its thorn.

Then Fancy her magical pinions spread wide,


And bade the young dreamer in ecstasy rise:
Now far, far behind him the green waters glide,
And the cot of his forefathers blesses his eyes.

The jessamine clambers in flower o’er the thatch,


And the swallow chirps sweet from her nest in the wall;
All trembling with transport, he raises the latch,
And the voices of loved ones reply to his call.

A father bends o’er him with looks of delight;


His cheek is impearled with a mother’s warm tear;
And the lips of the boy in a love kiss unite
With the lips of the maid whom his bosom holds dear.

The heart of the sleeper beats high in his breast;


Joy quickens his pulses—all hardships seem o’er,
And a murmur of happiness steals through his rest:
“O God! thou hast blessed me; I ask for no more.”

Ah! what is that flame which now bursts on his eye?


Ah! what is that sound which now ’larums his ear?
Tis the lightning’s red gleam, painting death in the sky!
’Tis the crashing of thunders, the groan of the sphere!

He springs from his hammock—he flies to the deck!


Amazement confronts him with images dire;
Wild winds and mad waves drive the vessel a wreck;
The masts fly in splinters; the shrouds are on fire!

Like mountains the billows tremendously swell;


In vain the lost wretch calls on Mercy to save;
Unseen hands of spirits are ringing his knell,
And the death angel flaps his broad wing o’er the wave!
And the death angel flaps his broad wing o er the wave!

O sailor boy, woe to thy dream of delight!


In darkness dissolves the gay frost work of bliss.
Where now is the picture that Fancy touched bright—
Thy parents’ fond pressure, and Love’s honeyed kiss?

O sailor boy! sailor boy! never again


Shall home, love, or kindred thy wishes repay;
Unblessed, and unhonored, down deep in the main
Full many a fathom, thy frame shall decay.

Days, months, years, and ages shall circle away,


And still the vast waters above thee shall roll;
Earth loses thy pattern for ever and aye:—
O sailor boy! sailor boy! peace to thy soul!
—William Dimond.
THE SANDS O’ DEE.

“O Mary, go and call the cattle home,


And call the cattle home,
And call the cattle home,
Across the sands o’ Dee!”
The western wind was wild and dank with foam,
And all alone went she.

The creeping tide came up along the sand,


And o’er and o’er the sand,
And round and round the sand,
As far as eye could see.
The rolling mist came down and hid the land—
And never home came she.

“Oh, is it weed, or fish, or floating hair—


A tress of golden hair,
A drownèd maiden’s hair,
Above the nets at sea?”
Was never salmon yet that shone so fair
Among the stakes on Dee.

They brought her in across the rolling foam,


The cruel crawling foam,
The cruel hungry foam,
To her grave beside the sea.
But still the boatmen hear her call the cattle home,
Across the sands o’ Dee.
—Charles Kingsley.
THE INVENTION OF PRINTING.
I. BLOCK BOOKS.
Six hundred years ago every book was written by hand; for the art of
printing was then unknown, If there were pictures, they were drawn with a
pen or painted with a brush. It required a great deal of labor and time to
make a book; and when it was finished, it was so costly that only a very rich
person could afford to own it.
There were no bookstores such as we have now, and books were very
few. But in the great schools and large monasteries there were men called
scriptores, or copyists, whose business it was to make written copies of
such works as were in demand. There were other men called illuminators
who ornamented the books with beautiful initials and chapter headings, and
sometimes encircled the pages with borders made with ink of different
colors.
At last some copyist who had several copies to make of the same book
thought of a new plan. He carved a copy of each page on a block of wood.
If there was a picture, he carved that too, much in the same way that wood
engravings are made now. When the block was finished, it was carefully
wetted with a thin, inky substance; then a sheet of paper was laid upon it
and pressed down till an impression of the carved block was printed upon it.
Each page was treated in the same way, but the paper could be printed only
on one side. When all were finished, the leaves were stitched together and
made into a book. It was not as handsome a book as those written with pen
and ink; but, after the block had once been engraved, the copyist could
make fifty copies of it in less time than he could make one by hand.
Books made in this way were called block books. It required much time
and a great deal of skill to engrave the blocks; and so this method of
printing never came into very general use.

II. LAURENCE COSTER


About the beginning of the fifteenth century there lived in the old Dutch
town of Haarlem a man whose name was Laurence Jaonssen. This man was
much looked up to by all his neighbors; for he was honest and wealthy, and
he had been in his younger days the treasurer of the town. He was the
sacristan of the Church of St. Bavon, and for that reason he was called
Laurence Coster, which means Laurence the Sacristan. As he grew old and
gray, he became very quiet in his ways, and there was nothing that he liked
so well as being alone, with the bright sun above him and the trees and
flowers and birds all around him.
Every afternoon, as soon as he had dined, he threw his short black cloak
over his shoulders, took his broad-brimmed hat from its peg, and with his
staff in his hand sauntered out for a walk. Sometimes he strolled along the
banks of the broad and sluggish river, picking flowers as he went;
sometimes he rambled through the fields and came home by the great road
which led around to the other side of the town. But he liked best to go out to
the old forest which lay beyond the flat meadow lands a mile farther away.
There the trees grew large and tall, and afforded a pleasant shelter on warm
days from the sun, and in cooler weather from the keen winds that blow
across the meadows from the sea.
When tired of walking, Laurence Coster would often sit down on the
spreading root of some old beech tree; and then, to pass away the time, he
would split off a piece of the bark, and with his knife would shape it into
one of the letters of the alphabet. This was an old habit of his—a habit
which he had learned when he was a boy; and afterwards, when he was just
turning into manhood, it had been no uncommon thing for him to stroll into
the woods and carve upon the trees the name of a young maiden whom he
knew. Now, old and gray and solemn, the habit still remained with him. He
liked to sit and cut out alphabets for the amusement of his little
grandchildren to whom he carried them.
One day, having shaped the letters with more care than usual, he
wrapped them up in a piece of parchment that he had in his pocket. “The
children will be delighted with these, I know,” he said.
When he reached home and opened the package, he was surprised to see
the imprint of several of the letters very clear and distinct upon the
parchment. The sap, running out of the green bark, had acted as ink on the
face of the letters. This accident set him to thinking.
He carved another set of letters with very great care, and then, dipping
one side in ink, pressed them on a sheet of parchment. The result was a
print, almost as good as the block pictures and block books which were sold
in the shops, and were the only examples of printing then known.
“I really believe,” said Laurence Coster, “that with enough of these
letters I could print a book. It would be better than printing by the block
method; for I would not be obliged to cut a separate block for each page,
but could arrange and rearrange the letters in any order that might be
required.”
And so now, instead of idling his afternoons away, and instead of cutting
letters merely for the children, he set earnestly to work to improve his
invention. He made a kind of ink that was thicker and more gluey than
common ink, and not so likely to spread and leave an ugly blot. He carved a
great many letters of various sizes, and found that with his improved ink he
could make clear, distinct impressions, and could print entire pages, with
cuts and diagrams and fancy headings.
After a while he thought of making the letters of lead instead of wood;
and finally he found that a mixture of lead and tin was better than pure lead,
because it was harder and more durable. And so, year after year, Laurence
Coster toiled at the making of types and the printing of books. Soon his
books began to attract attention, and as they were really better and cheaper
than the block books, there was much call for them.
Some of the good people of Haarlem were greatly troubled because the
old gentleman spent so much of his time at such work.
“He is bewitched,” said some.
“He has sold himself to the evil one,” said others.
“No good thing will ever come out of this business,” said they all.

III. JOHN GUTENBERG.


One day when Laurence Coster was making his first experiments in
printing, a young traveler, with a knapsack on his back and a staff in his
hand, came trudging into Haarlem.
“My name is John Gutenberg, and my home is at Mayence,” he said to
the landlord of the inn where he stopped.
“And pray what may be your business in our good city of Haarlem?”
asked the landlord.
“I am trying to gain knowledge by seeing the world,” was the answer. “I
have been to Rome and Venice and Genoa; I have visited Switzerland and
all the great cities in Germany; and now I am on my way through Holland
to France.”
“What is the most wonderful thing that you have seen in your travels?”
asked the landlord.
“There is nothing more wonderful to me than the general ignorance of
the people,” said Gutenberg. “They seem to know nothing about the country
in which they live; they know nothing about the peoples of other lands; and,
what is worse, they know nothing about the truths of religion. If there were
only some way to make books more plentiful, so that the common people
could buy them and learn to read them, a great deal of this ignorance would
be dispelled. Ever since I was a mere youth at school, is this thought has
been in my mind.”
“Well,” said the landlord, “we have a man here in Haarlem who makes
books; and, although I know nothing about them myself, I have been told
that he makes them by a new method, and much faster and cheaper than
they have ever been made before.”
“Who is this man? Tell me where I can find him!” cried Gutenberg.
“His name is Laurence Coster, and he lives in the big house which you
see over there close by the market place. You can find him at home at all
hours of the day; for, since he got into this mad way about printing, he
never walks out.”
Gutenberg lost no time in making the acquaintance of Laurence Coster.
The kind old gentleman showed him his types, and told him all about his
plans; and when he brought out a Latin Grammar which he had just
finished, Gutenberg was filled with wonder and delight.
“This is what I have so long hoped for,” he said. “Now knowledge will
fly on the wings of truth to the uttermost parts of the earth!”
Many different stories have been told about the way in which Gutenberg
set to work to improve the art of printing. One relates that, after having
gained the confidence of Laurence Coster, he stole all his types and tools
and carried them to Mayence, where he opened a workshop of his own.
Another story is as follows:
After seeing Laurence Coster’s work, he was so impatient to be doing
something of the kind himself that he left Haarlem the next morning, and
hurried to Strasburg. There he shut himself up
in a room which he rented, and set to work to
carry out the plans which he had in mind. With
a knife and some pieces of wood he made
several sets of movable type, and arranging
them in words and sentences, strung them
together upon pieces of wire. In this way he
was able to print more rapidly than by
Laurence Coster’s method, where each letter,
or at most each word, was printed separately.
He soon set up a shop in an old ruined
monastery just outside of the town, and began
John Gutenberg. work as a jeweler. He polished precious stones,
and he dealt in mirrors which he mounted in
frames of carved wood. He did this partly to earn a livelihood, and partly to
conceal the greater projects which he had in hand. In a dark secluded corner
of the monastery he fitted up another workshop where he could secretly
carry on his experiments in printing. There, behind bolts and bars and a
thick oaken door, he spent all of his spare time with his types.
Little by little, Gutenberg made improvements in his art. He invented
methods for making letters of metal that were better than any that Laurence
Coster had used. He learned how to mix inks of various colors. He made
brushes and rollers for inking the types; “forms” for keeping the letters
together when arranged for printing; and at last a press for bringing the
paper into contact with the inked type.

IV. THE TWO VOICES.


Whether awake or asleep, John Gutenberg’s mind was always full of his
great invention. One night as he sat looking at a sheet that he had printed on
his first press, he thought that he heard two voices whispering near him.
One of the voices was soft and musical and very pleasant to hear; the other
was harsh and gruff and full of discordant tones. The gentle voice spoke
first,
“Happy, happy man!” it said, “Go on with your great work, and be not
discouraged. In the ages to come, men of all lands will gain knowledge and
become wise by means of your great invention. Books will multiply until
they are within the reach of all classes of people. Every child will learn to
read. And to the end of time, the name of John Gutenberg will be
remembered.”

Gutenberg and his Printing Press.


Drawn by Arthur I. Keller. Engraved by E. Heinemann.

Then the harsh voice spoke: “Beware! beware! and think twice of what
you are doing. Evil as well as good will come from this invention upon
which you have set your heart. Instead of being a blessing to mankind, it
will prove to be a curse. Pause and consider before you place in the hands
of sinful and erring men another instrument of evil.”
Gutenberg’s mind was filled with distress. He thought of the fearful
power which the art of printing would give to wicked men to corrupt and
debase their fellow-men. He leaped to his feet, he seized his hammer, and
had almost destroyed his types and press when the gentle voice spoke again,
and in accents loud enough to cause him to pause.
“Think a moment,” it said. “God’s gifts are all good, and yet which one
of them is not abused and sometimes made to serve the purposes of wicked
men. What will the art of printing do? It will carry the knowledge of good
into all lands; it will promote virtue; it will be a new means of giving
utterance to the thoughts of the wise and the good.”
Gutenberg threw down his hammer and set to work to repair the mischief
that he had done. But scarcely had he put his printing machine in good
order when other troubles arose. He was in debt, and he had difficulties
with the town officers. His goods were seized upon; his types were
destroyed; and he was at last obliged to return penniless to his old home in
Mayence.

V. JOHN FUST.
In Mayence, Gutenberg had an old friend named John Fust, who was a
goldsmith and very rich. With this man he soon formed a partnership, and a
printing office much better than the one at Strasburg was set up. Several
books, most of them on religious subjects, were printed and sent out, and
the business was soon in a flourishing condition.
But Gutenberg’s troubles were not yet ended. There were a great many
people who were opposed to his new way of making books. The copyists
who made their living by transcribing books were very bitter against it
because it would destroy their business. They formed a league to oppose the
printers, and before long drove Gutenberg out of Mayence.
After wandering to various places in Germany, he at last gained the
friendship of Adolphus, the Elector of Nassau, who took a great interest in
his plans. A press was set up at the court of the Elector, and there Gutenberg
worked for several years, printing volume after volume with his own hands.
But his invention did not bring him wealth. When he died at the age of
sixty-nine years, he left no property but a few books which he had printed.
His partner, John Fust, had been much more fortunate. He had set up
another press at Mayence, and in spite of the copyists and their friends was
printing many books, and reaping great profits from their sale. One summer
he printed some Bibles and took them to Paris to sell. They looked very
much like the manuscript copies made by the copyists, for it was to the
interest of the printers to pass off their books as manuscripts. People were
astonished when Fust offered to sell his Bibles at sixty crowns, while the
copyists demanded five hundred. They were still more astonished when he
produced them as fast as they were wanted, and finally lowered the price.
The copyists were very bitter against him.
“He is a magician!” they cried. “No one but a magician could do this.”
And so the officers were sent to arrest him and search his rooms. They
found a great many Bibles and some red ink.
“There is no doubt about it,” said the officers. “This is blood, and the
man is a magician.”
In order to save himself from being burned as a wizard, Fust was obliged
to go before the Parliament of Paris and tell all about his new method of
making books, and how he used the red ink for embellishing the borders of
the pages.
It was thus that the art of printing by movable types first became known
to the world.
THE WANDERER.
Upon a mountain height far from the sea
I found a shell,
And to my listening ear the lonely thing
Ever a song of ocean seemed to sing,
Ever a tale of ocean seemed to tell.

How came the shell upon that mountain height?


Ah, who can say?
Whether there dropped by some too careless hand
Or whether there cast when Ocean left the Land
Ere the Eternal had ordained the Day.

Strange, was it not? Far from its native deep


One song it sang,— Eugene Field.
Sang of the awful mysteries of the tide,
Sang of the misty sea, profound and wide,—
Ever with echoes of the ocean rang.

And, as the shell upon the mountain height


Sings of the sea,
So do I ever, leagues and leagues away,—
So do I ever, wandering where I may—
Sing, O my home! sing, O my home, of thee!
—Eugene Field.
LEAD THOU ME ON.

Lead, kindly light, amid the encircling gloom,


Lead thou me on!
The night is dark, and I am far from home,—
Lead thou me on!
Keep thou my feet; I do not ask to see
The distant scene,—one step enough for me.

I was not ever thus, nor prayed that thou


Shouldst lead me on.
I loved to choose and see my path, but now
Lead thou me on!
I loved the garish day, and, spite of fears,
Pride ruled my will: remember not past years.
Cardinal Newman.
So long thy power hath blessed me, sure it still
Will lead me on,
O’er moor and fen, o’er crag and torrent, till
The night is gone;
And with the morn those angel faces smile
Which I have loved long since, and lost a while.
—John Henry Newman.
THE AMERICAN INDIAN.
Not many generations ago, where you now sit, encircled with all that
exalts and embellishes civilized life, the rank thistle nodded in the wind,
and the wild fox dug his hole unscared. Here lived and loved another race
of beings. Beneath the same sun that rolls over your heads, the Indian
hunter pursued the panting deer; gazing on the same moon that smiles for
you, the Indian lover wooed his dusky mate.
Here the wigwam blaze beamed on the tender and helpless, the council
fire glared on the wise and daring. Now they dipped their noble limbs in
your sedgy lakes, and now they paddled the light canoe along your rocky
shores. Here they warred; the echoing whoop, the bloody grapple, the
defying death song, all were here; and, when the tiger strife was over, here
curled the smoke of peace.
Here, too, they worshiped; and from many a dark bosom went up a pure
prayer to the Great Spirit. He had not written his laws for them on tables of
stone, but he had traced them on the tables of their hearts. The poor child of
nature knew not the God of revelation, but the God of the universe he
acknowledged in everything around.
He beheld him in the star that sank in beauty behind his lonely dwelling;
in the sacred orb that flamed on him from his midday throne; in the flower
that snapped in the morning breeze; in the lofty pine, that defied a thousand
whirlwinds; in the timid warbler that never left its native grove; in the
fearless eagle whose untired pinion was wet in clouds; in the worm that
crawled at his foot; and in his own matchless form, glowing with a spark of
that light, to whose mysterious Source he bent, in humble, though blind,
adoration.
And all this has passed away. Across the ocean came a pilgrim bark,
bearing the seeds of life and death. The former were sown for you; the latter
sprang up in the path of the simple native. Two hundred years have changed
the character of a great continent, and blotted, forever, from its face a whole
peculiar people. Art has usurped the bowers of nature, and the anointed
children of education have been too powerful for the tribes of the ignorant.
Here and there, a stricken few remain; but how unlike their bold,
untamed, untamable progenitors! The Indian of falcon glance and lion
bearing, the theme of the touching ballad, the hero of the pathetic tale, is
gone! and his degraded offspring crawl upon the soil where he walked in
majesty, to remind us how miserable is man, when the foot of the conqueror
is on his neck.
As a race, they have withered from the land. Their arrows are broken,
their springs are dried up, their cabins are in the dust. Their council fire has
long since gone out on the shore, and their war cry is fast dying to the
untrodden west. Slowly and sadly they climb the distant mountains. They
are shrinking before the mighty tide which is pressing them away; they
must soon hear the roar of the last wave, which will settle over them
forever.
Ages hence, the inquisitive white man, as he stands by some growing
city, will ponder on the structure of their disturbed remains, and wonder to
what manner of person they belonged. They will live only in the songs and
chronicles of their exterminators. Let these be faithful to their rude virtues
as men, and pay due tribute to their unhappy fate as a people.
—Charles Sprague.
THE PASSING OF KING ARTHUR.
Whether there ever was a real King Arthur, or whether he lived only in
the imagination of story-tellers and song writers, no one can tell. This much
is true, however, that the history of his exploits and those of his Knights of
the Round Table has existed in poetry and song for now almost a thousand
years.
Long before there were any English books worth speaking of, the story
of King Arthur was sung and recited by wandering bards to delighted
listeners in the halls and castles of Old England. In the course of time it was
written down in poetry and in prose; it was turned into French, and from the
French back into English again; other stories were added to it, and it
became the most popular romance ever composed. In 1470, a knight whose
name was Sir Thomas Malory made a version of it in what was then good
English prose, taking it, as he said, “out of a certain book of French.” This
version has ever since been the one book to which all who would know the
story of King Arthur have turned; it is the mine from which later writers
have derived materials for their works. It is written in a style which,
although old-fashioned and quaint, is wonderfully simple and beautiful.
One of the most touching passages in the story is that which tells how
King Arthur, having fought his last battle, lay wounded upon the ground;
and how, being deserted by all the knights except Sir Bedivere, he waited
for the coming of fairy messengers to bear him away to the island valley of
Avilion. Here is the passage, not in the exact words of Sir Thomas Malory,
but repeated, somewhat after his manner, in words of modern usage.
“My hour is near at hand,” said the king to Sir Bedivere. “Therefore,
take thou my good sword Excalibur, and go with it to yonder water side;
and when thou comest there, I charge thee throw it in that water, and then
come and tell me what thou hast seen.”
“My lord,” said Sir Bedivere, “your bidding shall be done, and I will
come quickly and bring you word.”
So Sir Bedivere departed, and as he went he looked at that noble sword,
and saw that the hilt and guard were covered with precious stones; and then
he said to himself, “If I throw this rich sword into the water, no good shall
ever come of it, but only harm and loss.”
Then Sir Bedivere hid Excalibur under a tree. And as soon as he might,
he came again unto the king, and said he had been at the water side, and had
thrown the sword into the water.
“What sawest thou there?” said the king.
“Sir, I saw nothing but waves and winds.”
“Thou speakest not the truth,” said the king. “Therefore, go quickly
again and do my bidding; and as thou art dear to me, spare not, but throw
the sword in.”
Then Sir Bedivere returned again, and took the sword in his hand. But
when he looked at it he thought it a sin and a shame to throw away so noble
a sword. And so, after he had hidden it again, he came back and told the
king that he had been at the water and had done his bidding.
“What sawest thou there?” said the king.

And there came an arm and a hand above the


water.

“Sir,” he said, “I saw nothing but the waves lapping on the beach, and
the water rising and falling among the reeds.”
“Ah, traitor untrue,” said King Arthur, “now thou hast betrayed me
twice. Who would have thought that thou, who hast been so near and dear
to me and art called a noble knight, would betray me for the riches of the
sword? But now go again quickly, for I am chilled with cold, and my life is
in danger through thy long delay. And if thou dost not do my bidding, and I
ever see thee again, I will slay thee with my own hands; for thou, for the
sake of my rich sword, would see me dead.”
Then Sir Bedivere departed; and he quickly took the sword and went to
the water side. Then he wrapped the belt about the hilt, and threw the sword
as far into the water as he could. And there came an arm and a hand above
the water, and caught the sword, and shook it thrice and brandished it. Then
the hand, with the sword, vanished in the water. So Sir Bedivere came again
to the king and told him what he had seen.
“Alas,” said the king, “help me from this place; for I fear that I have
tarried too long.”
Then Sir Bedivere took the king upon his back, and carried him to the
water side. And when they came to the water, a little barge was seen
floating close by the bank; and in the barge were many fair ladies, and
among them was a queen. All these wept and cried out when they saw King
Arthur.
“Now put me into the barge,” said the king; and this Sir Bedivere did,
with tenderness and care.
And three of the fair ladies received him with great mourning. Then that
one who was the queen said: “Ah, dear brother, why have you staid so
long? Alas, I fear lest this wound on your head has been chilled over much
with the cold!”
Then they rowed from the land, and Sir Bedivere watched them. And he
cried: “Ah, my lord Arthur! What shall become of me, now you go away
and leave me here alone among my enemies?”
“Comfort thyself,” said the king, “and do the best thou canst, for I can no
longer give thee help. For I go now into the vale of Avilion, to heal me of
my grievous wound. If thou never hear more of me, pray for my soul.”
But the ladies and the queen wept and cried in a way that was piteous to
hear. And when Sir Bedivere lost sight of the barge, he wept bitterly; and,
weeping, he went into the forest, where he wandered all that long night.
“Some men yet say,” continues Sir Thomas Malory, “that King Arthur is
not dead, but taken by the will of our Lord into another place. And men say
that he shall come again and shall win the holy cross. I will not say it shall
be so, but rather I will say that in this world he changed his life. But many
men say that there is written upon his tomb a verse in Latin, which when
turned into English, is this: ‘Here lieth Arthur, that was and is to be King.’ ”
BIOGRAPHICAL NOTES.
George Bancroft: An American historian. Born at Worcester,
Massachusetts, 1800; died, 1891. Wrote “History of the United States from
the Discovery of the Continent” (10 vols.).
Daniel Boone: The pioneer of Kentucky. Born in Pennsylvania, 1735;
died in Missouri, 1820.
William Cullen Bryant: An eminent American poet. Born in
Massachusetts, 1794; died, 1878. Wrote “Thanatopsis” and many other
short poems. Was one of the editors of the “Evening Post” (New York) for
more than fifty years.
John C. Calhoun: An eminent American statesman and orator. Born in
South Carolina, 1782; died, 1850.
Richard Henry Dana, Jr.: An American lawyer and author. Born at
Cambridge, Massachusetts, 1815; died, 1868.
Charles Dickens: An English novelist. Born at Landport, England,
1812; died, 1870. His best novel is generally conceded to be “David
Copperfield.”
William Dimond: An English poet, remembered only for his “Mariner’s
Dream.” Died, about 1837.
Eugene Field: An American author. Born in St. Louis, 1850; died in
Chicago, 1895. Wrote “A Little Book of Western Verse,” “A Little Book of
Profitable Tales,” etc.
Robert Fulton: An American inventor. Born in Lancaster County,
Pennsylvania, 1765; died, 1815.
Charles E. A. Gayarré: An American historian. Born in Louisiana,
1805; died, 1895. Wrote a “History of Louisiana,” and several other works.
Sir Archibald Geikie: A Scottish geologist. Born in Edinburgh, 1835.
Has written “The Story of a Boulder,” “A Class Book of Physical
Geography,” and many other popular and scientific works on geological
subjects.
Thomas Grimke: An American lawyer and philanthropist. Born in
South Carolina, 1786; died, 1834.
Nathaniel Hawthorne: A distinguished American author. Born at
Salem, Massachusetts, 1804; died, 1864. Wrote “The Scarlet Letter,” “The
Marble Faun,” “The House of the Seven Gables,” “The Wonder Book,”
“Tanglewood Tales,” etc. His style has been said to possess “almost every
excellence—elegance, simplicity, grace, clearness, and force.”
Homer: The reputed author of the two great poems, the “Iliad” and the
“Odyssey.” Supposed to have been born at Smyrna, or Chios, about one
thousand years before Christ. The “Iliad” has been called “the beginning of
all literature.”
Washington Irving: An American author and humorist. Born in New
York, 1783; died, 1859. Wrote “The Sketch Book,” “History of New York
by Diedrich Knickerbocker,” “Tales of a Traveler,” “The Alhambra,”
“Columbus and his Companions,” “Mahomet and his Successors,” and
many other works.
Charles Kingsley: An English clergyman and writer. Born in
Devonshire, 1819; died, 1875. Wrote “Hypatia,” “Westward Ho!” “The
Heroes,” “The Water Babies,” “Alton Locke, Tailor and Poet,” “Madame
How and Lady Why,” several poems, and a volume of sermons.
Sir Edwin Landseer: The most famous of modern painters of animals.
Born in London, 1802; died, 1873. His pictures of dogs and horses have
seldom, if ever, been surpassed.
Edward George Bulwer-Lytton, Baron Lytton: A British novelist and
poet. Born in Norfolk, England, 1803; died, 1873. Wrote “The Last Days of
Pompeii,” “The Caxtons,” “My Novel,” and many other novels; also,
several volumes of poems, and two dramas, “The Lady of Lyons” and
“Richelieu.”
Sir Thomas Malory: A Welsh or English Knight, remembered for his
noble prose epic, “Morte d’Arthur,” which he translated from the French.
Born, about 1430.
John Henry Newman: An eminent English theologian. Born in London,
1801; died, 1890. Wrote many religious and controversial works, and a few
beautiful hymns. In 1879 he was made cardinal-deacon in the Roman
Catholic Church.
John Ruskin: A distinguished English author and art critic. Born in
London, 1819; died, 1900. Wrote “The Stones of Venice,” “Sesame and
Lilies,” “Ethics of the Dust,” “The Queen of the Air,” “Modern Painters,”
and many other works, chiefly on subjects connected with art.
Sir Walter Scott: A celebrated novelist and poet. Born in Edinburgh,
Scotland, 1771; died, 1832. Wrote the “Waverley Novels,” “The Lay of the
Last Minstrel,” “The Lady of the Lake,” “Tales of a Grandfather,” and
many other works.
Charles Sprague: An American poet. Born in Boston, 1791; died 1875.
Wrote several short poems, most of which are now forgotten.
Alfred, Lord Tennyson: Poet laureate of England. Born in Lincolnshire,
1809; died, 1892. Wrote “Idylls of the King,” “In Memoriam,” “The
Princess,” and many shorter poems; also the dramas “Queen Mary,”
“Harold,” and “Becket.”
Daniel Webster: American statesman and orator. Born in New
Hampshire, 1782; died, 1852. His most famous orations are those on
Bunker Hill, Adams and Jefferson, and his “Reply to Hayne.”
John Greenleaf Whittier: A distinguished American poet. Born at
Haverhill, Massachusetts, 1807; died, 1892. Wrote many volumes of poetry,
including “In War Time,” “Snow-Bound,” “Mabel Martin,” “The King’s
Missive,” and others.
Samuel Woodworth: An American journalist and poet. Born in
Massachusetts, 1785; died, 1842. He is remembered chiefly for his little
poem “The Old Oaken Bucket.”
WORD LIST.
THE MOST DIFFICULT WORDS IN THE PRECEDING LESSONS
PRONOUNCED AND DEFINED.

KEY TO THE MARKS OF PRONUNCIATION.


ā, ē, ī, ō, ū, long; ă, ĕ, ĭ, ŏ, ŭ, y̆ , short; câre, ärm, ȧsk, ạll; fĕrn; fôrm,
sȯn; rṳde, fṳll, ûrn; fōōd, bŏŏk; çinder; ġentle; chasm; thin; them; iṉk.

a băn´don. To give up; relinquish.


ăb´bot. The ruler of an abbey.
a brĭdged´. Shortened.
a by̆ ss´. A bottomless gulf.
ac çĕl´erated. Quickened; hastened.
ăc´ çi dent. A sudden and unexpected event.
a chiēved´. Done; accomplished.
acknowl´edged (ăk nŏl´ĕjd). Assented to; owned as a fact.
ăd mi rā´tion. Wonder and delight.
ăf fĕct´ed. Moved; influenced.
ăġ i tā´tion. Emotion; excitement.
a lōōf´. Away from.
a māze´ment. Wonder; astonishment.
ăm´ber. Yellowish.
ăm´bling. Going at an easy gait.
ăm mu nĭ´tion. Articles used in charging firearms.
ăm´ple. Sufficient. “Ample prospects” = wide or extended views.
a nŏn´. “Ever and anon” = frequently; often.
ăn´ti quāt ed. Old-fashioned.
an tique´ (ăn tēēk´). Old; ancient.
ăn´tlered. Having horns like a deer.
ăp pạll´ing. Terrible; fearful.
ăp pâr´ent ly. Clearly; seemingly.
ăp pa rĭ´tion. A wonderful appearance; a ghost.
ăp pli cā´tion (of the rod). The act of laying on.
Welcome to our website – the perfect destination for book lovers and
knowledge seekers. We believe that every book holds a new world,
offering opportunities for learning, discovery, and personal growth.
That’s why we are dedicated to bringing you a diverse collection of
books, ranging from classic literature and specialized publications to
self-development guides and children's books.

More than just a book-buying platform, we strive to be a bridge


connecting you with timeless cultural and intellectual values. With an
elegant, user-friendly interface and a smart search system, you can
quickly find the books that best suit your interests. Additionally,
our special promotions and home delivery services help you save time
and fully enjoy the joy of reading.

Join us on a journey of knowledge exploration, passion nurturing, and


personal growth every day!

ebookmasss.com

You might also like