Write Modern Web Apps with the MEAN Modern Web Apps with the MEAN Stack Mongo, Express, AngularJS, and Node.js. DEVELOP AND DESIGN Write Modern Web Apps with the MEAN Stack Mongo, Express, AngularJS, and Node.js Jeff Dickey PEACHPIT PRESS ... 101 Chapter 8 ADDING ROUTING AND CLIENT AUTHENTICATION ..... 102 Routing ... Node.js. P

  • Published on
    20-Mar-2018

  • View
    215

  • Download
    3

Transcript

Jeff DickeyDEVELOP AND DESIGNWrite Modern Web Apps with the MEAN StackMongo, Express, AngularJS, and Node.jsDEVELOP AND DESIGNWrite Modern Web Apps with the MEAN StackMongo, Express, AngularJS, and Node.jsJeff DickeyPEACHPIT PRESSWWW.PEACHPIT.COMhttp://WWW.PEACHPIT.COMWrite Modern Web Apps with the MEAN Stack: Mongo, Express, AngularJS, and Node.jsJeff DickeyPeachpit Presswww.peachpit.comTo report errors, please send a note to errata@peachpit.comPeachpit Press is a division of Pearson Education.Copyright 2015 by Jeff DickeyEditor: Kim WimpsettProduction editor: David Van NessProofreader: Liz WelchTechnical editor: Joe ChellmanCompositor: Danielle FosterIndexer: Danielle FosterCover design: Aren StraigerInterior design: Mimi HeftNotice of RightsAll rights reserved. No part of this book may be reproduced or transmitted in any form by any means, electronic, mechani-cal, photocopying, recording, or otherwise, without the prior written permission of the publisher. For information on getting permission for reprints and excerpts, contact permissions@peachpit.com.Notice of LiabilityThe information in this book is distributed on an As Is basis, without warranty. While every precaution has been taken in the preparation of the book, neither the author nor Peachpit shall have any liability to any person or entity with respect to any loss or damage caused or alleged to be caused directly or indirectly by the instructions contained in this book or by the computer software and hardware products described in it.TrademarksMany of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks. Where those designations appear in this book, and Peachpit was aware of a trademark claim, the designations appear as requested by the owner of the trademark. All other product names and services identified throughout this book are used in editorial fashion only and for the benefit of such companies with no intention of infringement of the trademark. No such use, or the use of any trade name, is intended to convey endorsement or other affiliation with this book.ISBN-13: 978-0-13-393015-3ISBN-10: 0-13-393015-79 8 7 6 5 4 3 2 1Printed and bound in the United States of Americahttp://www.peachpit.comTo Mom and Dad, for sometimes allowing me to sit inside all day on that computerABOUT THE AUTHORJeff Dickey is a full-stack web developer with years of startup experience in San Francisco and Los Angeles. Jeff has launched projects, maintained large systems, and led development teams. With more than 10 years of experience on all of the major web platforms, he is con-tinually searching for the latest technology for building applications. Currently Jeff works for Heroku as its first CLI developer. Jeff is also an instructor for General Assembly, teaching a course on back-end web development.iv About the AuthorCONTENTSPreface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ixIntroduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xChapter 1 HOW MODERN WEB ARCHITECTURE IS CHANGING . . . . . . . . . . . 2The Rise of the Static App . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4Enter the Thick Client . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6Chapter 2 WHY JAVASCRIPT IS A GOOD CHOICE FOR MODERN APPS . . . . 8What Is Angular.js? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10What Is Node.js? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13What Is Express? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20What Is MongoDB? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22Chapter 3 INTRODUCING THE SOCIAL NETWORKING PROJECT . . . . . . . . . 28Creating a Static Mockup of the Recent Posts Page . . . . . . . . . . . . . . . . . 30Angularizing the Page . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31Adding New Posts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34Next Steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38Chapter 4 BUILDING A NODE.JS API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40The Stock Endpoint . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42Creating Posts via the API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44MongoDB Models with Mongoose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45Using Mongoose Models with the POST Endpoint . . . . . . . . . . . . . . . . . . 46Next Steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49Chapter 5 INTEGRATING NODE WITH ANGULAR . . . . . . . . . . . . . . . . . . . . . . . . 50$http . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52Reading Posts from the API with $http . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53Serving posts.html Through Node . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55Saving Posts to the API with $http . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56Fixing the Post Ordering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57Cleaning Up server.js . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58Cleaning Up Angular . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63Next Steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67Contents vChapter 6 AUTOMATING YOUR BUILD WITH GULP . . . . . . . . . . . . . . . . . . . . . . 68Introducing Grunt and Gulp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70Gulp Hello World . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71Building JavaScript with Gulp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72Building CSS with Gulp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80Gulp Dev Task . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82Other Gulp Plug-ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84Next Steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85Chapter 7 BUILDING AUTHENTICATION IN NODE.JS . . . . . . . . . . . . . . . . . . . . 86Introducing Token Authentication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88JSON Web Token (JWT) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89Using BCrypt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94Authentication with MongoDB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97Next Steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101Chapter 8 ADDING ROUTING AND CLIENT AUTHENTICATION . . . . . . . . . 102Routing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104Creating a Login Form . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107Express Authentication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110Angular Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114Authenticating Social Posts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116HTML5 Pushstate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118Registration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119Logout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120Remember Me . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121User Foreign Key . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122Next Steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123Chapter 9 PUSHING NOTIFICATIONS WITH WEBSOCKETS . . . . . . . . . . . . . 124Introducing WebSockets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126How WebSockets Work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127What Should You Use WebSockets For? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128WebSockets in Your Social App . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129WebSockets in Angular.js . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133WebSocket Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135Dynamic WebSocket Hostname . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140Next Steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141vi ContentsChapter 10 PERFORMING END-TO-END TESTING . . . . . . . . . . . . . . . . . . . . . . . . 142Setting Up Protractor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144JavaScript Testing Frameworks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145Writing a Basic Protractor Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146Protractor Expectations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156chai-as-promised . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159When to Use End-to-End Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160Next Steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161Chapter 11 TESTING THE NODE SERVER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162Not Quite Unit Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164Mocha for Node . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165Post Controller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167SuperTest . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168Base Router . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169Using the Base Router with SuperTest . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170Models in Controller Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171Testing Controllers with Authentication . . . . . . . . . . . . . . . . . . . . . . . . . . . 173Code Coverage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175The npm test Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177JSHint . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178Next Steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179Chapter 12 TESTING ANGULAR.JS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180Using Karma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182Using Bower . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183Setting Up Karma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185Basic Karma Service Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187HTTP Testing with Karma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189Karma Controller Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192Testing Spies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197Next Steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199Contents viiChapter 13 DEPLOYING TO HEROKU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200Platform-as-a-Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202How Heroku Works . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203Twelve-Factor Apps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204Deploying an Application to Heroku . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205MongoDB on Heroku . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207Redis on Heroku . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208Compiling Assets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210Node Cluster . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212Next Steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213Chapter 14 DEPLOYING TO DIGITAL OCEAN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214What Is Digital Ocean? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216Single-Server vs. Multiserver Architecture . . . . . . . . . . . . . . . . . . . . . . . . . 217Fedora 20 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218Creating a Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219Installing Node . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222Installing MongoDB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223Installing Redis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225Running the Social App . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227Running Social App Under systemd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228Zero-Downtime Deploys . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229Multiserver Migration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234Next Steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237Index. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238viii ContentsPREFACEWHO IS THIS BOOK FOR?This book is for web developers wanting to learn how building web applications has changed. The book assumes a basic knowledge of JavaScript. Knowledge of Node or Angular is helpful as well but not required.WHY I WROTE THIS BOOKIve been a web developer since 2004 and have professionally worked with most of the majorweb platforms. I love to seek out new technology that helps me write my applicationsbetter.Applications built with an MVC framework such as Angular has been the largest paradigm shift that Ive seen in the web community. Frameworks and tools have come andgone, but client-side MVC applications are fundamentally different.Ive been impressed with the quality of applications that Ive shipped with Angular and Node. The tools are simplesometimes a bit navebut this simplicity comes with the fantastic ability to iterate on features and maintain a codebase.Applications such as those built with the MEAN stack are becoming more popular, butmany development teams still feel comfortable with server-generated pages and relational databases.Ive had such good luck with MEAN applications that I want to share my knowledge ofhow to build them with you.I hope youll enjoy exploring this new method of building applications with me. Ilove discussing these topics, so feel free to reach out to me on Twitter to continue theconversation.Jeff Dickey @dickeyxxx August 2014PrefACe ixINTRODUCTIONThe JavaScript community has a strong belief in the power of composability when architect-ing software. This is in line with the Unix philosophy of simple components that can be used together to quickly build applications.By no means is this methodology the only one that exists. Ruby on Rails, for example, uses an opinionated framework to make decisions for you about what your application should look like. Opinionated frameworks offer the advantage of being able to quickly learn an application because out of the box it worksyou just need to fill in the gaps. Opinionated frameworks are also easier to learn because there is usually a right way to do something. The downside is that youre limited to building applications that the framework was made for, and moving outside of the use cases the framework was made for can be difficult.By contrast, the composition methodology is more flexible. Composing simple pieces together has a clear advantage of allowing you to build anything you want. These frame-works provide you with building blocks, and its up to you to decide how to put them together. The downside is mostly in the learning phase. Its difficult to know what is a good idea and what is a bad idea without having experience doing both.For this reason, its useful to read up on opinionated guides for how to build JavaScript applications. These opinions provide one persons viewpoint on good and bad decisions and give you a road map to what an application should look like.This book shows you how to build your own MEAN application following my opinions of what a good application should look like. These opinions come from my experience develop-ing applications. While I have a good amount of experience, its unlikely it will fit perfectly with any other one person. For this reason, I find books such as this are useful to learn not just the how of using a tool set but the why as well.In other words, its useful to know how to use promises in Node but not very useful if you dont understand why theyre useful.The application you will build is called simply Social App (see Figure I.1). You can see anexample of it running at https://mean-sample.herokuapp.com as well as the code at https://github.com/dickeyxxx/mean-sample.The application is similar to Twitter. Users can create an account and add posts. The feature count is not large but does consist of some neat solutions such as WebSockets that immediately display new posts to all users viewing the application. Ill also go over compil-ing the CSS and JavaScript assets with Gulp, deploying the application to both Heroku and Digital Ocean, building a clean, maintainable API and more.Having a newsfeed that displays live, updating content is a pattern that I see on just about every project I work on. I chose this as an example because it is complicated enough to incorporate many different tools but not so complex that you will become bogged down inthe minutiae of this specific application.x IntroduCtIonhttps://mean-sample.herokuapp.comhttps://github.com/dickeyxxx/mean-sampleThis application is also easily extensible. I encourage you while reading this book to take the time to not only implement the application as I have done but to build features of your own. Its relatively easy to follow along and build the same application, but you know thats not how software is actually written.Learning a new skill is tough. As a teacher, Ive witnessed many people learning some-thing for the first time and been able to witness their progress. One facet of that Ive noticed is that learning doesnt feel like anything. You cant tell whether youre learning something when youre learning itin fact, learning feels a lot more like frustration.What Ive learned is that during this period of frustration is actually when people improve the most, and their improvements are usually obvious to an outsider. If you feel frustrated while trying to understand these new concepts, try to remember that it might not feel like it, but youre probably rapidly expanding your knowledge.With that, join me in Chapter 1 while you learn a bit about the history of the Webs sur-prising relationship with JavaScript, how its changed the way we think of applications, and where the MEAN stack fits in.FIGURE I.1 Social appIntroduCtIon xiThis page intentionally left blank CHAPTER 4Building a Node.js APIIn the previous chapter, you built a fully functioning Angular app for posting status updates. In this chapter, you will build an API for it to get a list of all the posts and to make a new post. The endpoints will be as follows: GET /api/posts returns a JSON array of all the posts. This is similar to what you had in $scope.posts. POST /api/posts expects a JSON document containing a username and post body. It will save that post in MongoDB.41THE STOCK ENDPOINTTo start, youll use Node.js and Express to build a stock /api/posts endpoint. First, inside a new folder, create a package.json file like the following:{ name: socialapp}The name can be anything you want, but try to ensure it doesnt conflict with an existing pack-age. The package.json file is the only thing you need to make a directory a node project.Now that you have this, you can add express and body-parser as dependencies:$ cd $ npm install --save express$ npm install --save body-parserbody-parser is used for express to read in JSON on POST requests automatically.The --save flag saves the dependency to the package.json file so you know what versions of what packages the app was built with (and therefore depends on). In fact, ifyouopen your package.json, youll see something similar to this:{ name: socialapp, dependencies: { body-parser: ^1.4.3, express: ^4.4.4 }}Now that youve done this, you can require(express) to include it in a node script.42 Chapter 4 buIldIng A node.Js APICreate a server.js file with the following contents:var express = require(express)var bodyParser = require(body-parser)var app = express()app.use(bodyParser.json())app.get(/api/posts, function (req, res) { res.json([ { username: dickeyxxx, body: node rocks! } ])})app.listen(3000, function () { console.log(Server listening on, 3000)})Try running this file:$ node server.jsYou can access it in your browser at http://localhost:3000/api/posts. You should see that your stubbed JSON comes back.You now have the basic Node request in place, so you need to add the POST endpoint for adding posts and back it against MongoDB.the stoCk endPoInt 43http://localhost:3000/api/postsCREATING POSTS VIA THE APINow lets build the POST endpoint for creating posts. Add this endpoint to server.js:app.post(/api/posts, function (req, res) { console.log(post received!) console.log(req.body.username) console.log(req.body.body) res.send(201)})This is just a request that checks to see whether youre reading the data properly. The cli-ent would receive only the HTTP status code 201 (created). Its good to build a lot of these stubbed-out sorts of logic to check to see whether your plumbing is in order when building MEAN applications. Because you cant test a POST request using the browser, you should check to see whether it is working using curl:curl -v -H Content-Type: application/json -XPOST --data p {\username\:\dickeyxxx\, \body\:\node rules!\} p localhost:3000/api/postsIf you are unfamiliar with curl, this says Make a POST request to localhost:3000/api/posts. Be verbose. Setting your Content-Type header to json includes the JSON document as the body.The Content-Type header is necessary to be able to parse this content into the friendly req.body.username objects from the JSON.If the command line isnt your thing, you can do this same thing using the great Postman app for Chrome to test APIs. Regardless of what method you use, it is crucial you test your APIs using stub clients like this rather than building your app in lockstep. 44 Chapter 4 buIldIng A node.Js APIMongoDB MODELS WITH MONGOOSETo interact with MongoDB, you will be using the Mongoose ODM. Its a light layer on top ofthe Mongo driver. To add the npm package, do this:$ npm install --save mongooseItll be good to keep this code modularized so your server.js file doesnt get huge. Letsadd a db.js file with some of the base database connection logic:var mongoose = require(mongoose)mongoose.connect(mongodb://localhost/social, function () { console.log(mongodb connected)})module.exports = mongooseYou can get access to this mongoose instance by using the require function. Now lets create a mongoose model to store the posts. Place this code in models/post.js:var db = require(../db)var Post = db.model(Post, { username: { type: String, required: true }, body: { type: String, required: true }, date: { type: Date, required: true, default: Date.now }})module.exports = PostNow you have a model you can get with require. You can use it to interact with the database.Mongodb Models wIth Mongoose 45USING MONGOOSE MODELS WITH THE POST ENDPOINTNow requiring this module will give you the Post model, which you can use inside of your endpoint to create posts.In server.js, change your app.post(/api/posts) endpoint to the following:var Post = require(./models/post)app.post(/api/posts, function (req, res, next) { var post = new Post({ username: req.body.username, body: req.body.body }) post.save(function (err, post) { if (err) { return next(err) } res.json(201, post) })})First, you require the Post model. When a request comes in, you build up a new instance of the Post model with new Post(). Then, you save that Post model and return a JSON rep-resentation of the model to the user with status code 201.While it isnt totally necessary to return the JSON here, I like for my create API actions to do so. The client can sometimes make use of it. It might be able to use the _id field or show data that the server generated (such as the date field, for example).Note the err line. In Node, its common for code to return callbacks like this that start with an error argument, and then the data is returned. Its your responsibility to check whether there is an error message and do something about it. In this case, you call the next() callback with an argument, which triggers a 500 in Express. An error in this case would typically mean the database was having issues. Other programming languages use exceptions to handle errors like this, but Node.js made the design decision to go with error objects because of its asynchronous nature. Its simply not possible to bubble up an excep-tion with evented code like Node.js.Go ahead and hit this endpoint again with curl or Postman. (Make sure you first restart your server. Later youll see how to automatically restart it with nodemon.)$ curl -v -H Content-Type: application/json -XPOST --data p {\username\:\dickeyxxx\, \body\:\node rules!\} p localhost:3000/api/posts46 Chapter 4 buIldIng A node.Js APIYou should see a response like the following (make sure youve started your Mongo server):> POST /api/posts HTTP/1.1> User-Agent: curl/7.30.0> Host: localhost:3000> Accept: */*> Content-Type: application/json> Content-Length: 46>* upload completely sent off: 46 out of 46 bytes< HTTP/1.1 201 Created< X-Powered-By: Express< Content-Type: application/json; charset=utf-8< Content-Length: 120< Date: Sun, 22 Jun 2014 00:41:55 GMT< Connection: keep-alive db.posts.find(){ _id : ObjectId(53a62653fa305e5ddb318c1b), username : dickeyxxx, p body : node rules!, date : ISODate(2014-06-22T00:41:55.040Z), p __v : 0 }Looks like it made it into the database!Now, lets update the GET request to read from the database:app.get(/api/posts, function (req, res, next) { Post.find(function(err, posts) { if (err) { return next(err) } res.json(posts) })})usIng Mongoose Models wIth the Post endPoInt 47This one is similar to the last one. Call find on the Post model; then, when the request returns, render out the posts as JSON (so long as no error was returned). Go back to your web browser and reload http://localhost:3000/api/posts to see it in action.You now have a full API you can read and write from in order to support your Angular app.Here is the final server.js:var express = require(express)var bodyParser = require(body-parser)var Post = require(./models/post)var app = express()app.use(bodyParser.json())app.get(/api/posts, function (req, res, next) { Post.find(function(err, posts) { if (err) { return next(err) } res.json(posts) })})app.post(/api/posts, function (req, res, next) { var post = new Post({ username: req.body.username, body: req.body.body }) post.save(function (err, post) { if (err) { return next(err) } res.json(201, post) })})app.listen(3000, function () { console.log(Server listening on, 3000)})48 Chapter 4 buIldIng A node.Js APIhttp://localhost:3000/api/postsNEXT STEPSYouve now built the full API for you to use with the Angular app. In the next chapter, youll integrate the API into Angular and serve the Angular app via Node. Youll also take some time to clean up your code a little by breaking it into modules.next stePs 49INDEXNUMBER12-factor apps. See Heroku 12-factor appsAAjax-empowered JavaScript, 4AMQP (RabbitMQ) message broker, 137Angular applicationscookie-based authentication, 88token-based authentication, 88Angular code modules, 31Angular.js. See also Node integration with Angularbenefits, 12breaking into services, 6466creating logical sections, 6466events, 114115vs. jQuery, 1012JSON, 12overview, 10recent posts page, 3133serving static assets, 6364Unknown provider error, 75use with MEAN stack, 12WebSockets in, 133134Angular.js testing. See also testing frameworksBower, 183184HTTP with Karma, 189191Karma, 182Karma controller, 192196Karma service test, 187188setting up Karma, 185186spies, 197198application process, traditional, 4asynchronous code, writing with promises,52authenticating social posts, 116117authentication in Express, 110113authentication in Node.js. See also Node.jsBCrypt, 9496JWT (JSON Web Token), 8993with MongoDB, 97100tokens, 88automating builds. See GulpBback end, 6base routeraccessing for Node-server testing, 169using with SuperTest, 170BCrypt hashing algorithm, 9496boot.js script, 229231Bootstrap styling, using with login form,107Bower, using with Angular, 183184BSON data storage, using with MongoDB, 2324238 Index Ccallbacks, 1617Chai assertion, performing in Protractor, 157client authentication. See authenticationclient-server communication. SeeWebSocketscloud server. See Digital Ocean cloud serverCommonJS spec, 17concurrency, handling, 1516connecting to ws websocket, 129130controller tests, models in, 171173controllersdeclaring with Angular.js, 3132testing, 192196controllers with authentication, testing, 173174cookie-based authentication, 88CSS, building with Gulp, 8081Ddata, loading with WebSockets, 128databases. See MongoDB document databaseDigital Ocean cloud serverarchitecture, 217centralized databases, 235creating account with, 219creating droplets, 219221Fedora 20, 218, 220installing Redis, 225226load balancer, 234235MongoDB, 223224multiserver migration, 234235overview, 216private networking, 235running social app, 227social app under systemd, 228SSH key, 219, 221zero-downtime deploys, 229233documentsinserting in MongoDB, 26querying in MongoDB, 26droplets, creating on Digital Ocean, 219221Ee2e directory, using in Protractor test, 146end-to-end testingJavaScript testing frameworks, 145Protractor setup, 144using, 160enterpriseNode.js in, 14PayPal, 14vs. startup, 13Yammer, 14evented architecture, 1516eventsAngular.js, 114115broadcasting in WebSockets, 131events from clients, publishing, 139expectations in Protractor, 156158Express NPM packageauthentication, 110113databases for Node.js, 20Index 239Express NPM package (continued )installing, 20JWT with, 9091stock endpoint, 4243external modules, declaring, 17FFedora 20, 218, 220foreign keys for users, 122function calls, testing for, 197198GGit, integrating for Heroku, 205Grunt and Gulp, 70Gulpangular.module() method, 72building CSS, 8081building JavaScript, 7279getters and setters, 72and Grunt, 70Hello World, 71rebuilding upon file changes, 77source maps, 7879Uglifier, 7477gulp-autoprefixer plug-in, 84gulp-concat plugin, installing, 72gulp-imagemin plug-in, 84gulp-jshint plug-in, 84gulp-livereload plug-in, 84gulp.-nodemon, Uglifier minification tool, 8283gulp-rev plug-in, 84gulp-rimraf plug-in, 84gulp.watch, 77Hhashing algorithms, using with passwords, 94Hello WorldGulp, 71Node.js, 19Heroku 12-factor appsadmin processes, 204backing services, 204build, release, run, 204codebase, 204concurrency, 204config, 204dependencies, 204dev/prod parity, 204disposability, 204logs, 204port binding, 204processes, 204Heroku PaaScompiling assets, 210211deploying applications to, 205206error page, 206function of, 203hosting UNIX processes, 203integrating Git for, 205MongoDB on, 207Node Cluster, 212overview, 202Redis on, 208209240 Index $httpreading posts from API with, 5354saving posts to API, 56HTML5 pushstate, enabling, 118, 121HTTP calls, performing in Angular, 52HTTP module, using with Node.js, 19HTTP proxy, node-http-proxy, 234235HTTP testing with Karma, 189191IinstallingExpress NPM package, 20gulp-concat plugin, 72MongoDB document database, 25MongoDB for Digital Ocean, 223224Node.js, 18Redis for Digital Ocean, 225Uglifier minification tool, 72I/O, handling by JavaScript, 16JJasmine testing framework, 145JavaScriptAjax-empowered, 4design of, 16maintenance, 5sharing code on Web, 17testing frameworks, 145jQuery vs. Angular.js, 1012JSHint, using with Node, 178JSONrecent posts page, 32use with Angular. js, 12JWT (JSON Web Token)creating tokens, 89with Express, 9091password validation, 9193server.js, 90KKarma controller test, 192196Karma test runnerservices, 187188setting up, 185186using with Angular, 182Llanguages, rise and fall, 14libraries, handling concurrency, 16logged-in user, showing, 114115login formBootstrap styling, 107creating, 107109in Protractor, 153154updating nav bar, 114updating URL, 108.login() function, calling, 108logout, 120Mmessage brokersAMQP (RabbitMQ), 137Rediss pubsub, 137138ZeroMQ, 137messages, passing as strings, 127minification tool, Uglifier, 7477Index 241mobile APIs, 5Mocha testing frameworkdefault reporter, 165described, 145for Node, 165166Nyan Cat reporter, 166using with Protractor, 147148modularity, 6modulesdeclaring controller, 31and NPM, 1718mongod daemon, starting, 25MongoDB document databaseauthentication, 97100auto-sharding, 24BSON data storage, 2324Collection in hierarchy, 25collections, 22Database in hierarchy, 25Document in hierarchy, 25document-oriented, 2223documents, 22ensureIndex command, 24on Heroku, 207hierarchy of data, 25horizontal scaling, 24inserting documents, 26installing, 25installing for Digital Ocean, 223224Mongoose ODM, 45overview, 22playground database, 25querying, 23querying documents, 26schemaless, 24tables, 22test database, 25user and roles, 22using, 25Mongoose ODM with Post endpoint, 4648Nnamespacing routers, 61nav bar, updating in login form, 114ng-annotate tool, using with Uglifier, 76ng-route, 104106ng/websockets.js file, creating, 133Node Cluster, using with Heroku, 212Node integration with Angular. See also Angular.js$http, 52addPost() method, 56cleaning up server.js, 5862post ordering, 57promises, 52reading posts with $http, 5354saving posts with $http, 56serving posts.html, 55Node stack, writing tests for, 164node-http-proxy, 234235Node.js. See also authentication in Node.jsbooting inside Protractor, 149151databases for Express, 20in enterprise, 14Hello World server, 19242 Index HTTP module, 19installing, 18modules and NPM, 1718ORMs (object related mappers), 20overview, 13performance, 15startup vs. enterprise, 13Walmart, 15web server, 19Node.js APIcreating posts, 44Mongoose ODM, 45Mongoose with Post endpoint, 4648server.js, 48stock endpoint, 4243Node-server testing. See also testsbase router, 169code coverage, 175176controllers with authentication, 173174GET action, 167JSHint, 178Mocha, 165166models in controller tests, 171173npm package, 175npm test command, 177POST /api/posts endpoint, 173post controller, 167SuperTest, 168NPM and modules, 1718NPM package, Express, 2021npm package, using with Node, 175npm test command, 177Oopen source environment, 13ORMs (object related mappers), 26PPaaS (platform-as a service), Heroku, 202package manager, NPM, 17pages. See recent posts pagepassword validation in JWT, 9193passwords, using hashing algorithms, 94PayPal in enterprise, 14performanceas benefit of Web architecture, 6Node.js, 15POST /api/posts endpoint, testing, 173Post endpoint, using Mongoose with, 4648post notifications, publishing, 130132post ordering, fixing, 57postsadding to recent posts page, 3437making with Protractor, 154155Node.js API, 44posts.html, serving through Node, 55progressive enhancement, 45promisesclarifying with chai-as-promised, 159using with Node.js and Angular, 52prototyping, 6Protractor. See also testing frameworksbooting Node inside, 149151Chai assertion, 157configuring, 147149Index 243Protractor (continued )DOM element for locator, 151152editing server.js, 150151enableTimeouts setting, 147expectations, 156158installing Mocha, 147148locators, 151152login form, 153154login nav link, 152154making posts, 154155onPrepare function, 149150running, 147149setting up, 144wiping database after running, 155Protractor teste2e directory, 146.spec.js suffix, 147user login and posting, 146publishing events from clients, 139pubsub message broker, 137138pushstate, enabling, 118, 121QQUnit testing framework, 145Rrecent posts page$scope, 32adding posts, 3437declaring controller, 31including Angular, 3133JSON representation, 32 tag, 3132static markup, 26Redison Heroku, 208209installing for Digital Ocean, 225226pubsub message broker, 137138systemd commands, 226registration, 119remembering users, 121routers, namespacing, 61routing, 104106SSass CSS preprocessor, 80 tag, using with recent posts page, 3132security in WebSocket, 136server.jsbreaking out /api/posts, 5961breaking out sendfile endpoint, 62cleaning up, 5862JWT (JSON Web Token), 90namespacing routers, 61social API, WebSockets in, 129132social apprunning, 232running on Digital Ocean, 227running under systemd, 228social networking project. See recent postspagesocial posts, authenticating, 116117.spec.js suffix, using in Protractor test, 147244 Index SSH key, using with Digital Ocean, 221startupvs. enterprise, 13Node.js in, 14static appsAjax-empowered JavaScript, 4mobile APIs, 5progressive enhancement, 45static assets, serving in Angular, 6364static mockup, building, 26strings, passing messages as, 127Stylus CSS preprocessor, 80SuperTestdone callback, 168using base router with, 170using with Node, 168TTCP layer, 127templates/posts.html file, 105test code, placement in directory, 146testing controllers with authentication, 173174testing frameworks. See also Angular.js testing; ProtractorJasmine, 145Mocha, 145QUnit, 145tests, writing for Node stack, 164. See also Node-server testingthick clients, 6token authenticationJWT (JSON Web Token), 89types, 88UUglifier minification tooldefining dependencies, 76installing, 72ng-annotate tool, 76rebuilding /assets/app.js, 77Unknown provider error, 75unit testing, 164UNIX processes, hosting, 203Unknown provider error, seeing in Angular, 75URL, updating, 108.use method, passing namespaces into, 61users, foreign keys, 122users, remembering, 121WWalmart, use of Node.js, 15web architectureback end, 6benefits, 6flow, 6modularity, 6performance, 6prototyping, 6standardized tools, 6web pages. See recent posts pageweb server, creating with Node.js, 19Index 245websitesDigital Ocean private networking, 235Introduction to NPM, 18JSHint documentation, 178Node.js, 14WebSocket architecturemessage broker, 137multiprocess/multiserver design, 137138publishing events from clients, 139reconnection, 135security, 136WebSocketsin Angular.js, 133134broadcasting events, 131client-server communication, 128dynamic hostname, 140loading data, 128ng/websockets.js file, 133overview, 127publishing post notifications, 130132in social API, 129132trouble with, 128uses, 128ws websocket, connecting to, 129130wscat command, 130YYammer, 14Zzero-downtime deploys.disconnect() method, 229.fork() method, 229boot.js script, 229231Digital Ocean, 229233integration into systemd, 233ZeroMQ message broker, 137246 Index CONTENTSPrefaceIntroductionCHAPTER 4 BUILDING A NODE.JS APIThe Stock EndpointCreating Posts via the APIMongoDB Models with MongooseUsing Mongoose Models with the POST EndpointNext StepsIndexABCDEFGHIJKLMNOPQRSTUWYZ