{"id":1298,"date":"2016-08-17T15:05:49","date_gmt":"2016-08-17T15:05:49","guid":{"rendered":"https:\/\/ionic.io\/blog\/?p=1298"},"modified":"2016-09-01T05:58:43","modified_gmt":"2016-09-01T05:58:43","slug":"one-mean-ionic-2-todo-app-on-heroku-part-1","status":"publish","type":"post","link":"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-1","title":{"rendered":"One MEAN Ionic 2 Todo App on Heroku, Part 1"},"content":{"rendered":"<p>Given the choice between a short or tall stack of pancakes, which would you get? The correct answer is always more pancakes. In this post, we\u2019re giving you more pancakes! So grab the syrup, and let&#8217;s make a full-stack of MEAN. This is the first post in a three-part series! Here&#8217;s <a href=\"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-2\/\">part 2<\/a> and <a href=\"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-3\/\">part 3<\/a> for reference.<\/p>\n<p>Before we really dig in, a little bit about the MEAN stack:<\/p>\n<p>For those who aren&#8217;t familiar, the MEAN stack is similar in concept to the popular LAMP (Linux, Apache, MySQL, PHP) stack, and is one of the most popular application development stacks for JavaScript developers. MEAN stands for MongoDB, Express, AngularJS, and Node.js, which are the four technologies that make up the stack. Here&#8217;s a quick breakdown of the part each of these plays:<\/p>\n<ul>\n<li>MongoDB: NoSQL database\/persistence<\/li>\n<li>Express: HTTP request router\/API framework<\/li>\n<li>AngularJS: Application\/MVC framework<\/li>\n<li>Node.js: Server-side execution environment<\/li>\n<\/ul>\n<p>MEAN has been a popular default dev stack for web apps in particular for quite some time now, primarily because it gives developers the ability to work with JavaScript and JSON across their entire application stack, from the server all the way to the UI. This is pretty cool for a lot of reasons, though one of the largest is that it removes a lot of complexity from an already complex system. Not only can we write all of our code in a single language (JS), since every level of the stack speaks the same language we also get to use a single data format to exchange data (JSON), as well as common idioms and object types. This continuity between layers can reduce errors and make coordinating development across the stack much easier.<\/p>\n<p><!--more--><\/p>\n<p>Ok, enough of that. On to our app!<\/p>\n<h3>Project Setup, Git, Heroku and the Node.js Backend<\/h3>\n<p>We\u2019ll be creating is a simple Ionic 2 app that uses Typescript and a RESTful api. We\u2019ll also build a Node.js backend, using Express for our API and MongoDB for data storage. When we\u2019re all done, we\u2019ll use Git to push the app to Heroku, where it will be hosted.<\/p>\n<p>The code for the app is available on <a href=\"https:\/\/github.com\/jplwood\/ionic2-mean-heroku-todo-app\">GitHub<\/a>, and, for the impatient, able to be deployed live to your Heroku account by using the button below:<br \/>\n<a href=\"https:\/\/heroku.com\/deploy?template=https:\/\/github.com\/jplwood\/ionic2-mean-heroku-todo-app\" ><img decoding=\"async\" data-src=\"https:\/\/www.herokucdn.com\/deploy\/button.svg\" alt=\"Deploy\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" class=\"lazyload\"><noscript><img decoding=\"async\" src=\"https:\/\/www.herokucdn.com\/deploy\/button.svg\" alt=\"Deploy\"><\/noscript><\/a><\/p>\n<h3>Project Setup<\/h3>\n<p>We\u2019ll be writing the app\u2019s frontend in TypeScript (TS), so you should probably <a href=\"https:\/\/www.typescriptlang.org\/index.html#download-links\">download a TS compiler<\/a> for your editor&#8211;it\u2019ll make your life much easier.<\/p>\n<p>To start, create a <code>blank<\/code> Ionic 2 app using the Ionic CLI\u2019s <code>start<\/code> command. Feel free to name your app whatever you want. I\u2019ve called mine <code>todo-ionic2-heroku<\/code>:<\/p>\n<pre><code>$ &gt; ionic start todo-ionic2-heroku blank --v2\n<\/code><\/pre>\n<p>This will create a new project directory in place, with the same name as your project. The folder structure should look roughly like this:<br \/>\n<img loading=\"lazy\" decoding=\"async\" width=\"152\" height=\"300\" class=\"aligncenter size-medium wp-image-1300 lazyload\" data-src=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2016\/08\/image03-152x300.png\" alt=\"image03\" data-srcset=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2016\/08\/image03-152x300.png 152w, https:\/\/ionic.io\/blog\/wp-content\/uploads\/2016\/08\/image03.png 200w\" data-sizes=\"auto, (max-width: 152px) 100vw, 152px\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" style=\"--smush-placeholder-width: 152px; --smush-placeholder-aspect-ratio: 152\/300;\" \/><noscript><img loading=\"lazy\" decoding=\"async\" width=\"152\" height=\"300\" class=\"aligncenter size-medium wp-image-1300\" src=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2016\/08\/image03-152x300.png\" alt=\"image03\" srcset=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2016\/08\/image03-152x300.png 152w, https:\/\/ionic.io\/blog\/wp-content\/uploads\/2016\/08\/image03.png 200w\" sizes=\"auto, (max-width: 152px) 100vw, 152px\" \/><\/noscript><\/p>\n<p>Let\u2019s check it out. <code>cd<\/code> into your newly created directory and serve it up!<\/p>\n<pre><code>$ &gt; cd todo-ionic2-heroku\n$ \/todo-ionic2-heroku &gt; ionic serve\n<\/code><\/pre>\n<p>The <code>serve<\/code> command runs a variety of gulp tasks to build your app, then opens it in your browser (I\u2019m using the device mode built into Chrome\u2019s DevTools to see how the app looks on mobile):<br \/>\n<img loading=\"lazy\" decoding=\"async\" width=\"778\" height=\"598\" class=\"aligncenter size-full wp-image-1303 lazyload\" data-src=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2016\/08\/image01.png\" alt=\"image01\" data-srcset=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2016\/08\/image01.png 778w, https:\/\/ionic.io\/blog\/wp-content\/uploads\/2016\/08\/image01-300x231.png 300w, https:\/\/ionic.io\/blog\/wp-content\/uploads\/2016\/08\/image01-768x590.png 768w\" data-sizes=\"auto, (max-width: 778px) 100vw, 778px\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" style=\"--smush-placeholder-width: 778px; --smush-placeholder-aspect-ratio: 778\/598;\" \/><noscript><img loading=\"lazy\" decoding=\"async\" width=\"778\" height=\"598\" class=\"aligncenter size-full wp-image-1303\" src=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2016\/08\/image01.png\" alt=\"image01\" srcset=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2016\/08\/image01.png 778w, https:\/\/ionic.io\/blog\/wp-content\/uploads\/2016\/08\/image01-300x231.png 300w, https:\/\/ionic.io\/blog\/wp-content\/uploads\/2016\/08\/image01-768x590.png 768w\" sizes=\"auto, (max-width: 778px) 100vw, 778px\" \/><\/noscript><\/p>\n<p>Flipping amazing, right? Okay, maybe not yet, but it\u2019s a good start.<\/p>\n<h3>The Node.js Backend<\/h3>\n<p>If this is your first time using Heroku with a Node.js app, check out the <a href=\"https:\/\/devcenter.heroku.com\/articles\/getting-started-with-nodejs#introduction\">Getting Started with Node.js on Heroku tutorial<\/a> in Heroku\u2019s Dev Center.<\/p>\n<p>If you\u2019re awesome and want to keep going, make sure you have the following installed:<br \/>\n<a href=\"https:\/\/toolbelt.heroku.com\/\">Heroku toolbelt<\/a>&#8211;Heroku\u2019s CLI tool for creating and managing Heroku apps<br \/>\n<a href=\"https:\/\/nodejs.org\/en\/download\/\">Node.js<\/a><\/p>\n<h3>Git Init &amp; Heroku Create<\/h3>\n<p>Let\u2019s initialize a Git repository for our app:<\/p>\n<pre><code>$ \/todo-ionic2-heroku &gt; git init\n<\/code><\/pre>\n<p>Then set up the app with Heroku (Note: you must be <a href=\"https:\/\/devcenter.heroku.com\/articles\/heroku-command#logging-in\">logged in to your Heroku account<\/a> from the command line):<\/p>\n<pre><code>$ \/todo-ionic2-heroku &gt; heroku create\n<\/code><\/pre>\n<p>This command just created a Git remote named <code>heroku<\/code>, where we\u2019ll push our code. It also generated a random name for our app: <code>evening-everglades-42641<\/code>, in my case.<\/p>\n<h3>Set up MongoDB<\/h3>\n<p>Now that we have a blank Ionic app, and we\u2019re linked up to Heroku, let\u2019s provision a MongoDB instance. We could set up a local instance of MongoDB, but because we\u2019re working with Heroku, we\u2019ll use MongoLab\u2019s mLab addon. This database-as-a-service through Heroku makes it very simple to provision a MongoDB database. Also, it\u2019s free for little projects like this!<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"300\" height=\"169\" class=\"aligncenter size-medium wp-image-1306 lazyload\" data-src=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2016\/08\/image00-300x169.png\" alt=\"image00\" data-srcset=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2016\/08\/image00-300x169.png 300w, https:\/\/ionic.io\/blog\/wp-content\/uploads\/2016\/08\/image00.png 480w\" data-sizes=\"auto, (max-width: 300px) 100vw, 300px\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" style=\"--smush-placeholder-width: 300px; --smush-placeholder-aspect-ratio: 300\/169;\" \/><noscript><img loading=\"lazy\" decoding=\"async\" width=\"300\" height=\"169\" class=\"aligncenter size-medium wp-image-1306\" src=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2016\/08\/image00-300x169.png\" alt=\"image00\" srcset=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2016\/08\/image00-300x169.png 300w, https:\/\/ionic.io\/blog\/wp-content\/uploads\/2016\/08\/image00.png 480w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/noscript><\/p>\n<p>Note: if you don\u2019t want to use MongoLab, there are <a href=\"https:\/\/elements.heroku.com\/addons\">other data store options for Heroku<\/a>.<\/p>\n<p>Use the Heroku CLI to provision your database:<\/p>\n<pre><code>$ \/todo-ionic2-heroku &gt; heroku addons:create mongolab\n<\/code><\/pre>\n<p>This little command provisioned a sandbox database for us that\u2019s connected to the Heroku app created in the last step. It also created a <a href=\"https:\/\/devcenter.heroku.com\/articles\/config-vars\">config variable<\/a> in your Heroku environment: <code>MONGODB_URI<\/code>. We\u2019ll use that to connect to our database in the next step.<\/p>\n<h3>Create an Express App Connected to MongoDB<\/h3>\n<p>When we first created the Ionic project, much of the plumbing for a Node app came along with it. Excellent!<\/p>\n<p>The only setup left is to download the <code>node_modules<\/code> for our server and <code>--save<\/code> them to our existing <code>package.json<\/code> file.<\/p>\n<pre><code>$ \/todo-ionic2-heroku &gt; npm install express mongodb cors body-parser --save\n<\/code><\/pre>\n<p>In order to interact with the mLab database we provisioned, we\u2019ll use the <a href=\"https:\/\/www.npmjs.com\/package\/mongodb\">mongodb node module<\/a>, which is officially supported by Node.js.<\/p>\n<p>(Note: For projects with more complex data models, you may want to check out <a href=\"http:\/\/mongoosejs.com\/index.html\">Mongoose<\/a>, which provides \u201celegant mongodb object modeling for node.js\u201d.)<\/p>\n<p>In the main folder of your project, create a file called <code>server.js<\/code>, and put the following code in it:<\/p>\n<pre><code class=\"javascript\">\/\/server.js (todo-ionic2-heroku\/server.js)\nvar express = require(&#039;express&#039;);\nvar bodyParser = require(&#039;body-parser&#039;);\nvar cors = require(&#039;cors&#039;);\nvar app = express();\n\nvar mongodb = require(&#039;mongodb&#039;),\nmongoClient = mongodb.MongoClient,\nObjectID = mongodb.ObjectID, \/\/ Used in API endpoints\ndb; \/\/ We&#039;ll initialize connection below\n\napp.use(bodyParser.json());\napp.set(&#039;port&#039;, process.env.PORT || 8080);\napp.use(cors()); \/\/ CORS (Cross-Origin Resource Sharing) headers to support Cross-site HTTP requests\napp.use(express.static(&quot;www&quot;)); \/\/ Our Ionic app build is in the www folder (kept up-to-date by the Ionic CLI using &#039;ionic serve&#039;)\n\nvar MONGODB_URI = process.env.MONGODB_URI;\n\n\/\/ Initialize database connection and then start the server.\nmongoClient.connect(MONGODB_URI, function (err, database) {\nif (err) {\nprocess.exit(1);\n}\n\ndb = database; \/\/ Our database object from mLab\n\nconsole.log(&quot;Database connection ready&quot;);\n\n\/\/ Initialize the app.\napp.listen(app.get(&#039;port&#039;), function () {\nconsole.log(&quot;You&#039;re a wizard, Harry. I&#039;m a what? Yes, a wizard, on port&quot;, app.get(&#039;port&#039;));\n});\n});\n\n\/\/ Todo API Routes Will Go Below\n\n<\/code><\/pre>\n<h3>Get the MONGODB_URI for Local Development Fallback<\/h3>\n<p>As we develop our app, we\u2019ll want to be able to run it locally. For this, we have the code on line 17 in <code>server.js<\/code>:<\/p>\n<pre><code>var MONGODB_URI = process.env.MONGODB_URI;\n<\/code><\/pre>\n<p><code>process.env.MONGODB_URI<\/code> tells our server where our database is when the app is running on Heroku, but if you try starting your server locally with <code>node server.js<\/code>, you\u2019ll get an error like this:<\/p>\n<p><code>TypeError: Parameter &#039;url&#039; must be a string, not undefined<\/code><\/p>\n<p>To fix this, we need to grab the database URI from Heroku with the <code>heroku config<\/code> command:<\/p>\n<pre><code>$ \/todo-ionic2-heroku &gt; heroku config | grep MONGODB_URI\n<\/code><\/pre>\n<p>From the output, copy the part starting with <code>mongodb:\/\/heroku<\/code> and continues on with a string of gobbledegook. It should look something like this:<\/p>\n<pre><code>mongodb:\/\/heroku_g24xsxd8:ur8k708rh1qqga17luq6saqtat@ds045622.mlab.com:45122\/heroku_g24xsxd8\n<\/code><\/pre>\n<p>Then update line 17 of server.js:<\/p>\n<p><code>var MONGODB_URI = process.env.MONGODB_URI || &#039;your_mongodb_uri_goes_in_these_quotes&#039;;<\/code><\/p>\n<p>Note: Try not to share your DB URI anywhere public as it would grant full access to your database to anyone who knows how to use it.<\/p>\n<p>At this point, you should be able to start the server and open up your app at http:\/\/localhost:8080\/.<\/p>\n<pre><code>$ \/todo-ionic2-heroku &gt; node server.js\nDatabase connection ready\nYou&#039;re a wizard, Harry. I&#039;m a what? Yes, a wizard, on port 8080\n<\/code><\/pre>\n<p>Note: Going forward, it\u2019s useful to have three tabs open in your terminal: one running your backend Express server, one running <code>ionic serve<\/code> to rebuild the frontend when Ionic detects changes, and one for running additional commands.<\/p>\n<h3>Set up Your RESTful API Endpoints<\/h3>\n<p>Now that our server is up and running, let\u2019s go ahead and create the endpoints for a simple RESTful API that we\u2019ll use to data for the front-end of our app. We\u2019ll create two endpoints that support the following CRUD (Create, Read, Update, Delete) operations:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-1333 size-large lazyload\" data-src=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2016\/08\/Screen-Shot-2016-08-19-at-9.24.44-AM-e1472698608572-1024x346.png\" alt=\"Screen Shot 2016-08-19 at 9.24.44 AM\" width=\"640\" height=\"216\" data-srcset=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2016\/08\/Screen-Shot-2016-08-19-at-9.24.44-AM-e1472698608572-1024x346.png 1024w, https:\/\/ionic.io\/blog\/wp-content\/uploads\/2016\/08\/Screen-Shot-2016-08-19-at-9.24.44-AM-e1472698608572-300x101.png 300w, https:\/\/ionic.io\/blog\/wp-content\/uploads\/2016\/08\/Screen-Shot-2016-08-19-at-9.24.44-AM-e1472698608572-768x259.png 768w, https:\/\/ionic.io\/blog\/wp-content\/uploads\/2016\/08\/Screen-Shot-2016-08-19-at-9.24.44-AM-e1472698608572.png 1253w\" data-sizes=\"auto, (max-width: 640px) 100vw, 640px\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" style=\"--smush-placeholder-width: 640px; --smush-placeholder-aspect-ratio: 640\/216;\" \/><noscript><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-1333 size-large\" src=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2016\/08\/Screen-Shot-2016-08-19-at-9.24.44-AM-e1472698608572-1024x346.png\" alt=\"Screen Shot 2016-08-19 at 9.24.44 AM\" width=\"640\" height=\"216\" srcset=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2016\/08\/Screen-Shot-2016-08-19-at-9.24.44-AM-e1472698608572-1024x346.png 1024w, https:\/\/ionic.io\/blog\/wp-content\/uploads\/2016\/08\/Screen-Shot-2016-08-19-at-9.24.44-AM-e1472698608572-300x101.png 300w, https:\/\/ionic.io\/blog\/wp-content\/uploads\/2016\/08\/Screen-Shot-2016-08-19-at-9.24.44-AM-e1472698608572-768x259.png 768w, https:\/\/ionic.io\/blog\/wp-content\/uploads\/2016\/08\/Screen-Shot-2016-08-19-at-9.24.44-AM-e1472698608572.png 1253w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/noscript><\/p>\n<p>&nbsp;<\/p>\n<p>Finally, just for reference, the database schema for our todos is very simple:<\/p>\n<pre><code>{\n&quot;_id&quot;: ,\n&quot;description&quot;: ,\n&quot;isComplete&quot;:\n}\n<\/code><\/pre>\n<h3>Add API Endpoints to Server.js<\/h3>\n<p>To create our endpoints, let\u2019s add the following to <code>server.js<\/code>:<\/p>\n<pre><code>\/\/server.js\n...\n\/*\n* Endpoint --&gt; &quot;\/api\/todos&quot;\n*\/\n\n\/\/ GET: retrieve all todos\napp.get(&quot;\/api\/todos&quot;, function(req, res) {\ndb.collection(&quot;todos&quot;).find({}).toArray(function(err, docs) {\nif (err) {\nhandleError(res, err.message, &quot;Failed to get todos&quot;);\n} else {\nres.status(200).json(docs);\n}\n});\n});\n\n\/\/ POST: create a new todo\napp.post(&quot;\/api\/todos&quot;, function(req, res) {\nvar newTodo = {\ndescription: req.body.description,\nisComplete: false\n}\n\ndb.collection(&quot;todos&quot;).insertOne(newTodo, function(err, doc) {\nif (err) {\nhandleError(res, err.message, &quot;Failed to add todo&quot;);\n} else {\nres.status(201).json(doc.ops[0]);\n}\n});\n});\n\n\/*\n* Endpoint &quot;\/api\/todos\/:id&quot;\n*\/\n\n\/\/ GET: retrieve a todo by id -- Note, not used on front-end\napp.get(&quot;\/api\/todos\/:id&quot;, function(req, res) {\ndb.collection(&quot;todos&quot;).findOne({ _id: new ObjectID(req.params.id) }, function(err, doc) {\nif (err) {\nhandleError(res, err.message, &quot;Failed to get todo by _id&quot;);\n} else {\nres.status(200).json(doc);\n}\n});\n});\n\n\/\/ PUT: update a todo by id\napp.put(&quot;\/api\/todos\/:id&quot;, function(req, res) {\nvar updateTodo = req.body;\ndelete updateTodo._id;\n\ndb.collection(&quot;todos&quot;).updateOne({_id: new ObjectID(req.params.id)}, updateTodo, function(err, doc) {\nif (err) {\nhandleError(res, err.message, &quot;Failed to update todo&quot;);\n} else {\nres.status(204).end();\n}\n});\n});\n\n\/\/ DELETE: delete a todo by id\napp.delete(&quot;\/api\/todos\/:id&quot;, function(req, res) {\ndb.collection(&quot;todos&quot;).deleteOne({_id: new ObjectID(req.params.id)}, function(err, result) {\nif (err) {\nhandleError(res, err.message, &quot;Failed to delete todo&quot;);\n} else {\nres.status(204).end();\n}\n});\n});\n\n\/\/ Error handler for the api\nfunction handleError(res, reason, message, code) {\nconsole.log(&quot;API Error: &quot; + reason);\nres.status(code || 500).json({&quot;Error&quot;: message});\n}\n<\/code><\/pre>\n<h3>Push to Heroku and Test out Your API<\/h3>\n<p>Before we move onto our Ionic app, let\u2019s push everything to Heroku as it currently stands and test out our API with a <code>curl<\/code> command.<\/p>\n<h3>Update .gitignore<\/h3>\n<p>By default, Ionic puts <code>www\/build<\/code> in our <code>.gitignore<\/code> file, as we normally wouldn\u2019t want to track it, but we need it to support Heroku deployment, so we\u2019ll remove it. After removing it, <code>.gitignore<\/code> should look something like this:<\/p>\n<pre><code>#.gitignore\nnode_modules\/\nplatforms\/\nplugins\/\n.DS_Store\n<\/code><\/pre>\n<h3>Commit Changes and Push to Heroku<\/h3>\n<p>Next up, commit all of your our changes to the git repository and push it to Heroku:<\/p>\n<pre><code>$ \/todo-ionic2-heroku &gt; git add -A\n$ \/todo-ionic2-heroku &gt; git commit -m &quot;First commit&quot;\n$ \/todo-ionic2-heroku &gt; git push heroku master\n<\/code><\/pre>\n<p>Heroku will confirm your app has been deployed, but to open your app, you need at least one instance of it running. To activate your app run the following:<\/p>\n<pre><code>$\/todo-ionic2-heroku &gt; heroku ps:scale web=1\n<\/code><\/pre>\n<p>Then open your app:<\/p>\n<pre><code>$\/todo-ionic2-heroku &gt; heroku open\n<\/code><\/pre>\n<p>This opens your simple, blank Ionic app at <code>your-app-name.heroku-app.com<\/code>.<\/p>\n<p>Next, let\u2019s test the API by adding a new Todo by running the following <code>curl<\/code> command:<\/p>\n<pre><code>&lt;br \/&gt;$\/todo-ionic2-heroku &gt; curl -H &quot;Content-Type: application\/json&quot; -d &#039;{&quot;description&quot;:&quot;Order a tall stack of pancakes, just because.&quot;}&#039; https:\/\/your-app-name.herokuapp.com\/api\/todos\n<\/code><\/pre>\n<p>You can check out your newly added todo under the <code>todos<\/code> collection in your mLab management portal. Open it up by running:<\/p>\n<pre><code>$\/todo-ionic2-heroku &gt; heroku addons:open mongolab\n<\/code><\/pre>\n<h3>Some Closing Thoughts<\/h3>\n<p>And with that, the backend is all ready to go. The next step will be to build out the frontend of our app. In the <a href=\"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-2\/\">next post<\/a>, we\u2019ll write some Angular 2 code to retrieve the todos we just added to the database and display them in an Ionic 2 app.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Given the choice between a short or tall stack of pancakes, which would you get? The correct answer is always more pancakes. In this post, we\u2019re giving you more pancakes! So grab the syrup, and let&#8217;s make a full-stack of MEAN. This is the first post in a three-part series! Here&#8217;s part 2 and part [&hellip;]<\/p>\n","protected":false},"author":30,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"publish_to_discourse":"","publish_post_category":"","wpdc_auto_publish_overridden":"","wpdc_topic_tags":"","wpdc_pin_topic":"","wpdc_pin_until":"","discourse_post_id":"","discourse_permalink":"","wpdc_publishing_response":"","wpdc_publishing_error":"","_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[13,25],"class_list":["post-1298","post","type-post","status-publish","format-standard","hentry","category-all","tag-ionic-2","tag-tutorials"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v23.0 (Yoast SEO v23.0) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>One MEAN Ionic 2 Todo App on Heroku, Part 1 - Ionic Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-1\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"One MEAN Ionic 2 Todo App on Heroku, Part 1\" \/>\n<meta property=\"og:description\" content=\"Given the choice between a short or tall stack of pancakes, which would you get? The correct answer is always more pancakes. In this post, we\u2019re giving you more pancakes! So grab the syrup, and let&#8217;s make a full-stack of MEAN. This is the first post in a three-part series! Here&#8217;s part 2 and part [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-1\" \/>\n<meta property=\"og:site_name\" content=\"Ionic Blog\" \/>\n<meta property=\"article:published_time\" content=\"2016-08-17T15:05:49+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2016-09-01T05:58:43+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.herokucdn.com\/deploy\/button.svg\" \/>\n<meta name=\"author\" content=\"Justin Leatherwood\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@ionicframework\" \/>\n<meta name=\"twitter:site\" content=\"@ionicframework\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Justin Leatherwood\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-1#article\",\"isPartOf\":{\"@id\":\"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-1\"},\"author\":{\"name\":\"Justin Leatherwood\",\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/person\/ebd8f9961dbecd11be74bf51d440689b\"},\"headline\":\"One MEAN Ionic 2 Todo App on Heroku, Part 1\",\"datePublished\":\"2016-08-17T15:05:49+00:00\",\"dateModified\":\"2016-09-01T05:58:43+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-1\"},\"wordCount\":1406,\"commentCount\":28,\"publisher\":{\"@id\":\"https:\/\/ionic.io\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-1#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.herokucdn.com\/deploy\/button.svg\",\"keywords\":[\"Ionic 2\",\"Tutorials\"],\"articleSection\":[\"All\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-1#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-1\",\"url\":\"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-1\",\"name\":\"One MEAN Ionic 2 Todo App on Heroku, Part 1 - Ionic Blog\",\"isPartOf\":{\"@id\":\"https:\/\/ionic.io\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-1#primaryimage\"},\"image\":{\"@id\":\"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-1#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.herokucdn.com\/deploy\/button.svg\",\"datePublished\":\"2016-08-17T15:05:49+00:00\",\"dateModified\":\"2016-09-01T05:58:43+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-1#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-1\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-1#primaryimage\",\"url\":\"https:\/\/www.herokucdn.com\/deploy\/button.svg\",\"contentUrl\":\"https:\/\/www.herokucdn.com\/deploy\/button.svg\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-1#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/ionic.io\/blog\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"One MEAN Ionic 2 Todo App on Heroku, Part 1\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/ionic.io\/blog\/#website\",\"url\":\"https:\/\/ionic.io\/blog\/\",\"name\":\"ionic.io\/blog\",\"description\":\"Build amazing native and progressive web apps with the web\",\"publisher\":{\"@id\":\"https:\/\/ionic.io\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/ionic.io\/blog\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/ionic.io\/blog\/#organization\",\"name\":\"Ionic\",\"url\":\"https:\/\/ionic.io\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2020\/10\/white-on-color.png\",\"contentUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2020\/10\/white-on-color.png\",\"width\":1920,\"height\":854,\"caption\":\"Ionic\"},\"image\":{\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/x.com\/ionicframework\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/person\/ebd8f9961dbecd11be74bf51d440689b\",\"name\":\"Justin Leatherwood\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/b618dcf46835261d07da1f0caf5847b8cf86ac4aae30f6073764ed6747e57544?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/b618dcf46835261d07da1f0caf5847b8cf86ac4aae30f6073764ed6747e57544?s=96&d=mm&r=g\",\"caption\":\"Justin Leatherwood\"},\"url\":\"https:\/\/ionic.io\/blog\/author\/justin\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"One MEAN Ionic 2 Todo App on Heroku, Part 1 - Ionic Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-1","og_locale":"en_US","og_type":"article","og_title":"One MEAN Ionic 2 Todo App on Heroku, Part 1","og_description":"Given the choice between a short or tall stack of pancakes, which would you get? The correct answer is always more pancakes. In this post, we\u2019re giving you more pancakes! So grab the syrup, and let&#8217;s make a full-stack of MEAN. This is the first post in a three-part series! Here&#8217;s part 2 and part [&hellip;]","og_url":"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-1","og_site_name":"Ionic Blog","article_published_time":"2016-08-17T15:05:49+00:00","article_modified_time":"2016-09-01T05:58:43+00:00","og_image":[{"url":"https:\/\/www.herokucdn.com\/deploy\/button.svg"}],"author":"Justin Leatherwood","twitter_card":"summary_large_image","twitter_creator":"@ionicframework","twitter_site":"@ionicframework","twitter_misc":{"Written by":"Justin Leatherwood","Est. reading time":"10 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-1#article","isPartOf":{"@id":"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-1"},"author":{"name":"Justin Leatherwood","@id":"https:\/\/ionic.io\/blog\/#\/schema\/person\/ebd8f9961dbecd11be74bf51d440689b"},"headline":"One MEAN Ionic 2 Todo App on Heroku, Part 1","datePublished":"2016-08-17T15:05:49+00:00","dateModified":"2016-09-01T05:58:43+00:00","mainEntityOfPage":{"@id":"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-1"},"wordCount":1406,"commentCount":28,"publisher":{"@id":"https:\/\/ionic.io\/blog\/#organization"},"image":{"@id":"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-1#primaryimage"},"thumbnailUrl":"https:\/\/www.herokucdn.com\/deploy\/button.svg","keywords":["Ionic 2","Tutorials"],"articleSection":["All"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-1#respond"]}]},{"@type":"WebPage","@id":"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-1","url":"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-1","name":"One MEAN Ionic 2 Todo App on Heroku, Part 1 - Ionic Blog","isPartOf":{"@id":"https:\/\/ionic.io\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-1#primaryimage"},"image":{"@id":"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-1#primaryimage"},"thumbnailUrl":"https:\/\/www.herokucdn.com\/deploy\/button.svg","datePublished":"2016-08-17T15:05:49+00:00","dateModified":"2016-09-01T05:58:43+00:00","breadcrumb":{"@id":"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-1#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-1"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-1#primaryimage","url":"https:\/\/www.herokucdn.com\/deploy\/button.svg","contentUrl":"https:\/\/www.herokucdn.com\/deploy\/button.svg"},{"@type":"BreadcrumbList","@id":"https:\/\/ionic.io\/blog\/one-mean-ionic-2-todo-app-on-heroku-part-1#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/ionic.io\/blog"},{"@type":"ListItem","position":2,"name":"One MEAN Ionic 2 Todo App on Heroku, Part 1"}]},{"@type":"WebSite","@id":"https:\/\/ionic.io\/blog\/#website","url":"https:\/\/ionic.io\/blog\/","name":"ionic.io\/blog","description":"Build amazing native and progressive web apps with the web","publisher":{"@id":"https:\/\/ionic.io\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/ionic.io\/blog\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/ionic.io\/blog\/#organization","name":"Ionic","url":"https:\/\/ionic.io\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ionic.io\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2020\/10\/white-on-color.png","contentUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2020\/10\/white-on-color.png","width":1920,"height":854,"caption":"Ionic"},"image":{"@id":"https:\/\/ionic.io\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/ionicframework"]},{"@type":"Person","@id":"https:\/\/ionic.io\/blog\/#\/schema\/person\/ebd8f9961dbecd11be74bf51d440689b","name":"Justin Leatherwood","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ionic.io\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/b618dcf46835261d07da1f0caf5847b8cf86ac4aae30f6073764ed6747e57544?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/b618dcf46835261d07da1f0caf5847b8cf86ac4aae30f6073764ed6747e57544?s=96&d=mm&r=g","caption":"Justin Leatherwood"},"url":"https:\/\/ionic.io\/blog\/author\/justin"}]}},"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/posts\/1298","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/users\/30"}],"replies":[{"embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/comments?post=1298"}],"version-history":[{"count":0,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/posts\/1298\/revisions"}],"wp:attachment":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/media?parent=1298"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/categories?post=1298"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/tags?post=1298"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}