Zero To Production In Rust: An introduction to backend development (Updated)

This document was uploaded by one of our users. The uploader already confirmed that they had the permission to publish it. If you are author/publisher or own the copyright of this documents, please report to us by using this DMCA report form.

Simply click on the Download Book button.

Yes, Book downloads on Ebookily are 100% Free.

Sometimes the book is free on Amazon As well, so go ahead and hit "Search on Amazon"

Zero To Production is the ideal starting point for your journey as a Rust backend developer. You will learn by doing: you will build a fully functional email newsletter API, starting from scratch. You'll learn how to Navigate and leverage Rust's crates ecosystem Structure your application to make it modular and extensible Write tests, from single units to full-blown integration tests Enforce your domain invariants using Rust's type system Authenticate and authorize users of your API Implement a robust error handling strategy Observe the state of your application using structured logs Set up an extensive continuous integration and continuous deployment pipeline for your Rust projects The book is composed of 11 chapters, for a grand total of 600 pages. All supporting code (including tests!) is available on GitHub.

Author(s): Luca Palmieri
Year: 2023

Language: English
Pages: 530

Zero To Production In Rust
Zero To Production In Rust
Foreword
Preface
What Is This Book About
Cloud-native applications
Working in a team
Who Is This Book For
1 Getting Started
1.1 Installing The Rust Toolchain
1.1.1 Compilation Targets
1.1.2 Release Channels
1.1.3 What Toolchains Do We Need?
1.2 Project Setup
1.3 IDEs
1.3.1 Rust-analyzer
1.3.2 IntelliJ Rust
1.3.3 What Should I Use?
1.4 Inner Development Loop
1.4.1 Faster Linking
1.4.2 cargo-watch
1.5 Continuous Integration
1.5.1 CI Steps
1.5.2 Ready-to-go CI Pipelines
2 Building An Email Newsletter
2.1 Our Driving Example
2.1.1 Problem-based Learning
2.2 What Should Our Newsletter Do?
2.2.1 Capturing Requirements: User Stories
2.3 Working In Iterations
2.3.1 Coming Up
2.4 Checking Your Progress
3 Sign Up A New Subscriber
3.1 Our Strategy
3.2 Choosing A Web Framework
3.3 Our First Endpoint: A Basic Health Check
3.3.1 Wiring Up actix-web
3.3.2 Anatomy Of An actix-web Application
3.3.3 Implementing The Health Check Handler
3.4 Our First Integration Test
3.4.1 How Do You Test An Endpoint?
3.4.2 Where Should I Put My Tests?
3.4.3 Changing Our Project Structure For Easier Testing
3.5 Implementing Our First Integration Test
3.5.1 Polishing
3.6 Refocus
3.7 Working With HTML Forms
3.7.1 Refining Our Requirements
3.7.2 Capturing Our Requirements As Tests
3.7.3 Parsing Form Data From A POST Request
3.8 Storing Data: Databases
3.8.1 Choosing A Database
3.8.2 Choosing A Database Crate
3.8.3 Integration Testing With Side-effects
3.8.4 Database Setup
3.8.5 Writing Our First Query
3.9 Persisting A New Subscriber
3.9.1 Application State In actix-web
3.9.2 actix-web Workers
3.9.3 The Data Extractor
3.9.4 The INSERT Query
3.10 Updating Our Tests
3.10.1 Test Isolation
3.11 Summary
4 Telemetry
4.1 Unknown Unknowns
4.2 Observability
4.3 Logging
4.3.1 The log Crate
4.3.2 actix-web’s Logger Middleware
4.3.3 The Facade Pattern
4.4 Instrumenting POST /subscriptions
4.4.1 Interactions With External Systems
4.4.2 Think Like A User
4.4.3 Logs Must Be Easy To Correlate
4.5 Structured Logging
4.5.1 The tracing Crate
4.5.2 Migrating From log To tracing
4.5.3 tracing’s Span
4.5.4 Instrumenting Futures
4.5.5 tracing’s Subscriber
4.5.6 tracing-subscriber
4.5.7 tracing-bunyan-formatter
4.5.8 tracing-log
4.5.9 Removing Unused Dependencies
4.5.10 Cleaning Up Initialisation
4.5.11 Logs For Integration Tests
4.5.12 Cleaning Up Instrumentation Code - tracing::instrument
4.5.13 Protect Your Secrets - secrecy
4.5.14 Request Id
4.5.15 Leveraging The tracing Ecosystem
4.6 Summary
5 Going Live
5.1 We Must Talk About Deployments
5.2 Choosing Our Tools
5.2.1 Virtualisation: Docker
5.2.2 Hosting: DigitalOcean
5.3 A Dockerfile For Our Application
5.3.1 Dockerfiles
5.3.2 Build Context
5.3.3 Sqlx Offline Mode
5.3.4 Running An Image
5.3.5 Networking
5.3.6 Hierarchical Configuration
5.3.7 Database Connectivity
5.3.8 Optimising Our Docker Image
5.4 Deploy To DigitalOcean Apps Platform
5.4.1 Setup
5.4.2 App Specification
5.4.3 How To Inject Secrets Using Environment Variables
5.4.4 Connecting To Digital Ocean’s Postgres Instance
5.4.5 Environment Variables In The App Spec
5.4.6 One Last Push
6 Reject Invalid Subscribers #1
6.1 Requirements
6.1.1 Domain Constraints
6.1.2 Security Constraints
6.2 First Implementation
6.3 Validation Is A Leaky Cauldron
6.4 Type-Driven Development
6.5 Ownership Meets Invariants
6.5.1 AsRef
6.6 Panics
6.7 Error As Values - Result
6.7.1 Converting parse To Return Result
6.8 Insightful Assertion Errors: claims
6.9 Unit Tests
6.10 Handling A Result
6.10.1 match
6.10.2 The ? Operator
6.10.3 400 Bad Request
6.11 The Email Format
6.12 The SubscriberEmail Type
6.12.1 Breaking The Domain Sub-Module
6.12.2 Skeleton Of A New Type
6.13 Property-based Testing
6.13.1 How To Generate Random Test Data With fake
6.13.2 quickcheck Vs proptest
6.13.3 Getting Started With quickcheck
6.13.4 Implementing The Arbitrary Trait
6.14 Payload Validation
6.14.1 Refactoring With TryFrom
6.15 Summary
7 Reject Invalid Subscribers #2
7.1 Confirmation Emails
7.1.1 Subscriber Consent
7.1.2 The Confirmation User Journey
7.1.3 The Implementation Strategy
7.2 EmailClient, Our Email Delivery Component
7.2.1 How To Send An Email
7.2.2 How To Write A REST Client Using reqwest
7.2.3 How To Test A REST Client
7.2.4 First Sketch Of EmailClient::send_email
7.2.5 Tightening Our Happy Path Test
7.2.6 Dealing With Failures
7.3 Skeleton And Principles For A Maintainable Test Suite
7.3.1 Why Do We Write Tests?
7.3.2 Why Don’t We Write Tests?
7.3.3 Test Code Is Still Code
7.3.4 Our Test Suite
7.3.5 Test Discovery
7.3.6 One Test File, One Crate
7.3.7 Sharing Test Helpers
7.3.8 Sharing Startup Logic
7.3.9 Build An API Client
7.3.10 Summary
7.4 Refocus
7.5 Zero Downtime Deployments
7.5.1 Reliability
7.5.2 Deployment Strategies
7.6 Database Migrations
7.6.1 State Is Kept Outside The Application
7.6.2 Deployments And Migrations
7.6.3 Multi-step Migrations
7.6.4 A New Mandatory Column
7.6.5 A New Table
7.7 Sending A Confirmation Email
7.7.1 A Static Email
7.7.2 A Static Confirmation Link
7.7.3 Pending Confirmation
7.7.4 Skeleton of GET /subscriptions/confirm
7.7.5 Connecting The Dots
7.7.6 Subscription Tokens
7.8 Database Transactions
7.8.1 All Or Nothing
7.8.2 Transactions In Postgres
7.8.3 Transactions In Sqlx
7.9 Summary
8 Error Handling
8.1 What Is The Purpose Of Errors?
8.1.1 Internal Errors
8.1.2 Errors At The Edge
8.1.3 Summary
8.2 Error Reporting For Operators
8.2.1 Keeping Track Of The Error Root Cause
8.2.2 The Error Trait
8.3 Errors For Control Flow
8.3.1 Layering
8.3.2 Modelling Errors as Enums
8.3.3 The Error Type Is Not Enough
8.3.4 Removing The Boilerplate With thiserror
8.4 Avoid “Ball Of Mud” Error Enums
8.4.1 Using anyhow As Opaque Error Type
8.4.2 anyhow Or thiserror?
8.5 Who Should Log Errors?
8.6 Summary
9 Naive Newsletter Delivery
9.1 User Stories Are Not Set In Stone
9.2 Do Not Spam Unconfirmed Subscribers
9.2.1 Set Up State Using The Public API
9.2.2 Scoped Mocks
9.2.3 Green Test
9.3 All Confirmed Subscribers Receive New Issues
9.3.1 Composing Test Helpers
9.4 Implementation Strategy
9.5 Body Schema
9.5.1 Test Invalid Inputs
9.6 Fetch Confirmed Subscribers List
9.7 Send Newsletter Emails
9.7.1 context Vs with_context
9.8 Validation Of Stored Data
9.8.1 Responsibility Boundaries
9.8.2 Follow The Compiler
9.8.3 Remove Some Boilerplate
9.9 Limitations Of The Naive Approach
9.10 Summary
10 Securing Our API
10.1 Authentication
10.1.1 Drawbacks
10.1.2 Multi-factor Authentication
10.2 Password-based Authentication
10.2.1 Basic Authentication
10.2.2 Password Verification - Naive Approach
10.2.3 Password Storage
10.2.4 Do Not Block The Async Executor
10.2.5 User Enumeration
10.3 Is it safe?
10.3.1 Transport Layer Security (TLS)
10.3.2 Password Reset
10.3.3 Interaction Types
10.3.4 Machine To Machine
10.3.5 Person Via Browser
10.3.6 Machine to machine, on behalf of a person
10.4 Interlude: Next Steps
10.5 Login Forms
10.5.1 Serving HTML Pages
10.6 Login
10.6.1 HTML Forms
10.6.2 Redirect On Success
10.6.3 Processing Form Data
10.6.4 Contextual Errors
10.7 Sessions
10.7.1 Session-based Authentication
10.7.2 Session Store
10.7.3 Choosing A Session Store
10.7.4 actix-session
10.7.5 Admin Dashboard
10.8 Seed Users
10.8.1 Database Migration
10.8.2 Password Reset
10.9 Refactoring
10.9.1 How To Write An actix-web Middleware
10.10 Summary
11 Fault-tolerant Workflows
11.1 POST /admin/newsletters - A Refresher
11.2 Our Goal
11.3 Failure Modes
11.3.1 Invalid Inputs
11.3.2 Network I/O
11.3.3 Application Crashes
11.3.4 Author Actions
11.4 Idempotency: An Introduction
11.4.1 Idempotency In Action: Payments
11.4.2 Idempotency Keys
11.4.3 Concurrent Requests
11.5 Requirements As Tests #1
11.6 Implementation Strategies
11.6.1 Stateful Idempotency: Save And Replay
11.6.2 Stateless Idempotency: Deterministic Key Generation
11.6.3 Time Is a Tricky Beast
11.6.4 Making A Choice
11.7 Idempotency Store
11.7.1 Which Database Should We Use?
11.7.2 Schema
11.8 Save And Replay
11.8.1 Read Idempotency Key
11.8.2 Retrieve Saved Responses
11.8.3 Save Responses
11.9 Concurrent Requests
11.9.1 Requirements As Tests #2
11.9.2 Synchronization
11.10 Dealing With Errors
11.10.1 Distributed Transactions
11.10.2 Backward Recovery
11.10.3 Forward Recovery
11.10.4 Asynchronous Processing
11.11 Epilogue