Table of Contents for
Building Enterprise JavaScript Applications

Version ebook / Retour

Cover image for bash Cookbook, 2nd Edition Building Enterprise JavaScript Applications by Daniel Li Published by Packt Publishing, 2018
  1. Building Enterprise JavaScript Applications
  2. Title Page
  3. Copyright and Credits
  4. Building Enterprise JavaScript Applications
  5. Dedication
  6. Packt Upsell
  7. Why subscribe?
  8. PacktPub.com
  9. Contributors
  10. About the author
  11. About the reviewer
  12. Packt is searching for authors like you
  13. Table of Contents
  14. Preface
  15. Who this book is for
  16. What this book covers
  17. Section 1 – Theory and practice
  18. Section 2 – Developing our backend API
  19. Section 3 – Developing our frontend UI
  20. Section 4 – Infrastructure and automation
  21. Section 5 – Important JavaScript concepts and syntax
  22. What is not covered
  23. To get the most out of this book
  24. Download the example code files
  25. Conventions used
  26. Get in touch
  27. Reviews
  28. The Importance of Good Code
  29. Technical debt
  30. What is technical debt?
  31. Causes of technical debt
  32. The debt spiral
  33. Consequences of technical debt
  34. Technical debt leads to low morale
  35. Consequences of low morale
  36. Repaying technical debt through refactoring
  37. Preventing technical debt
  38. Informing the decision makers
  39. The triple constraint
  40. The fallacy of the triple constraint
  41. Refuse to develop
  42. Don't be a hero
  43. Defining processes
  44. Test-Driven Development
  45. Understanding the TDD process
  46. Fixing bugs
  47. Benefits of TDD
  48. Avoiding manual tests
  49. Tests as specification
  50. Tests as documentation
  51. Short development cycles
  52. Difficulties with TDD adoption
  53. When not to use TDD
  54. Summary
  55. The State of JavaScript
  56. Evolution of the web application
  57. Just-in-time (JIT) compilers
  58. Single page applications (SPAs)
  59. Isomorphic JavaScript applications
  60. Benefits of Node.js
  61. Context switching
  62. Switching between projects
  63. Switching between languages
  64. The business perspective
  65. Shared code
  66. Summary
  67. Managing Version History with Git
  68. Setting up Git
  69. Creating a new repository
  70. Configuring Git
  71. Configuring a user
  72. Learning the basics
  73. Committing to history
  74. Understanding file states in Git
  75. The three tracked states
  76. Staging our changes
  77. Quick recap
  78. Branching and merging
  79. Git branches
  80. Branching models
  81. The Driessen model
  82. Creating a development branch
  83. Creating feature branches
  84. Naming sub-branches
  85. Merging branches
  86. Examining more realistic examples
  87. Keeping the dev Branch Bug-Free
  88. Keeping our history clean
  89. Keeping our history clean with git rebase
  90. Using merge and rebase together
  91. Releasing code
  92. Semantic versioning
  93. Creating a release branch
  94. Tagging releases
  95. Hotfixes
  96. Working with others
  97. Creating a remote repository
  98. Pulling and pushing
  99. Cloning a repository
  100. Conducting peer review through pull requests
  101. Summary
  102. Setting Up Development Tools
  103. What is Node.js?
  104. Terminology
  105. Modules
  106. The dawn of modules
  107. The birth of Node.js modules
  108. Adoption of the CommonJS standard
  109. Fulfilling the encapsulation requirement
  110. Standardizing module formats
  111. Installing Node
  112. Using nvm to install Node
  113. Documenting Node versions
  114. Starting projects with npm
  115. Using yarn instead of npm
  116. Package version locking
  117. Offline cache
  118. Speed
  119. Installing yarn
  120. Getting familiar with the yarn CLI
  121. npm and yarn, together
  122. Creating an HTTP server
  123. Our HTTP server in detail
  124. Transpiling ES6 with Babel
  125. Babel is a transpiler...and more!
  126. Different faces of Babel
  127. @babel/cli
  128. @babel/register
  129. Using @babel/register for tests
  130. @babel/node
  131. @babel/core
  132. @babel/polyfill
  133. Adding Babel CLI and polyfill
  134. Using Babel CLI to transpile our code
  135. Plugins and presets
  136. The env preset
  137. Separating source and distribution code
  138. Importing the Babel polyfill
  139. Consolidating commands with npm scripts
  140. Ensuring cross-platform compatibility
  141. Automating development using nodemon
  142. Linting with ESLint
  143. Installing ESLint
  144. Linting our code
  145. Adding lint script to package.json
  146. Installing the ESLint extension
  147. Adding pre-commit hooks
  148. Committing our code into Git
  149. Using .gitignore to ignore files
  150. Summary
  151. Writing End-to-End Tests
  152. Understanding different types of test
  153. Structuring our test suite with the testing pyramid
  154. When implementing a new feature, write your E2E tests first
  155. Following a TDD workflow
  156. Gathering business requirements
  157. Formalizing requirements through documentation
  158. Refining requirements into specification
  159. Writing tests as specification
  160. Test-driven development
  161. Writing manual tests
  162. Exploratory testing
  163. Maintenance
  164. Gathering requirements
  165. Setting Up E2E tests with Cucumber
  166. Features, scenarios, and steps
  167. Gherkin keywords
  168. Specifying our feature
  169. Writing our first scenario
  170. Laying out our step definitions
  171. Running our scenarios
  172. Implementing step definitions
  173. Calling our endpoint
  174. Asserting results
  175. Using a debugger for Node.js debugging
  176. Using Chrome DevTools
  177. Using ndb
  178. Using the Visual Studio Code debugger
  179. Retaining line numbers
  180. Examining the req object
  181. Making work-in-progress (WIP) commits
  182. Asserting the correct response status code
  183. You ain't gonna need it (YAGNI)
  184. Asserting the correct response payload
  185. Asserting the correct response payload content
  186. Refactoring
  187. Isolating contexts for each scenario
  188. Making failure more informative
  189. Removing hardcoded values
  190. Validating data type
  191. Refactoring our tests
  192. Using scenario outlines
  193. Combining duplicate step definitions
  194. Refactoring our application
  195. Choosing a framework
  196. Migrating our API to Express
  197. (Re)defining routes
  198. Using body-parser middleware
  199. Run E2E test
  200. Moving common logic into middleware
  201. Validating our payload
  202. Checking for required fields
  203. Checking property type
  204. Checking the payload property's format
  205. Refactoring our step definitions
  206. Testing the success scenario
  207. Summary
  208. Storing Data in Elasticsearch
  209. Introduction to Elasticsearch
  210. Elasticsearch versus other distributed document store
  211. Installing Java and Elasticsearch
  212. Installing Java
  213. Installing and starting Elasticsearch
  214. Understanding key concepts in Elasticsearch
  215. Elasticsearch is a JSON document store
  216. Document vs. relationship data storage
  217. Understanding indices, types, documents, and versions
  218. Querying Elasticsearch from E2E tests
  219. Indexing documents to Elasticsearch
  220. Cleaning up after our tests
  221. Deleting our test user
  222. Improving our testing experience
  223. Running tests in a test database
  224. Separating development and testing servers
  225. Making a standalone E2E test script
  226. The shebang interpreter directive
  227. Ensuring Elasticsearch is running
  228. Running the test API server in the background
  229.  Checking our API server is ready
  230. Checking API status using netstat/ss
  231. Cleaning up the background process
  232. Running our tests
  233. Summary
  234. Modularizing Our Code
  235. Modularizing our code
  236. Modularizing our middleware
  237. Modularizing our request handlers
  238. The single responsibility principle
  239. Decoupling our validation logic
  240. Creating the ValidationError interface
  241. Modularizing our validation logic
  242. Creating engines
  243. Adding a user profile
  244. Writing a specification as a test
  245. Schema-based validation
  246. Types of schema
  247. Picking an object schema and validation library
  248. Interoperability
  249. Expressiveness
  250. Creating our profile schema
  251. Rejecting additional properties
  252. Dynamic mapping in Elasticsearch
  253. Adding specificity to a sub-schema
  254. Adding a title and description
  255. Specifying a meta-schema
  256. Specifying a unique ID
  257. Creating a schema for the Create User request payload
  258. Picking a JSON Schema validation library
  259. Validating against JSON Schema with Ajv
  260. Generating validation error messages
  261. Generalizing functions
  262. Updating the npm build script
  263. Testing the success scenario
  264. Resetting our test index
  265. Summary
  266. Writing Unit/Integration Tests
  267. Picking a testing framework
  268. Installing Mocha
  269. Structuring our test files
  270. Writing our first unit test
  271. Describing the expected behavior
  272. Overriding ESLint for test files
  273. Understanding arrow functions in Mocha
  274. Specifying ESLint environments
  275. Running our unit tests
  276. Running unit tests as an npm script
  277. Completing our first unit test suite
  278. Unit testing ValidationError
  279. Unit testing middleware
  280. Asserting deep equality
  281. Asserting function calls with spies
  282. Simulating behavior with stubs
  283. Testing all middleware functions
  284. Unit testing the request handler
  285. Stubbing create
  286. Dependency injection
  287. Monkey patching
  288. Dependency injection versus monkey patching
  289. Modularity
  290. Readability
  291. Reliance on third-party tools
  292. Following the dependency injection pattern
  293. Promises and Mocha
  294. Dealing with rejected promises
  295. Completing the unit tests
  296. Unit testing our engine
  297. Integration testing our engine
  298. Adding test coverage
  299. Reading a test coverage report
  300. Improving test coverage
  301. Code coverage versus test quality
  302. You don't have to test everything, all the time
  303. Unifying test coverage
  304. Ignoring files
  305. Finishing up
  306. Summary
  307. Designing Our API
  308. What it means to be RESTful
  309. What is REST?
  310. What REST is not
  311. Should my API be RESTful?
  312. Designing our API
  313. Consistent
  314. Common consistency
  315. Sending the correct HTTP status code
  316. Using HTTP methods
  317. Using ISO formats
  318. Local consistency
  319. Naming convention
  320. Consistent data exchange format
  321. Error response payload
  322. Transversal consistency
  323. Domain consistency
  324. Perennial consistency
  325. Breaking changes in APIs
  326. Future-proofing your URL
  327. Future-proofing your data structure
  328. Versioning
  329. Intuitive
  330. URLs for humans
  331. Favor verbosity and explicitness
  332. Keep It Simple Stupid (KISS)
  333. Completing our API
  334. Summary
  335. Deploying Our Application on a VPS
  336. Obtaining an IP address
  337. Managed DNS
  338. Setting up a Virtual Private Server (VPS)
  339. Creating a VPS instance
  340. Choosing an image
  341. Choosing a size
  342. Picking a data center region
  343. Selecting additional options
  344. Naming your server
  345. Connecting to the VPS
  346. Setting up user accounts
  347. Creating a new user
  348. Adding a user to the sudo group
  349. Setting up public key authentication
  350. Checking for existing SSH key(s)
  351. Creating an SSH key
  352. Adding the SSH key to the remote server
  353. Using ssh-copy-id
  354. Providing extra security
  355. Disable password-based authentication
  356. Disable root login
  357. Firewall
  358. Configuring the time zone
  359. Running our API
  360. Keeping our API alive with PM2
  361. Killing a process
  362. Keeping PM2 alive
  363. Running our API on port 80
  364. Privileged ports
  365. Possible solutions
  366. Running as root
  367. De-escalating privileges
  368. Setting capabilities
  369. Using authbind
  370. Using iptables
  371. Using reverse proxy
  372. What's a proxy? What's a reverse proxy?
  373. Setting up NGINX
  374. Configuring NGINX
  375. Understanding NGINX's configuration file
  376. Configuring the HTTP module
  377. Splitting nginx.conf into multiple files
  378. From IP to domain
  379. Buying a domain
  380. Understanding DNS
  381. Updating the domain nameserver
  382. Building our zone file
  383. NS records
  384. A and AAAA
  385. Start of Authority (SOA)
  386. Updating NGINX
  387. Summary
  388. Continuous Integration
  389. Continuous Integration (CI)
  390. Picking a CI server
  391. Integrating with Travis CI
  392. Configuring Travis CI
  393. Specifying the language
  394. Setting up databases
  395. Setting environment variables
  396. Activating our project
  397. Examining Travis CI results
  398. Continuous Integration with Jenkins
  399. Introduction to Jenkins
  400. Freestyle projects
  401. Pipeline
  402. Setting up a new Jenkins server
  403. Creating the jenkins user
  404. Configuring time
  405. Installing Java
  406. Installing Jenkins
  407. Installing NGINX as a reverse proxy
  408. Configuring the firewall
  409. Updating our DNS records
  410. Configuring Jenkins
  411. Composing a Jenkinsfile
  412. The Pipeline DSL syntax
  413. Declarative versus scripted pipelines
  414. The declarative pipeline
  415. The scripted pipeline
  416. Setting up the environment
  417. Installing Docker
  418. Integration with GitHub
  419. Providing access to the repository
  420. The Personal Access (OAuth) Token
  421. Using the GitHub plugin
  422. Setting up GitHub service hooks manually
  423. Creating a new folder
  424. Creating a new pipeline
  425. Running the first build
  426. Summary
  427. Security – Authentication and Authorization
  428. What is Authentication?
  429. Introduction to password-based authentication
  430. Hashing passwords
  431. Cryptographic hash functions
  432. Picking a cryptographic hashing algorithm
  433. Hash stretching
  434. Hash stretching algorithms
  435. Preventing brute-force attacks against a single user
  436. Protecting against brute-force attacks
  437. Reverse lookup table attacks
  438. Protecting against reverse lookup table attacks
  439. Implementing password-base authentication
  440. Updating existing E2E tests
  441. Generating a random digest
  442. Picking a bcrypt library
  443. Using the bcryptjs library
  444. Validating a digest
  445. Updating an existing implementation
  446. Retrieving the salt
  447. Implementing the Retrieve Salt endpoint
  448. Implementing a Retrieve Salt engine
  449. Generating a salt for non-existent users
  450. Writing E2E tests
  451. Implementation
  452. Login
  453. Writing tests
  454. Implementing Login
  455. Keeping users authenticated
  456. JSON web tokens (JWTs)
  457. Anatomy of a JWT
  458. Header
  459. Payload and claims
  460. Registered claim names
  461. Public claim names
  462. Private claim names
  463. Example claim
  464. Signature
  465. Asymmetric signature generation
  466. Symmetric signature generation
  467. Picking an algorithm
  468. A note on encryption
  469. Terminology and summary
  470. Responding with a token
  471. Adding E2E Tests
  472. Implementation
  473. Multiline environment variables
  474. Generating the token
  475. Attaching the token
  476. HTTP cookies
  477. Cross-Site Scripting (XSS)
  478. Cross-Site Request Forgery (XSRF)
  479. HTTP headers
  480. The Authorization header
  481. Writing tests
  482. Features and scenarios
  483. Implementation step definitions
  484. Verifying the digest in the request
  485. Next steps
  486. Preventing man-in-the-middle (MITM) attacks
  487. Encrypting digests
  488. Block cipher
  489. Exploring the Secure Remote Password (SRP) protocol
  490. Summary
  491. Documenting Our API
  492. Overview of OpenAPI and Swagger
  493. Picking an API specification language
  494. Swagger vs OpenAPI
  495. Swagger Toolchain
  496. Swagger Editor
  497. Swagger UI
  498. Swagger Inspector
  499. Swagger codegen
  500. Defining an API specification with OpenAPI
  501. Learning YAML
  502. An overview of the root fields
  503. Specifying the GET /salt endpoint
  504. Specifying parameters
  505. Specifying responses
  506. Specifying the Create User endpoint
  507. Specifying the request body
  508. Defining common components
  509. Specifying the Retrieve User endpoint
  510. Specifying the Replace Profile endpoint
  511. Specifying the rest of the endpoints
  512. Generating documentation with Swagger UI
  513. Adding the Swagger UI to our repository
  514. Using our specification in the Swagger UI
  515. Exposing swagger.yaml from our API
  516. Enabling CORS
  517. Same-origin policy
  518. Cross-Origin Resource Sharing (CORS)
  519. Final touches
  520. Replacing the specification URL
  521. Removing the header
  522. Deployment
  523. Summary
  524. Creating UI with React
  525. Picking a front-end framework/library
  526. Vanilla JavaScript vs. frameworks
  527. Choosing a framework/library
  528. Popularity/community
  529. Features
  530. Virtual DOM
  531. JSX
  532. Post-React
  533. Flexibility
  534. Performance
  535. Cross-platform
  536. Hybrid applications with Ionic
  537. Native UI with React Native and Weex
  538. Learning curve
  539. Conclusion
  540. Getting started with React
  541. What is React?
  542. Components
  543. Virtual DOM
  544. How Virtual DOM improves performance
  545. React is declarative
  546. React summary
  547. Starting a new repository
  548. Adding some boilerplate
  549. Creating our first component
  550. JSX
  551. Transpiling JSX
  552. Defining React components
  553. Functional and class components
  554. Pure components
  555. Maintaining the state and listening for events
  556. Handling events
  557. setState and immutability
  558. Rendering the state
  559. Submitting forms
  560. Uncontrolled form elements
  561. Resolving CORS issues
  562. Disabling the Button component
  563. Controlled form elements
  564. Modularizing React
  565. Client-side modules
  566. Module bundling
  567. Browserify
  568. Webpack
  569. Rollup
  570. Parcel
  571. Asynchronous module loading
  572. AMD and Require.js
  573. Universal Module Definition
  574. SystemJS and the Loader specification
  575. jspm
  576. Module bundler versus module loader
  577. HTTP/2
  578. Webpack
  579. Modularizing our components
  580. Entry/output
  581. Loaders
  582. Plugins
  583. Copying files
  584. Final steps
  585. Summary
  586. E2E Testing in React
  587. Testing strategies
  588. Automated UI testing
  589. Unit testing
  590. Logical units
  591. Component units
  592. Browser testing
  593. Writing E2E tests with Gherkin, Cucumber, and Selenium
  594. Adding test script
  595. Specifying a feature
  596. Adding IDs to elements
  597. Selenium
  598. WebDriver API
  599. Using Selenium WebDriver
  600. Headless browsers
  601. Browser drivers
  602. Setup and teardown
  603. Implementing step definitions
  604. Navigating to a page
  605. Typing into input
  606. Asserting a result
  607. Running the tests
  608. Adding multiple testing browsers
  609. Running our backend API
  610. Dynamic string substitution with Webpack
  611. Serving the API from a submodule
  612. Defining the happy scenario
  613. Generating random data
  614. Making step definitions more generic
  615. Clicking
  616. Waiting
  617. Render components based on state
  618. Routing with React Router
  619. Basics
  620. Router
  621. Route matching
  622. Supporting the History API
  623. Navigation
  624. TDD
  625. Login
  626. Writing tests
  627. Implementing Login
  628. Over to you
  629. Summary
  630. Managing States with Redux
  631. State management tools
  632. Redux
  633. MobX
  634. Redux versus MobX
  635. Converting to Redux
  636. Creating the store
  637. Lifting the state up
  638. Dispatching actions
  639. Updating the state with the Reducer
  640. Connecting with React Redux
  641. Wrapping with the Provider component
  642. Connecting to the Redux store
  643. mapStateToProps
  644. mapDispatchToProps
  645. Decoupling Redux from components
  646. Summary
  647. Migrating to Docker
  648. Problems with manual deployment
  649. Introduction to Docker
  650. What are containers?
  651. Workflow
  652. How does Docker solve our issues?
  653. Mechanics of Docker
  654. What is a Docker container?
  655. Control groups
  656. Namespaces
  657. LXC and Docker
  658. Virtual Machines
  659. Containers versus Virtual Machines
  660. What is a Docker image?
  661. Images are layered
  662. Running a container
  663. Setting up the Docker Toolchain
  664. Adding the Docker package repository
  665. Installing Docker
  666. Docker Engine, Daemon, and Client
  667. Running Elasticsearch on Docker 
  668. Running a container
  669. Understanding the docker run option
  670. Identifying a container by name 
  671. Setting environment variables
  672. Running as daemon
  673. Network port mapping
  674. 0.0.0.0
  675. Updating our test script
  676. Dockerizing our backend API
  677. Overview of a Dockerfile
  678. Writing our Dockerfile
  679. Picking a base image
  680. Copying project files
  681. Building our application
  682. Specifying the executable
  683. Building our image
  684. Running our image
  685. Persisting data
  686. Following best practices
  687. Shell versus exec forms
  688. Allowing Unix signaling
  689. Running as a non-root user
  690. Taking advantage of the cache
  691. Caveats
  692. Using a lighter image
  693. Removing obsolete files
  694. Multi-stage builds
  695. Security
  696. Summary
  697. Robust Infrastructure with Kubernetes
  698. High availability
  699. Measuring availability
  700. Following the industry standard
  701. Eliminating single points of failure (SPOF)
  702. Load balancing versus failover
  703. Load balancing
  704. DNS load balancing
  705. Layer 4/7 load balancers
  706. Layer 4 load balancers
  707. Layer 7 load balancing
  708. High reliability
  709. Testing for reliability
  710. High throughput
  711. High scalability
  712. Clusters and microservices
  713. Microservices
  714. Clusters
  715. Cluster management
  716. Cluster-level tools
  717. Discovery service
  718. Scheduler
  719. Global configuration store
  720. Provisioning tools
  721. Picking a cluster management tool
  722. Control Planes and components
  723. Master components
  724. kube-apiserver
  725. kube-control-manager
  726. Node components
  727. Container runtime
  728. kubelet
  729. kube-proxy
  730. Kubernetes objects
  731. The four basic objects
  732. High-level objects
  733. Controllers
  734. Setting up the local development environment
  735. Checking hardware requirements
  736. Cleaning our environment
  737. Disabling swap memory
  738. Installing kubectl
  739. Installing Minikube
  740. Installing a Hypervisor or Docker Machine
  741. Creating our cluster
  742. Setting environment variables for the local cluster
  743. Running minikube start
  744. Updating the context
  745. Resetting the cluster
  746. Creating our first Pod
  747. Running Pods with kubelet
  748. Running Pods with kubectl run
  749. Understanding high-level Kubernetes objects
  750. Declarative over imperative
  751. Deleting deployment
  752. Creating a deployment manifest
  753. A note on labels
  754. Running pods declaratively with kubectl apply
  755. Kubernetes Object management hierarchy
  756. Configuring Elasticsearch cluster
  757. Networking for distributed databases
  758. Configuring Elasticsearch's Zen discovery
  759. Attaching hostnames to Pods
  760. Working with StatefulSets
  761. Ordinal index
  762. Working with services
  763. Linking StatefulSet to a service
  764. Updating Zen Discovery configuration
  765. Validating Zen Discovery
  766. Deploying on cloud provider
  767. Creating a new remote cluster
  768. Switching contexts
  769. Configuring nodes for Elasticsearch
  770. Running commands on multiple servers
  771. Using pssh
  772. Using init containers
  773. Running the Elasticsearch service
  774. Validating Zen Discovery on the remote cluster
  775. Persisting data
  776. Introducing Kubernetes Volumes
  777. Defining Volumes
  778. Problems with manually-managed Volumes
  779. Introducing PersistentVolume (PV)
  780. Consuming PVs with PersistentVolumeClaim (PVC)
  781. Deleting a PersistentVolumeClaim
  782. Deleting a PersistentVolume
  783. Problems with manually provisioning PersistentVolume
  784. Dynamic volume provisioning with StorageClass
  785. Defining a StorageClass
  786. Using the csi-digitalocean provisioner
  787. Provisioning PersistentVolume to StatefulSet
  788. Configuring permissions on a bind-mounted directory
  789. Visualizing Kubernetes Objects using the Web UI Dashboard
  790. Launching the Web UI Dashboard locally
  791. Launching the Web UI Dashboard on a remote cluster
  792. Deploying the backend API
  793. Publishing our image to Docker Hub
  794. Creating a Deployment
  795. Discovering Services using kube-dns/CoreDNS
  796. Running Our backend Deployment
  797. Creating a backend Service
  798. Exposing services through Ingress
  799. Deploying the NGINX Ingress Controller
  800. Deploying the Ingress resource
  801. Updating DNS records
  802. Summary
  803. Other Books You May Enjoy
  804. Leave a review - let other readers know what you think

Picking an object schema and validation library

So out of the three options, which one should we use? To answer this question, we should first consider their interoperability and expressiveness.