{"id":1149,"date":"2017-09-01T07:00:21","date_gmt":"2017-09-01T14:00:21","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/midwest-js-project-source-full-stack-node-development-available\/"},"modified":"2017-09-01T07:00:21","modified_gmt":"2017-09-01T14:00:21","slug":"midwest-js-project-source-full-stack-node-development-available","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/midwest-js-project-source-full-stack-node-development-available\/","title":{"rendered":"Midwest JS Project Source on Full Stack Node Development, Available"},"content":{"rendered":"\n<p>Back in August I had participated in <a href=\"https:\/\/midwestjs.com\/\" target=\"_blank\" rel=\"noopener\">Midwest JS<\/a> located in\u00a0Minneapolis,\u00a0Minnesota. As you may know, I&#8217;m a huge fan of developing full stack applications with the JavaScript stack. This is exactly what I had presented on at the conference.<\/p>\n\n\n\n<p>My session was well attended and many developers were taught how to use Node.js with Couchbase to develop a RESTful API, and Angular as the client facing layer.<\/p>\n\n\n\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-3953 size-full\" src=\"https:\/\/www.couchbase.com\/wp-content\/uploads\/sites\/5\/2026\/05\/midwestjs-couchbase.jpg\" alt=\"Couchbase at Midwest JS\" width=\"768\" height=\"558\"><\/p>\n\n\n\n<p>As promised, I am going to revisit the material I went over during the presentation so the concepts and code can be reproduced and expanded upon.<\/p>\n\n\n\n<p><!--more--><\/p>\n\n\n\n<p>Going forward, the assumption is that you&#8217;ve got <a href=\"https:\/\/www.couchbase.com\" target=\"_blank\" rel=\"noopener\">Couchbase Server<\/a>, <a href=\"https:\/\/nodejs.org\" target=\"_blank\" rel=\"noopener\">Node.js<\/a>, and the <a href=\"https:\/\/ionicframework.com\/\" target=\"_blank\" rel=\"noopener\">Ionic Framework<\/a> CLI installed and configured. Couchbase will be the NoSQL Database, Node.js will power our backend, and Ionic Framework will give us a web frontend powered by Angular.<\/p>\n\n\n\n<p>The project created at Midwest JS allowed you to store information about video game consoles and video games for various consoles. This demonstrated the use of CRUD as well as relationships between NoSQL documents and how Couchbase makes it easy.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Creating the Node.js with Couchbase NoSQL Backend<\/h2>\n\n\n\n<p>Before we can begin development, we need to create a new Node.js project. From the command line, execute the following:<\/p>\n\n\n<p>[crayon lang=&#8221;default&#8221; decode=&#8221;true&#8221;]npm init -y<br \/>\nnpm install couchbase express body-parser uuid cors &#8211;save[\/crayon]<\/p>\n\n\n\n<p>The above command will create a project\u00a0<strong>package.json<\/strong> file and install our project dependencies. The <code>cors<\/code> package will allow us to use Node and Angular locally on two different ports without getting cross origin resource sharing errors. The <code>uuid<\/code> package will allow us to generate unique strings for use as document keys. The <code>body-parser<\/code> package will allow us to send JSON data in HTTP requests. We&#8217;ll be using Express and Couchbase which explains the other two packages.<\/p>\n\n\n\n<p>Create an\u00a0<strong>app.js<\/strong> file within your project. It will contain all the source code for our Node.js application. As boilerplate, it should look like the following:<\/p>\n\n\n<p>[crayon lang=&#8221;default&#8221; decode=&#8221;true&#8221;]var Couchbase = require(&#8220;couchbase&#8221;);<br \/>\nvar Express = require(&#8220;express&#8221;);<br \/>\nvar BodyParser = require(&#8220;body-parser&#8221;);<br \/>\nvar UUID = require(&#8220;uuid&#8221;);<br \/>\nvar Cors = require(&#8220;cors&#8221;);<\/p>\n<p>var app = Express();<br \/>\nvar N1qlQuery = Couchbase.N1qlQuery;<\/p>\n<p>app.use(BodyParser.json());<br \/>\napp.use(BodyParser.urlencoded({ extended: true }));<br \/>\napp.use(Cors());<\/p>\n<p>var cluster = new Couchbase.Cluster(&#8220;couchbase:\/\/localhost&#8221;);<br \/>\nvar bucket = cluster.openBucket(&#8220;default&#8221;, &#8220;&#8221;);<\/p>\n<p>app.get(&#8220;\/consoles&#8221;, (request, response) =&gt; {});<br \/>\napp.post(&#8220;\/console&#8221;, (request, response) =&gt; {});<br \/>\napp.post(&#8220;\/game&#8221;, (request, response) =&gt; {});<br \/>\napp.get(&#8220;\/games&#8221;, (request, response) =&gt; {});<br \/>\napp.get(&#8220;\/game\/:id&#8221;, (request, response) =&gt; {});<\/p>\n<p>var server = app.listen(3000, () =&gt; {<br \/>\n    console.log(&#8220;Listening on port &#8221; + server.address().port + &#8220;&#8230;&#8221;);<br \/>\n});[\/crayon]<\/p>\n\n\n\n<p>Notice that we&#8217;ve imported each of the downloaded dependencies, initialized and configured Express, and connected to a Bucket in our Couchbase cluster.<\/p>\n\n\n\n<p>We will have five different RESTful API endpoints for this application.<\/p>\n\n\n\n<p>The first logical thing to do would be to create a video game console so we can add games to it. Take a look at the following endpoint code:<\/p>\n\n\n<p>[crayon lang=&#8221;default&#8221; decode=&#8221;true&#8221;]app.post(&#8220;\/console&#8221;, (request, response) =&gt; {<br \/>\n    if(!request.body.title) {<br \/>\n        return response.status(401).send({ &#8220;message&#8221;: &#8220;A `title` is required.&#8221; });<br \/>\n    }<br \/>\n    var id = UUID.v4();<br \/>\n    request.body.type = &#8220;console&#8221;;<br \/>\n    bucket.insert(id, request.body, (error, result) =&gt; {<br \/>\n        if(error) {<br \/>\n            return response.status(500).send(error);<br \/>\n        }<br \/>\n        response.send(result);<br \/>\n    });<br \/>\n});[\/crayon]<\/p>\n\n\n\n<p>In the above logic, we are validating that a <code>title<\/code> exists in our request. If it does, we will generate a new id, assign a <code>type<\/code> to the data in our request, and insert it into Couchbase. The success or failure response of the insert will be returned to the client, which will eventually be an Angular application.<\/p>\n\n\n\n<p>To query for video game consoles, we&#8217;ll need to query based on the <code>type<\/code> property. For this reason, we&#8217;ll have to use a N1QL query rather than a lookup by id.<\/p>\n\n\n<p>[crayon lang=&#8221;default&#8221; decode=&#8221;true&#8221;]app.get(&#8220;\/consoles&#8221;, (request, response) =&gt; {<br \/>\n    var statement = &#8220;SELECT `&#8221; + bucket._name + &#8220;`.*, META().id FROM `&#8221; + bucket._name + &#8220;` WHERE type = &#8216;console'&#8221;;<br \/>\n    var query = N1qlQuery.fromString(statement);<br \/>\n    query.consistency(N1qlQuery.Consistency.REQUEST_PLUS);<br \/>\n    bucket.query(query, (error, result) =&gt; {<br \/>\n        if(error) {<br \/>\n            return response.status(500).send(error);<br \/>\n        }<br \/>\n        response.send(result);<br \/>\n    });<br \/>\n});[\/crayon]<\/p>\n\n\n\n<p>The N1QL query is nothing more than a simple <code>SELECT<\/code> statement that you&#8217;d find in SQL. After executing the query, we would return the response back to the client.<\/p>\n\n\n\n<p>This brings us to the actual video games. Things get a little more complex, but not more difficult.<\/p>\n\n\n<p>[crayon lang=&#8221;default&#8221; decode=&#8221;true&#8221;]app.post(&#8220;\/game&#8221;, (request, response) =&gt; {<br \/>\n    if(!request.body.title) {<br \/>\n        return response.status(401).send({ &#8220;message&#8221;: &#8220;A `title` is required.&#8221; });<br \/>\n    } else if(!request.body.cid) {<br \/>\n        return response.status(401).send({ &#8220;message&#8221;: &#8220;A `cid` is required.&#8221; });<br \/>\n    }<br \/>\n    var id = UUID.v4();<br \/>\n    request.body.type = &#8220;game&#8221;;<br \/>\n    bucket.insert(id, request.body, (error, result) =&gt; {<br \/>\n        if(error) {<br \/>\n            return response.status(500).send(error);<br \/>\n        }<br \/>\n        response.send(result);<br \/>\n    });<br \/>\n});[\/crayon]<\/p>\n\n\n\n<p>In the above endpoint logic, we plan to insert a new video game into the database. This is no different than what we saw when inserting a new video game console into the database. We are defining a <code>type<\/code> property, but we are also making sure a <code>cid<\/code> exists. The <code>cid<\/code> will be a console id which will allow us to establish a relationship with our data.<\/p>\n\n\n\n<p>When you have relationships, you have <code>JOIN<\/code> operations.<\/p>\n\n\n<p>[crayon lang=&#8221;default&#8221; decode=&#8221;true&#8221;]app.get(&#8220;\/games&#8221;, (request, response) =&gt; {<br \/>\n    var statement = &#8220;SELECT game.title AS game_title, console.title AS console_title FROM `&#8221; + bucket._name + &#8220;` AS game JOIN `&#8221; + bucket._name + &#8220;` AS console ON KEYS game.cid WHERE game.type = &#8216;game'&#8221;;<br \/>\n    var query = N1qlQuery.fromString(statement);<br \/>\n    query.consistency(N1qlQuery.Consistency.REQUEST_PLUS);<br \/>\n    bucket.query(query, (error, result) =&gt; {<br \/>\n        if(error) {<br \/>\n            return response.status(500).send(error);<br \/>\n        }<br \/>\n        response.send(result);<br \/>\n    });<br \/>\n});[\/crayon]<\/p>\n\n\n\n<p>In the above endpoint, we are doing another N1QL query, but this time we have a <code>JOIN<\/code> operation. It isn&#8217;t useful to return a <code>cid<\/code> when querying for video games, so we <code>JOIN<\/code> and replace that information with the console title of the other document.<\/p>\n\n\n\n<p>Likewise we have a similar query when trying to find a specific video game:<\/p>\n\n\n<p>[crayon lang=&#8221;default&#8221; decode=&#8221;true&#8221;]app.get(&#8220;\/game\/:id&#8221;, (request, response) =&gt; {<br \/>\n    if(!request.params.id) {<br \/>\n        return response.status(401).send({ &#8220;message&#8221;: &#8220;An `id` is required.&#8221; });<br \/>\n    }<br \/>\n    var statement = &#8220;SELECT game.title AS game_title, console.title AS console_title FROM `&#8221; + bucket._name + &#8220;` AS game JOIN `&#8221; + bucket._name + &#8220;` AS console ON KEYS game.cid WHERE game.type = &#8216;game&#8217; AND META(game).id = $id&#8221;;<br \/>\n    var query = N1qlQuery.fromString(statement);<br \/>\n    bucket.query(query, { &#8220;id&#8221;: request.params.id }, (error, result) =&gt; {<br \/>\n        if(error) {<br \/>\n            return response.status(500).send(error);<br \/>\n        }<br \/>\n        response.send(result);<br \/>\n    });<br \/>\n});[\/crayon]<\/p>\n\n\n\n<p>The alternative to using N1QL and <code>JOIN<\/code> operations would be to do two lookups based on id. There is nothing wrong with this practice, but in my opinion it is easier to just let the database take care of a <code>JOIN<\/code> rather than trying to <code>JOIN<\/code> via the application layer.<\/p>\n\n\n\n<p>This brings us to the client frontend.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Creating the Ionic Framework with Angular Frontend<\/h2>\n\n\n\n<p>As previously mentioned, this time around we are using Ionic Framework which uses a flavor of Angular. I chose this because I was feeling too lazy to create an attractive frontend with Bootstrap or Foundation.<\/p>\n\n\n\n<p>With the Ionic Framework CLI available, execute the following:<\/p>\n\n\n<p>[crayon lang=&#8221;default&#8221; decode=&#8221;true&#8221;]ionic start pwa sidemenu[\/crayon]<\/p>\n\n\n\n<p>The above command will create a project called <strong>pwa<\/strong> using the Ionic Framework <code>sidemenu<\/code> template.<\/p>\n\n\n\n<p>The base template is useful, but it doesn&#8217;t have everything we need. We need to add a few pages to the application.<\/p>\n\n\n\n<p>Using the Ionic Framework generators, or manually, create a <strong>consoles<\/strong>, <strong>games<\/strong>, and <strong>game<\/strong> page. Each of these pages should have an HTML, SCSS, and TypeScript file and each page directory should be in the <strong>pages<\/strong> directory.<\/p>\n\n\n\n<p>Open the project&#8217;s\u00a0<strong>app\/app.component.ts<\/strong> file and make it look like the following:<\/p>\n\n\n<p>[crayon lang=&#8221;default&#8221; decode=&#8221;true&#8221;]import { Component, ViewChild } from &#8216;@angular\/core&#8217;;<br \/>\nimport { Nav, Platform } from &#8216;ionic-angular&#8217;;<br \/>\nimport { StatusBar } from &#8216;@ionic-native\/status-bar&#8217;;<br \/>\nimport { SplashScreen } from &#8216;@ionic-native\/splash-screen&#8217;;<\/p>\n<p>import { GamesPage } from &#8216;..\/pages\/games\/games&#8217;;<br \/>\nimport { ConsolesPage } from &#8216;..\/pages\/consoles\/consoles&#8217;;<\/p>\n<p>@Component({<br \/>\n  templateUrl: &#8216;app.html&#8217;<br \/>\n})<br \/>\nexport class MyApp {<br \/>\n  @ViewChild(Nav) nav: Nav;<\/p>\n<p>  rootPage: any = GamesPage;<\/p>\n<p>  pages: Array&lt;{title: string, component: any}&gt;;<\/p>\n<p>  constructor(public platform: Platform, public statusBar: StatusBar, public splashScreen: SplashScreen) {<br \/>\n    this.initializeApp();<\/p>\n<p>    \/\/ used for an example of ngFor and navigation<br \/>\n    this.pages = [<br \/>\n      { title: &#8216;Games&#8217;, component: GamesPage },<br \/>\n      { title: &#8216;Consoles&#8217;, component: ConsolesPage }<br \/>\n    ];<\/p>\n<p>  }<\/p>\n<p>  initializeApp() {<br \/>\n    this.platform.ready().then(() =&gt; {<br \/>\n      \/\/ Okay, so the platform is ready and our plugins are available.<br \/>\n      \/\/ Here you can do any higher level native things you might need.<br \/>\n      this.statusBar.styleDefault();<br \/>\n      this.splashScreen.hide();<br \/>\n    });<br \/>\n  }<\/p>\n<p>  openPage(page) {<br \/>\n    \/\/ Reset the content nav to have just this page<br \/>\n    \/\/ we wouldn&#8217;t want the back button to show in this scenario<br \/>\n    this.nav.setRoot(page.component);<br \/>\n  }<br \/>\n}[\/crayon]<\/p>\n\n\n\n<p>Notice that we&#8217;ve imported\u00a0<code>GamesPage<\/code> and <code>ConsolesPage<\/code>, updated the <code>pages<\/code> array, and set the default root page as <code>GamesPage<\/code>. By doing this we&#8217;ve set up navigation and the default page when the application launches.<\/p>\n\n\n\n<p>To complete the setup, we also need to alter the project&#8217;s\u00a0<strong>app\/app.module.ts<\/strong> file. Make it look like the following:<\/p>\n\n\n<p>[crayon lang=&#8221;default&#8221; decode=&#8221;true&#8221;]import { BrowserModule } from &#8216;@angular\/platform-browser&#8217;;<br \/>\nimport { ErrorHandler, NgModule } from &#8216;@angular\/core&#8217;;<br \/>\nimport { IonicApp, IonicErrorHandler, IonicModule } from &#8216;ionic-angular&#8217;;<br \/>\nimport { HttpModule } from &#8220;@angular\/http&#8221;;<\/p>\n<p>import { MyApp } from &#8216;.\/app.component&#8217;;<br \/>\nimport { GamesPage } from &#8216;..\/pages\/games\/games&#8217;;<br \/>\nimport { GamePage } from &#8216;..\/pages\/game\/game&#8217;;<br \/>\nimport { ConsolesPage } from &#8216;..\/pages\/consoles\/consoles&#8217;;<\/p>\n<p>import { StatusBar } from &#8216;@ionic-native\/status-bar&#8217;;<br \/>\nimport { SplashScreen } from &#8216;@ionic-native\/splash-screen&#8217;;<\/p>\n<p>@NgModule({<br \/>\n  declarations: [<br \/>\n    MyApp,<br \/>\n    GamesPage,<br \/>\n    GamePage,<br \/>\n    ConsolesPage<br \/>\n  ],<br \/>\n  imports: [<br \/>\n    BrowserModule,<br \/>\n    HttpModule,<br \/>\n    IonicModule.forRoot(MyApp),<br \/>\n  ],<br \/>\n  bootstrap: [IonicApp],<br \/>\n  entryComponents: [<br \/>\n    MyApp,<br \/>\n    GamesPage,<br \/>\n    GamePage,<br \/>\n    ConsolesPage<br \/>\n  ],<br \/>\n  providers: [<br \/>\n    StatusBar,<br \/>\n    SplashScreen,<br \/>\n    {provide: ErrorHandler, useClass: IonicErrorHandler}<br \/>\n  ]<br \/>\n})<br \/>\nexport class AppModule {}[\/crayon]<\/p>\n\n\n\n<p>Notice that we&#8217;ve imported each of our new pages and added them to the <code>declarations<\/code> and <code>entryComponents<\/code> arrays of the <code>@NgModule<\/code> block.<\/p>\n\n\n\n<p>Now we can focus on the development of the application and connecting it to our API.<\/p>\n\n\n\n<p>Open the project&#8217;s\u00a0<strong>src\/pages\/games\/games.ts<\/strong> file and make it look like the following. We&#8217;re going to break down what is happening next.<\/p>\n\n\n\n<p><p>[crayon lang=&#8221;default&#8221; decode=&#8221;true&#8221;]var Couchbase = require(&#8220;couchbase&#8221;);<br \/>\nvar Express = require(&#8220;express&#8221;);<br \/>\nvar BodyParser = require(&#8220;body-parser&#8221;);<br \/>\nvar UUID = require(&#8220;uuid&#8221;);<br \/>\nvar Cors = require(&#8220;cors&#8221;);<\/p>\n<p>var app = Express();<br \/>\nvar N1qlQuery = Couchbase.N1qlQuery;<\/p>\n<p>app.use(BodyParser.json());<br \/>\napp.use(BodyParser.urlencoded({ extended: true }));<br \/>\napp.use(Cors());<\/p>\n<p>var cluster = new Couchbase.Cluster(&#8220;couchbase:\/\/localhost&#8221;);<br \/>\nvar bucket = cluster.openBucket(&#8220;default&#8221;, &#8220;&#8221;);<\/p>\n<p>app.get(&#8220;\/consoles&#8221;, (request, response) =&gt; {});<br \/>\napp.post(&#8220;\/console&#8221;, (request, response) =&gt; {});<br \/>\napp.post(&#8220;\/game&#8221;, (request, response) =&gt; {});<br \/>\napp.get(&#8220;\/games&#8221;, (request, response) =&gt; {});<br \/>\napp.get(&#8220;\/game\/:id&#8221;, (request, response) =&gt; {});<\/p>\n<p>var server = app.listen(3000, () =&gt; {<br \/>\n    console.log(&#8220;Listening on port &#8221; + server.address().port + &#8220;&#8230;&#8221;);<br \/>\n});[\/crayon]<\/p>\n0<\/p>\n\n\n\n<p>Within the <code>GamesPage<\/code> class, we have a public variable called <code>games<\/code>. Because it is public, it will be accessible via the HTML. It will contain all the games returned from the Node.js application.<\/p>\n\n\n\n<p>When the page loads, we want to query our endpoint. It is never a good idea to do this in the <code>constructor<\/code> method, so instead we use the <code>ionViewDidEnter<\/code> method. After issuing the request, the result is transformed into JSON and then loaded into our public variable.<\/p>\n\n\n\n<p>If we want to create a new game in our database, things are a little different. We are going to display a modal dialog and collect input.<\/p>\n\n\n\n<p><p>[crayon lang=&#8221;default&#8221; decode=&#8221;true&#8221;]var Couchbase = require(&#8220;couchbase&#8221;);<br \/>\nvar Express = require(&#8220;express&#8221;);<br \/>\nvar BodyParser = require(&#8220;body-parser&#8221;);<br \/>\nvar UUID = require(&#8220;uuid&#8221;);<br \/>\nvar Cors = require(&#8220;cors&#8221;);<\/p>\n<p>var app = Express();<br \/>\nvar N1qlQuery = Couchbase.N1qlQuery;<\/p>\n<p>app.use(BodyParser.json());<br \/>\napp.use(BodyParser.urlencoded({ extended: true }));<br \/>\napp.use(Cors());<\/p>\n<p>var cluster = new Couchbase.Cluster(&#8220;couchbase:\/\/localhost&#8221;);<br \/>\nvar bucket = cluster.openBucket(&#8220;default&#8221;, &#8220;&#8221;);<\/p>\n<p>app.get(&#8220;\/consoles&#8221;, (request, response) =&gt; {});<br \/>\napp.post(&#8220;\/console&#8221;, (request, response) =&gt; {});<br \/>\napp.post(&#8220;\/game&#8221;, (request, response) =&gt; {});<br \/>\napp.get(&#8220;\/games&#8221;, (request, response) =&gt; {});<br \/>\napp.get(&#8220;\/game\/:id&#8221;, (request, response) =&gt; {});<\/p>\n<p>var server = app.listen(3000, () =&gt; {<br \/>\n    console.log(&#8220;Listening on port &#8221; + server.address().port + &#8220;&#8230;&#8221;);<br \/>\n});[\/crayon]<\/p>\n1<\/p>\n\n\n\n<p>The <code>create<\/code> method will display our <code>GamePage<\/code> which will be in modal format. Any data entered in the form on the modal will be returned back to the <code>GamesPage<\/code> and sent via an HTTP request to the API.<\/p>\n\n\n\n<p>Before we take a look at\u00a0<code>GamePage<\/code>, let&#8217;s look at the HTML that powers <code>GamesPage<\/code>.<\/p>\n\n\n\n<p><p>[crayon lang=&#8221;default&#8221; decode=&#8221;true&#8221;]var Couchbase = require(&#8220;couchbase&#8221;);<br \/>\nvar Express = require(&#8220;express&#8221;);<br \/>\nvar BodyParser = require(&#8220;body-parser&#8221;);<br \/>\nvar UUID = require(&#8220;uuid&#8221;);<br \/>\nvar Cors = require(&#8220;cors&#8221;);<\/p>\n<p>var app = Express();<br \/>\nvar N1qlQuery = Couchbase.N1qlQuery;<\/p>\n<p>app.use(BodyParser.json());<br \/>\napp.use(BodyParser.urlencoded({ extended: true }));<br \/>\napp.use(Cors());<\/p>\n<p>var cluster = new Couchbase.Cluster(&#8220;couchbase:\/\/localhost&#8221;);<br \/>\nvar bucket = cluster.openBucket(&#8220;default&#8221;, &#8220;&#8221;);<\/p>\n<p>app.get(&#8220;\/consoles&#8221;, (request, response) =&gt; {});<br \/>\napp.post(&#8220;\/console&#8221;, (request, response) =&gt; {});<br \/>\napp.post(&#8220;\/game&#8221;, (request, response) =&gt; {});<br \/>\napp.get(&#8220;\/games&#8221;, (request, response) =&gt; {});<br \/>\napp.get(&#8220;\/game\/:id&#8221;, (request, response) =&gt; {});<\/p>\n<p>var server = app.listen(3000, () =&gt; {<br \/>\n    console.log(&#8220;Listening on port &#8221; + server.address().port + &#8220;&#8230;&#8221;);<br \/>\n});[\/crayon]<\/p>\n2<\/p>\n\n\n\n<p>In the above HTML, we are looping through our public <code>games<\/code> array. Each object in the array is rendered to the screen within a list. Angular does all the heavy lifting for us.<\/p>\n\n\n\n<p>Open the project&#8217;s\u00a0<strong>src\/pages\/game\/game.ts<\/strong> file and include the following:<\/p>\n\n\n\n<p><p>[crayon lang=&#8221;default&#8221; decode=&#8221;true&#8221;]var Couchbase = require(&#8220;couchbase&#8221;);<br \/>\nvar Express = require(&#8220;express&#8221;);<br \/>\nvar BodyParser = require(&#8220;body-parser&#8221;);<br \/>\nvar UUID = require(&#8220;uuid&#8221;);<br \/>\nvar Cors = require(&#8220;cors&#8221;);<\/p>\n<p>var app = Express();<br \/>\nvar N1qlQuery = Couchbase.N1qlQuery;<\/p>\n<p>app.use(BodyParser.json());<br \/>\napp.use(BodyParser.urlencoded({ extended: true }));<br \/>\napp.use(Cors());<\/p>\n<p>var cluster = new Couchbase.Cluster(&#8220;couchbase:\/\/localhost&#8221;);<br \/>\nvar bucket = cluster.openBucket(&#8220;default&#8221;, &#8220;&#8221;);<\/p>\n<p>app.get(&#8220;\/consoles&#8221;, (request, response) =&gt; {});<br \/>\napp.post(&#8220;\/console&#8221;, (request, response) =&gt; {});<br \/>\napp.post(&#8220;\/game&#8221;, (request, response) =&gt; {});<br \/>\napp.get(&#8220;\/games&#8221;, (request, response) =&gt; {});<br \/>\napp.get(&#8220;\/game\/:id&#8221;, (request, response) =&gt; {});<\/p>\n<p>var server = app.listen(3000, () =&gt; {<br \/>\n    console.log(&#8220;Listening on port &#8221; + server.address().port + &#8220;&#8230;&#8221;);<br \/>\n});[\/crayon]<\/p>\n3<\/p>\n\n\n\n<p>This modal logic is similar to what we&#8217;ve already seen. There will be a form that is bound to HTML and TypeScript. When the <code>ionViewDidEnter<\/code> triggers, we query for console information. This console information will eventually be used for a radio list that the user can select from.<\/p>\n\n\n\n<p>When the user selects the <code>save<\/code> method, the data bound in the public form is passed to the previous <code>GamesPage<\/code> page.<\/p>\n\n\n\n<p>The HTML that powers this modal, found in\u00a0<strong>src\/pages\/game\/game.html<\/strong> looks like this:<\/p>\n\n\n\n<p><p>[crayon lang=&#8221;default&#8221; decode=&#8221;true&#8221;]var Couchbase = require(&#8220;couchbase&#8221;);<br \/>\nvar Express = require(&#8220;express&#8221;);<br \/>\nvar BodyParser = require(&#8220;body-parser&#8221;);<br \/>\nvar UUID = require(&#8220;uuid&#8221;);<br \/>\nvar Cors = require(&#8220;cors&#8221;);<\/p>\n<p>var app = Express();<br \/>\nvar N1qlQuery = Couchbase.N1qlQuery;<\/p>\n<p>app.use(BodyParser.json());<br \/>\napp.use(BodyParser.urlencoded({ extended: true }));<br \/>\napp.use(Cors());<\/p>\n<p>var cluster = new Couchbase.Cluster(&#8220;couchbase:\/\/localhost&#8221;);<br \/>\nvar bucket = cluster.openBucket(&#8220;default&#8221;, &#8220;&#8221;);<\/p>\n<p>app.get(&#8220;\/consoles&#8221;, (request, response) =&gt; {});<br \/>\napp.post(&#8220;\/console&#8221;, (request, response) =&gt; {});<br \/>\napp.post(&#8220;\/game&#8221;, (request, response) =&gt; {});<br \/>\napp.get(&#8220;\/games&#8221;, (request, response) =&gt; {});<br \/>\napp.get(&#8220;\/game\/:id&#8221;, (request, response) =&gt; {});<\/p>\n<p>var server = app.listen(3000, () =&gt; {<br \/>\n    console.log(&#8220;Listening on port &#8221; + server.address().port + &#8220;&#8230;&#8221;);<br \/>\n});[\/crayon]<\/p>\n4<\/p>\n\n\n\n<p>We have a simple list that makes up our form. The form elements are bound to our TypeScript variable and the console information is looped through to populate an HTML <code>select<\/code> element.<\/p>\n\n\n\n<p>This brings us to the final page of the Angular frontend.<\/p>\n\n\n\n<p>Open the project&#8217;s\u00a0<strong>src\/pages\/consoles\/consoles.ts<\/strong> file and include the following:<\/p>\n\n\n\n<p><p>[crayon lang=&#8221;default&#8221; decode=&#8221;true&#8221;]var Couchbase = require(&#8220;couchbase&#8221;);<br \/>\nvar Express = require(&#8220;express&#8221;);<br \/>\nvar BodyParser = require(&#8220;body-parser&#8221;);<br \/>\nvar UUID = require(&#8220;uuid&#8221;);<br \/>\nvar Cors = require(&#8220;cors&#8221;);<\/p>\n<p>var app = Express();<br \/>\nvar N1qlQuery = Couchbase.N1qlQuery;<\/p>\n<p>app.use(BodyParser.json());<br \/>\napp.use(BodyParser.urlencoded({ extended: true }));<br \/>\napp.use(Cors());<\/p>\n<p>var cluster = new Couchbase.Cluster(&#8220;couchbase:\/\/localhost&#8221;);<br \/>\nvar bucket = cluster.openBucket(&#8220;default&#8221;, &#8220;&#8221;);<\/p>\n<p>app.get(&#8220;\/consoles&#8221;, (request, response) =&gt; {});<br \/>\napp.post(&#8220;\/console&#8221;, (request, response) =&gt; {});<br \/>\napp.post(&#8220;\/game&#8221;, (request, response) =&gt; {});<br \/>\napp.get(&#8220;\/games&#8221;, (request, response) =&gt; {});<br \/>\napp.get(&#8220;\/game\/:id&#8221;, (request, response) =&gt; {});<\/p>\n<p>var server = app.listen(3000, () =&gt; {<br \/>\n    console.log(&#8220;Listening on port &#8221; + server.address().port + &#8220;&#8230;&#8221;);<br \/>\n});[\/crayon]<\/p>\n5<\/p>\n\n\n\n<p>While not too different than what we&#8217;ve already seen, we have a new feature. We are using a popup dialog to collect input for new video game console information.<\/p>\n\n\n\n<p>When the popup is dismissed, the following is executed:<\/p>\n\n\n\n<p><p>[crayon lang=&#8221;default&#8221; decode=&#8221;true&#8221;]var Couchbase = require(&#8220;couchbase&#8221;);<br \/>\nvar Express = require(&#8220;express&#8221;);<br \/>\nvar BodyParser = require(&#8220;body-parser&#8221;);<br \/>\nvar UUID = require(&#8220;uuid&#8221;);<br \/>\nvar Cors = require(&#8220;cors&#8221;);<\/p>\n<p>var app = Express();<br \/>\nvar N1qlQuery = Couchbase.N1qlQuery;<\/p>\n<p>app.use(BodyParser.json());<br \/>\napp.use(BodyParser.urlencoded({ extended: true }));<br \/>\napp.use(Cors());<\/p>\n<p>var cluster = new Couchbase.Cluster(&#8220;couchbase:\/\/localhost&#8221;);<br \/>\nvar bucket = cluster.openBucket(&#8220;default&#8221;, &#8220;&#8221;);<\/p>\n<p>app.get(&#8220;\/consoles&#8221;, (request, response) =&gt; {});<br \/>\napp.post(&#8220;\/console&#8221;, (request, response) =&gt; {});<br \/>\napp.post(&#8220;\/game&#8221;, (request, response) =&gt; {});<br \/>\napp.get(&#8220;\/games&#8221;, (request, response) =&gt; {});<br \/>\napp.get(&#8220;\/game\/:id&#8221;, (request, response) =&gt; {});<\/p>\n<p>var server = app.listen(3000, () =&gt; {<br \/>\n    console.log(&#8220;Listening on port &#8221; + server.address().port + &#8220;&#8230;&#8221;);<br \/>\n});[\/crayon]<\/p>\n6<\/p>\n\n\n\n<p>This will take the information found in the form and send it via HTTP to our API which will in turn save the console information to the database.<\/p>\n\n\n\n<p>Awesome right?<\/p>\n\n\n\n<p>The HTML found in the project&#8217;s\u00a0<strong>src\/pages\/consoles\/consoles.html<\/strong> file looks like the following:<\/p>\n\n\n\n<p><p>[crayon lang=&#8221;default&#8221; decode=&#8221;true&#8221;]var Couchbase = require(&#8220;couchbase&#8221;);<br \/>\nvar Express = require(&#8220;express&#8221;);<br \/>\nvar BodyParser = require(&#8220;body-parser&#8221;);<br \/>\nvar UUID = require(&#8220;uuid&#8221;);<br \/>\nvar Cors = require(&#8220;cors&#8221;);<\/p>\n<p>var app = Express();<br \/>\nvar N1qlQuery = Couchbase.N1qlQuery;<\/p>\n<p>app.use(BodyParser.json());<br \/>\napp.use(BodyParser.urlencoded({ extended: true }));<br \/>\napp.use(Cors());<\/p>\n<p>var cluster = new Couchbase.Cluster(&#8220;couchbase:\/\/localhost&#8221;);<br \/>\nvar bucket = cluster.openBucket(&#8220;default&#8221;, &#8220;&#8221;);<\/p>\n<p>app.get(&#8220;\/consoles&#8221;, (request, response) =&gt; {});<br \/>\napp.post(&#8220;\/console&#8221;, (request, response) =&gt; {});<br \/>\napp.post(&#8220;\/game&#8221;, (request, response) =&gt; {});<br \/>\napp.get(&#8220;\/games&#8221;, (request, response) =&gt; {});<br \/>\napp.get(&#8220;\/game\/:id&#8221;, (request, response) =&gt; {});<\/p>\n<p>var server = app.listen(3000, () =&gt; {<br \/>\n    console.log(&#8220;Listening on port &#8221; + server.address().port + &#8220;&#8230;&#8221;);<br \/>\n});[\/crayon]<\/p>\n7<\/p>\n\n\n\n<p>Again, it is near identical to the other HTML files that we&#8217;ve seen.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>You just got a recap of everything I went over at Midwest JS 2017. We saw how to create a Node.js API that communicates with Couchbase, our NoSQL database, as well as creating a frontend using Angular and Ionic Framework. These are just a few components of a full stack application.<\/p>\n\n\n\n<p>For more information on <a href=\"https:\/\/www.couchbase.com\/blog\/build-a-rest-api-with-node-js-express-and-couchbase\/\">using Node.js<\/a> with Couchbase, check out the <a href=\"https:\/\/www.couchbase.com\/developers\/\" target=\"_blank\" rel=\"noopener\">Couchbase Developer Portal<\/a>. If you&#8217;d like me to come back to Midwest JS, let me know in the comments.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Back in August I had participated in Midwest JS located in\u00a0Minneapolis,\u00a0Minnesota. As you may know, I&#8217;m a huge fan of developing full stack applications with the JavaScript stack. This is exactly what I had presented on at the conference. My session was well attended and many developers were taught how to use Node.js with Couchbase [&hellip;]<\/p>\n","protected":false},"author":63,"featured_media":18,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[127,136,54,163,49,18],"tags":[213,281,161,165],"ppma_author":[148],"class_list":["post-1149","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-application-design","category-best-practices-and-tutorials","category-couchbase-server","category-javascript","category-node-js","category-n1ql-query","tag-angular","tag-full-stack","tag-ionic-framework","tag-javascript"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.6 (Yoast SEO v27.6) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Midwest JS Project Source on Full Stack Node Development, Available<\/title>\n<meta name=\"description\" content=\"The full stack Node.js, Angular, and Couchbase NoSQL project source from Midwest JS is now available, with full write-up guide to success.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/midwest-js-project-source-full-stack-node-development-available\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Midwest JS Project Source on Full Stack Node Development, Available\" \/>\n<meta property=\"og:description\" content=\"The full stack Node.js, Angular, and Couchbase NoSQL project source from Midwest JS is now available, with full write-up guide to success.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/midwest-js-project-source-full-stack-node-development-available\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/thepolyglotdeveloper\" \/>\n<meta property=\"article:published_time\" content=\"2017-09-01T14:00:21+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/couchbase-nosql-dbaas.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1800\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Nic Raboy, Developer Advocate, Couchbase\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@nraboy\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Nic Raboy, Developer Advocate, Couchbase\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/midwest-js-project-source-full-stack-node-development-available\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/midwest-js-project-source-full-stack-node-development-available\\\/\"},\"author\":{\"name\":\"Nic Raboy, Developer Advocate, Couchbase\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/person\\\/bb545ebe83bb2d12f91095811d0a72e1\"},\"headline\":\"Midwest JS Project Source on Full Stack Node Development, Available\",\"datePublished\":\"2017-09-01T14:00:21+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/midwest-js-project-source-full-stack-node-development-available\\\/\"},\"wordCount\":3026,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/midwest-js-project-source-full-stack-node-development-available\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/05\\\/couchbase-nosql-dbaas.png\",\"keywords\":[\"Angular\",\"full stack\",\"ionic framework\",\"javascript\"],\"articleSection\":[\"Application Design\",\"Best Practices and Tutorials\",\"Couchbase Server\",\"JavaScript\",\"Node.js\",\"SQL++ \\\/ N1QL Query\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/midwest-js-project-source-full-stack-node-development-available\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/midwest-js-project-source-full-stack-node-development-available\\\/\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/midwest-js-project-source-full-stack-node-development-available\\\/\",\"name\":\"Midwest JS Project Source on Full Stack Node Development, Available\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/midwest-js-project-source-full-stack-node-development-available\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/midwest-js-project-source-full-stack-node-development-available\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/05\\\/couchbase-nosql-dbaas.png\",\"datePublished\":\"2017-09-01T14:00:21+00:00\",\"description\":\"The full stack Node.js, Angular, and Couchbase NoSQL project source from Midwest JS is now available, with full write-up guide to success.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/midwest-js-project-source-full-stack-node-development-available\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/midwest-js-project-source-full-stack-node-development-available\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/midwest-js-project-source-full-stack-node-development-available\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/05\\\/couchbase-nosql-dbaas.png\",\"contentUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/05\\\/couchbase-nosql-dbaas.png\",\"width\":1800,\"height\":630},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/midwest-js-project-source-full-stack-node-development-available\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Midwest JS Project Source on Full Stack Node Development, Available\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/06\\\/logo.svg\",\"contentUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/06\\\/logo.svg\",\"width\":\"1024\",\"height\":\"1024\",\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/person\\\/bb545ebe83bb2d12f91095811d0a72e1\",\"name\":\"Nic Raboy, Developer Advocate, Couchbase\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/bedeb68368d4681aca4c74fe5f697f0c423b80d498ec50fd915ba018b72c101f?s=96&d=mm&r=g8863514d8bed0cf6080f23db40e00354\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/bedeb68368d4681aca4c74fe5f697f0c423b80d498ec50fd915ba018b72c101f?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/bedeb68368d4681aca4c74fe5f697f0c423b80d498ec50fd915ba018b72c101f?s=96&d=mm&r=g\",\"caption\":\"Nic Raboy, Developer Advocate, Couchbase\"},\"description\":\"Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in Java, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Apache Cordova. Nic writes about his development experiences related to making web and mobile development easier to understand.\",\"sameAs\":[\"https:\\\/\\\/www.thepolyglotdeveloper.com\",\"https:\\\/\\\/www.facebook.com\\\/thepolyglotdeveloper\",\"https:\\\/\\\/x.com\\\/nraboy\"],\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/author\\\/nic-raboy-2\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Midwest JS Project Source on Full Stack Node Development, Available","description":"The full stack Node.js, Angular, and Couchbase NoSQL project source from Midwest JS is now available, with full write-up guide to success.","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:\/\/www.couchbase.com\/blog\/midwest-js-project-source-full-stack-node-development-available\/","og_locale":"en_US","og_type":"article","og_title":"Midwest JS Project Source on Full Stack Node Development, Available","og_description":"The full stack Node.js, Angular, and Couchbase NoSQL project source from Midwest JS is now available, with full write-up guide to success.","og_url":"https:\/\/www.couchbase.com\/blog\/midwest-js-project-source-full-stack-node-development-available\/","og_site_name":"The Couchbase Blog","article_author":"https:\/\/www.facebook.com\/thepolyglotdeveloper","article_published_time":"2017-09-01T14:00:21+00:00","og_image":[{"width":1800,"height":630,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/couchbase-nosql-dbaas.png","type":"image\/png"}],"author":"Nic Raboy, Developer Advocate, Couchbase","twitter_card":"summary_large_image","twitter_creator":"@nraboy","twitter_misc":{"Written by":"Nic Raboy, Developer Advocate, Couchbase","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/midwest-js-project-source-full-stack-node-development-available\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/midwest-js-project-source-full-stack-node-development-available\/"},"author":{"name":"Nic Raboy, Developer Advocate, Couchbase","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/bb545ebe83bb2d12f91095811d0a72e1"},"headline":"Midwest JS Project Source on Full Stack Node Development, Available","datePublished":"2017-09-01T14:00:21+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/midwest-js-project-source-full-stack-node-development-available\/"},"wordCount":3026,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/midwest-js-project-source-full-stack-node-development-available\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/couchbase-nosql-dbaas.png","keywords":["Angular","full stack","ionic framework","javascript"],"articleSection":["Application Design","Best Practices and Tutorials","Couchbase Server","JavaScript","Node.js","SQL++ \/ N1QL Query"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/midwest-js-project-source-full-stack-node-development-available\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/midwest-js-project-source-full-stack-node-development-available\/","url":"https:\/\/www.couchbase.com\/blog\/midwest-js-project-source-full-stack-node-development-available\/","name":"Midwest JS Project Source on Full Stack Node Development, Available","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/midwest-js-project-source-full-stack-node-development-available\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/midwest-js-project-source-full-stack-node-development-available\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/couchbase-nosql-dbaas.png","datePublished":"2017-09-01T14:00:21+00:00","description":"The full stack Node.js, Angular, and Couchbase NoSQL project source from Midwest JS is now available, with full write-up guide to success.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/midwest-js-project-source-full-stack-node-development-available\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/midwest-js-project-source-full-stack-node-development-available\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/midwest-js-project-source-full-stack-node-development-available\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/couchbase-nosql-dbaas.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/couchbase-nosql-dbaas.png","width":1800,"height":630},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/midwest-js-project-source-full-stack-node-development-available\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Midwest JS Project Source on Full Stack Node Development, Available"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"The Couchbase Blog","description":"Couchbase, the NoSQL Database","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"The Couchbase Blog","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/06\/logo.svg","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/06\/logo.svg","width":"1024","height":"1024","caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/bb545ebe83bb2d12f91095811d0a72e1","name":"Nic Raboy, Developer Advocate, Couchbase","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/bedeb68368d4681aca4c74fe5f697f0c423b80d498ec50fd915ba018b72c101f?s=96&d=mm&r=g8863514d8bed0cf6080f23db40e00354","url":"https:\/\/secure.gravatar.com\/avatar\/bedeb68368d4681aca4c74fe5f697f0c423b80d498ec50fd915ba018b72c101f?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/bedeb68368d4681aca4c74fe5f697f0c423b80d498ec50fd915ba018b72c101f?s=96&d=mm&r=g","caption":"Nic Raboy, Developer Advocate, Couchbase"},"description":"Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in Java, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Apache Cordova. Nic writes about his development experiences related to making web and mobile development easier to understand.","sameAs":["https:\/\/www.thepolyglotdeveloper.com","https:\/\/www.facebook.com\/thepolyglotdeveloper","https:\/\/x.com\/nraboy"],"url":"https:\/\/www.couchbase.com\/blog\/author\/nic-raboy-2\/"}]}},"acf":[],"authors":[{"term_id":148,"user_id":63,"is_guest":0,"slug":"nic-raboy-2","display_name":"Nic Raboy, Developer Advocate, Couchbase","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/?s=96&d=mm&r=g","0":null,"1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":""}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/1149","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/users\/63"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/comments?post=1149"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/1149\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media\/18"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media?parent=1149"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/categories?post=1149"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/tags?post=1149"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=1149"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}