Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon

How-To Tutorials - Web Development

1802 Articles
article-image-internationalization-localization-node-js-app
Packt Editorial Staff
07 May 2018
15 min read
Save for later

How to implement Internationalization and localization in your Node.js app

Packt Editorial Staff
07 May 2018
15 min read
Internationalization, often abbreviated as i18n, implies a particular software design capable of adapting to the requirements of target local markets. In other words if we want to distribute our application to the markets other than USA we need to take care of translations, formatting of datetime, numbers, addresses, and such. In today’s post we will cover the concept of implementing Internationalization and localization in the Node.js app and look at context menu and system clipboard in detail. Date format by country Internationalization is a cross-cutting concern. When you are changing the locale it usually affects multiple modules. So I suggest going with the observer pattern that we already examined while working on DirService'. The ./js/Service/I18n.jsfile contains the following code: constEventEmitter=require("events"); classI18nServiceextendsEventEmitter{ constructor(){ super(); this.locale="en-US"; } notify(){ this.emit("update"); } } exports.I18nService=I18nService; As you see, we can change the locale by setting a new value to localeproperty. As soon as we call notifymethod, then all the subscribed modules immediately respond. But localeis a public property and therefore we have no control on its access and mutation. We can fix it by using overloading. The ./js/Service/I18n.jsfile contains the following code: //...constructor(){ super(); this._locale="en-US"; } getlocale(){ returnthis._locale; } setlocale(locale){ //validatelocale...this._locale=locale; } //... Now if we access localeproperty of I18ninstance it gets delivered by the getter (getlocale). When setting it a value, it goes through the setter (setlocale). Thus we can add extra functionality such as validation and logging on property access and mutation. Remember we have in the HTML, a combobox for selecting language. Why not give it a view? The ./js/View/LangSelector.jfile contains the following code: classLangSelectorView{ constructor(boundingEl,i18n){ boundingEl.addEventListener("change",this.onChanged.bind(this),false); this.i18n=i18n; } onChanged(e){ constselectEl=e.target;this.i18n.locale=selectEl.value;this.i18n.notify(); } } exports.LangSelectorView=LangSelectorView; In the preceding code, we listen for change events on the combobox. When the event occurs we change localeproperty of the passed in I18ninstance and call notifyto inform the subscribers. The ./js/app.jsfile contains the following code: consti18nService=newI18nService(), {LangSelectorView}=require("./js/View/LangSelector"); newLangSelectorView(document.querySelector("[data-bind=langSelector]"),i18nService); Well, we can change the locale and trigger the event. What about consuming modules? In FileListview we have static method formatTimethat formats the passed in timeStringfor printing. We can make it formated in accordance with currently chosen locale. The ./js/View/FileList.jsfile contains the following code: constructor(boundingEl,dirService,i18nService){ //... this.i18n=i18nService; //Subscribeoni18nServiceupdates i18nService.on("update",()=>this.update( dirService.getFileList())); } staticformatTime(timeString,locale){ constdate=newDate(Date.parse(timeString)),options={ year:"numeric",month:"numeric",day:"numeric",hour:"numeric",minute:"numeric",second:"numeric",hour12:false }; returndate.toLocaleString(locale,options); } update(collection){ //... this.el.insertAdjacentHTML("beforeend",`<liclass="file-listli"data-file="${fInfo.fileName}"> <spanclass="file-listliname">${fInfo.fileName}</span> <spanclass="file- listlisize">${filesize(fInfo.stats.size)}</span> <spanclass="file-listlitime">${FileListView.formatTime( fInfo.stats.mtime,this.i18n.locale)}</span> </li>`); //... } //... In the constructor, we subscribe for I18nupdate event and update the file list every time the locale changes. Static method formatTimeconverts passed in string into a Dateobject and uses Date.prototype.toLocaleString()method to format the datetime according to a given locale. This method belongs to so called ECMAScript Internationalization API (http://norbertlindenberg.com/2012/12/ecmascript-internationalization-api/index.html). The API describes methods of built-in object String, Dateand Numberdesigned to format and compare localized data. But what it really does is formatting a Dateinstance with toLocaleStringfor the English (United States) locale ("en-US") and it returns the date as follows: 3/17/2017, 13:42:23 However if we feed to the method German locale ("de-DE") we get quite a different result: 17.3.2017, 13:42:23 To put it into action we set an identifier to the combobox. The ./index.htmlfile contains the following code: .. <selectclass="footerselect"data-bind="langSelector"> .. And of course, we have to create an instance of I18nservice and pass it in LangSelectorViewand FileListView: ./js/app.js //... const{I18nService}=require("./js/Service/I18n"), {LangSelectorView}=require("./js/View/LangSelector"),i18nService=newI18nService(); newLangSelectorView(document.querySelector("[data-bind=langSelector]"),i18nService); //... newFileListView(document.querySelector("[data-bind=fileList]"),dirService,i18nService); Now we start the application. Yeah! As we change the language in the combobox the file modification dates adjust accordingly: Multilingual support Localization dates and number is a good thing, but it would be more exciting to provide translation to multiple languages. We have a number of terms across the application, namely the column titles of the file list and tooltips (via titleattribute) on windowing action buttons. What we need is a dictionary. Normally it implies sets of token translation pairs mapped to language codes or locales. Thus when you request from the translation service a term, it can correlate to a matching translation according to currently used language/locale. Here I have suggested making the dictionary as a static module that can be loaded with the required function. The ./js/Data/dictionary.jsfile contains the following code: exports.dictionary={"en-US":{ NAME:"Name",SIZE:"Size",MODIFIED:"Modified", MINIMIZE_WIN:"Minimizewindow", RESTORE_WIN:"Restorewindow",MAXIMIZE_WIN:"Maximizewindow",CLOSE_WIN:"Closewindow" }, "de-DE":{ NAME:"Dateiname",SIZE:"Grösse", MODIFIED:"Geändertam",MINIMIZE_WIN:"Fensterminimieren",RESTORE_WIN:"Fensterwiederherstellen",MAXIMIZE_WIN:"Fenstermaximieren", CLOSE_WIN:"Fensterschliessen" } }; So we have two locales with translations per term. We are going to inject the dictionary as a dependency into our I18nservice. The ./js/Service/I18n.jsfile contains the following code: //... constructor(dictionary){ super(); this.dictionary=dictionary; this._locale="en-US"; } translate(token,defaultValue){ constdictionary=this.dictionary[this._locale]; returndictionary[token]||defaultValue; } //... We also added a new method translate that accepts two parameters: tokenand defaulttranslation. The first parameter can be one of the keys from the dictionary like NAME. The second one is guarding value for the case when requested token does not yet exist in the dictionary. Thus we still get a meaningful text at least in English. Let's see how we can use this new method. The ./js/View/FileList.jsfile contains the following code: //... update(collection){ this.el.innerHTML=`<liclass="file-listlifile-listhead"> <spanclass="file-listliname">${this.i18n.translate("NAME","Name")}</span> <spanclass="file-listlisize">${this.i18n.translate("SIZE", "Size")}</span> <spanclass="file-listlitime">${this.i18n.translate("MODIFIED","Modified")}</span> </li>`; //... We change in FileListview hardcoded column titles with calls for translatemethod of I18ninstance, meaning that every time view updates it receives the actual translations. We shall not forget about TitleBarActionsview where we have windowing action buttons. The ./js/View/TitleBarActions.jsfile contains the following code: constructor(boundingEl,i18nService){ this.i18n=i18nService; //... //Subscribeoni18nServiceupdates i18nService.on("update",()=>this.translate()); } translate(){ this.unmaximizeEl.title=this.i18n.translate("RESTORE_WIN","Restorewindow"); this.maximizeEl.title=this.i18n.translate("MAXIMIZE_WIN","Maximizewindow"); this.minimizeEl.title=this.i18n.translate("MINIMIZE_WIN","Minimizewindow"); this.closeEl.title=this.i18n.translate("CLOSE_WIN","Closewindow"); } Here we add method translate, which updates button title attributes with actual translations. We subscribe for i18nupdate event to call the method every time user changes locale: Context menu Well, with our application we can already navigate through the file system and open files. Yet, one might expect more of a File Explorer. We can add some file related actions like delete, copy/paste. Usually these tasks are available via the context menu, what gives us a good opportunity to examine how to make it with NW.js. With the environment integration API we can create an instance of system menu (http://docs.nwjs.io/en/latest/References/Menu/). Then we compose objects representing menu items and attach them to the menu instance (http://docs.nwjs.io/en/latest/References/MenuItem/). This menucan be shown in an arbitrary position: constmenu=newnw.Menu(),menutItem=newnw.MenuItem({ label:"Sayhello", click:()=>console.log("hello!") }); menu.append(menu); menu.popup(10,10); Yet our task is more specific. We have to display the menu on the right mouse click in the position of the cursor. That is, we achieve by subscribing a handler to contextmenuDOM event: document.addEventListener("contextmenu",(e)=>{ console.log(`Showmenuinposition${e.x},${e.y}`); }); Now whenever we right-click within the application window the menu shows up. It's not exactly what we want, isn't it? We need it only when the cursor resides within a particular region. For an instance, when it hovers a file name. That means we have to test if the target element matches our conditions: document.addEventListener("contextmenu",(e)=>{ constel=e.target; if(elinstanceofHTMLElement&&el.parentNode.dataset.file){ console.log(`Showmenuinposition${e.x},${e.y}`); } }); Here we ignore the event until the cursor hovers any cell of file table row, given every row is a list item generated by FileListview and therefore provided with a value for data file attribute. This passage explains pretty much how to build a system menu and how to attach it to the file list. But before starting on a module capable of creating menu, we need a service to handle file operations. The ./js/Service/File.jsfile contains the following code: constfs=require("fs"), path=require("path"), //Copyfilehelper cp=(from,toDir,done)=>{ constbasename=path.basename(from),to=path.join(toDir,basename),write=fs.createWriteStream(to); fs.createReadStream(from) .pipe(write); write .on("finish",done); }; classFileService{ constructor(dirService){this.dir=dirService;this.copiedFile=null; } remove(file){ fs.unlinkSync(this.dir.getFile(file)); this.dir.notify(); } paste(){ constfile=this.copiedFile; if(fs.lstatSync(file).isFile()){ cp(file,this.dir.getDir(),()=>this.dir.notify()); } } copy(file){ this.copiedFile=this.dir.getFile(file); } open(file){ nw.Shell.openItem(this.dir.getFile(file)); } showInFolder(file){ nw.Shell.showItemInFolder(this.dir.getFile(file)); } }; exports.FileService=FileService; What's going on here? FileServicereceives an instance of DirServiceas a constructor argument. It uses the instance to obtain the full path to a file by name ( this.dir.getFile(file)). It also exploits notifymethod of the instance to request all the views subscribed to DirServiceto update. Method showInFoldercalls the corresponding method of nw.Shellto show the file in the parent folder with the system file manager. As you can recon method removedeletes the file. As for copy/paste we do the following trick. When user clicks copy we store the target file path in property copiedFile. So when user next time clicks paste we can use it to copy that file to the supposedly changed current location. Method openevidently opens file with the default associated program. That is what we do in FileListview directly. Actually this action belongs to FileService. So we rather refactor the view to use the service. The ./js/View/FileList.jsfile contains the following code: constructor(boundingEl,dirService,i18nService,fileService){ this.file=fileService; //... } bindUi(){ //... this.file.open(el.dataset.file); //... } Now we have a module to handle context menu for a selected file. The module will subscribe for contextmenuDOM event and build a menu when user right clicks on a file. This menu will contain items Show Item in the Folder, Copy, Paste, and Delete. Whereas copy and paste are separated from other items with delimiters. Besides, Paste will be disabled until we store a file with copy. Further goes the source code. The ./js/View/ContextMenu.jsfile contains the following code: classConextMenuView{ constructor(fileService,i18nService){ this.file=fileService;this.i18n=i18nService;this.attach(); } getItems(fileName){ constfile=this.file, isCopied=Boolean(file.copiedFile); return[ { label:this.i18n.translate("SHOW_FILE_IN_FOLDER","ShowItemintheFolder"), enabled:Boolean(fileName), click:()=>file.showInFolder(fileName) }, { type:"separator" }, { label:this.i18n.translate("COPY","Copy"),enabled:Boolean(fileName), click:()=>file.copy(fileName) }, { label:this.i18n.translate("PASTE","Paste"),enabled:isCopied, click:()=>file.paste() }, { type:"separator" }, { label:this.i18n.translate("DELETE","Delete"),enabled:Boolean(fileName), click:()=>file.remove(fileName) } ]; } render(fileName){ constmenu=newnw.Menu(); this.getItems(fileName).forEach((item)=>menu.append(newnw.MenuItem(item))); returnmenu; } attach(){ document.addEventListener("contextmenu",(e)=>{ constel=e.target; if(!(elinstanceofHTMLElement)){ return; } if(el.classList.contains("file-list")){ e.preventDefault(); this.render() .popup(e.x,e.y); } //Ifachildofanelementmatching[data-file] if(el.parentNode.dataset.file){ e.preventDefault(); this.render(el.parentNode.dataset.file) .popup(e.x,e.y); } }); } } exports.ConextMenuView=ConextMenuView; So in ConextMenuViewconstructor, we receive instances of FileServiceand I18nService. During the construction we also call attach method that subscribes for contextmenuDOM event, creates the menu and shows it in the position of the mouse cursor. The event gets ignored unless the cursor hovers a file or resides in empty area of the file list component. When user right clicks the file list, the menu still appears, but with all items disable except paste (in case a file was copied before). Method render create an instance of menu and populates it with nw.MenuItemscreated by getItemsmethod. The method creates an array representing menu items. Elements of the array are object literals. Property labelaccepts translation for item caption. Property enableddefines the state of item depending on our cases (whether we have copied file or not, whether the cursor on a file or not). Finally property clickexpects the handler for click event. Now we need to enable our new components in the main module. The ./js/app.jsfile contains the following code: const{FileService}=require("./js/Service/File"), {ConextMenuView}=require("./js/View/ConextMenu"),fileService=newFileService(dirService); newFileListView(document.querySelector("[data-bind=fileList]"),dirService,i18nService,fileService); newConextMenuView(fileService,i18nService); Let's now run the application, right-click on a file and voilà! We have the context menu and new file actions. System clipboard Usually Copy/Paste functionality involves system clipboard. NW.jsprovides an API to control it (http://docs.nwjs.io/en/latest/References/Clipboard/). Unfortunately it's quite limited, we cannot transfer an arbitrary file between applications, what you may expect of a file manager. Yet some things we are still available to us. Transferring text In order to examine text transferring with the clipboard we modify the method copy of FileService: copy(file){ this.copiedFile=this.dir.getFile(file);constclipboard=nw.Clipboard.get();clipboard.set(this.copiedFile,"text"); } What does it do? As soon as we obtained file full path, we create an instance of nw.Clipboardand save the file path there as a text. So now, after copying a file within the File Explorer we can switch to an external program (for example, a text editor) and paste the copied path from the clipboard. Transferring graphics It doesn't look very handy, does it? It would be more interesting if we could copy/paste a file. Unfortunately NW.jsdoesn't give us many options when it comes to file exchange. Yet we can transfer between NW.jsapplication and external programs PNG and JPEG images. The ./js/Service/File.jsfile contains the following code: //... copyImage(file,type){ constclip=nw.Clipboard.get(), //loadfilecontentasBase64 data=fs.readFileSync(file).toString("base64"), //imageasHTML html=`<imgsrc="file:///${encodeURI(data.replace(/^//,"") )}">`; //writebothoptions(rawimageandHTML)totheclipboardclip.set([ {type,data:data,raw:true}, {type:"html",data:html} ]); } copy(file){ this.copiedFile=this.dir.getFile(file); constext=path.parse(this.copiedFile).ext.substr(1); switch(ext){case"jpg":case"jpeg": returnthis.copyImage(this.copiedFile,"jpeg"); case"png": returnthis.copyImage(this.copiedFile,"png"); } } //... We extended our FileServicewith private method copyImage. It reads a given file, converts its contents in Base64 and passes the resulting code in a clipboard instance. In addition, it creates HTML with image tag with Base64-encoded image in data Uniform Resource Identifier (URI). Now after copying an image (PNG or JPEG) in the File Explorer, we can paste it in an external program such as graphical editor or text processor. Receiving text and graphics We've learned how to pass a text and graphics from our NW.jsapplication to external programs. But how can we receive data from outside? As you can guess it is accessible through get method of nw.Clipboard. Text can be retrieved that simple: constclip=nw.Clipboard.get(); console.log(clip.get("text")); When graphic is put in the clipboard we can get it with NW.js only as Base64-encoded content or as HTML. To see it in practice we add a few methods to FileService. The ./js/Service/File.jsfile contains the following code: //...hasImageInClipboard(){ constclip=nw.Clipboard.get(); returnclip.readAvailableTypes().indexOf("png")!==-1; } pasteFromClipboard(){ constclip=nw.Clipboard.get(); if(this.hasImageInClipboard()){ constbase64=clip.get("png",true), binary=Buffer.from(base64,"base64"),filename=Date.now()+"--img.png"; fs.writeFileSync(this.dir.getFile(filename),binary); this.dir.notify(); } } //... Method hasImageInClipboardchecks if the clipboard keeps any graphics. Method pasteFromClipboardtakes graphical content from the clipboard as Base64-encoded PNG. It converts the content into binary code, writes into a file and requests DirServicesubscribers to update. To make use of these methods we need to edit ContextMenuview. The ./js/View/ContextMenu.jsfile contains the following code: getItems(fileName){ constfile=this.file, isCopied=Boolean(file.copiedFile); return[ //... { label:this.i18n.translate("PASTE_FROM_CLIPBOARD","Pasteimagefromclipboard"), enabled:file.hasImageInClipboard(), click:()=>file.pasteFromClipboard() }, //... ]; } We add to the menu a new item Pasteimagefromclipboard, which is enabled only when there is any graphic in the clipboard. [box type="shadow" align="" class="" width=""]This article is an excerpt from the book Cross Platform Desktop Application Development: Electron, Node, NW.js and React written by Dmitry Sheiko. This book will help you build powerful cross-platform desktop applications with web technologies such as Node, NW.JS, Electron, and React.[/box] Read More: How to deploy a Node.js application to the web using Heroku How is Node.js Changing Web Development? With Node.js, it’s easy to get things done  
Read more
  • 0
  • 0
  • 10156

article-image-unit-testing-in-net-core-with-visual-studio-2017-for-better-code-quality
Kunal Chaudhari
07 May 2018
12 min read
Save for later

Unit Testing in .NET Core with Visual Studio 2017 for better code quality

Kunal Chaudhari
07 May 2018
12 min read
The famous Java programmer, Bruce Eckel, came up with a slogan which highlights the importance of testing software: If it ain't tested, it's broken. Though a confident programmer may challenge this, it beautifully highlights the ability to determine that code works as expected over and over again, without any exception. How do we know that the code we are shipping to the end user or customer is of good quality and all the user requirements would work? By testing? Yes, by testing, we can be confident that the software works as per customer requirements and specifications. If there are any discrepancies between expected and actual behavior, it is referred to as a bug/defect in the software. The earlier the discrepancies are caught, the more easily they can be fixed before the software is shipped, and the results are good quality. No wonder software testers are also referred to as quality control analysts in various software firms. The mantra for a good software tester is: In God we trust, the rest we test. In this article, we will understand the testing deployment model of .NET Core applications, the Live Unit Testing feature of Visual Studio 2017. We will look at types of testing methods briefly and write our unit tests, which a software developer must write after writing any program. Software testing is conducted at various levels: Unit testing: While coding, the developer conducts tests on a unit of a program to validate that the code they have written is error-free. We will write a few unit tests shortly. Integration testing: In a team where a number of developers are working, there may be different components that the developers are working on. Even if all developers perform unit testing and ensure that their units are working fine, there is still a need to ensure that, upon integration of these components, they work without any error. This is achieved through integration testing. System testing: The entire software product is tested as a whole. This is accomplished using one or more of the following: Functionality testing: Test all the functionality of the software against the business requirement document. Performance testing: To test how performant the software is. It tests the average time, resource utilization, and so on, taken by the software to complete a desired business use case. This is done by means of load testing and stress testing, where the software is put under high user and data load. Security testing: Tests how secure the software is against common and well-known security threats. Accessibility testing: Tests if the user interface is accessible and user-friendly to specially-abled people or not. User acceptance testing: When the software is ready to be handed over to the customer, it goes through a round of testing by the customer for user interaction and response. Regression testing: Whenever a piece of code is added/updated in the software to add a new functionality or fix an existing functionality, it is tested to detect if there are any side-effects from the newly added/updated code. Of all these different types of testing, we will focus on unit testing, as it is done by the developer while coding the functionality. Unit testing .NET Core has been designed with testability in mind. .NET Core 2.0 has unit test project templates for VB, F#, and C#. We can also pick the testing framework of our choice amongst xUnit, NUnit, and MSTest. Unit tests that test single programming parts are the most minimal-level tests. Unit tests should just test code inside the developer's control, and ought to not test infrastructure concerns, for example, databases, filesystems, or network resources. Unit tests might be composed utilizing test-driven development (TDD) or they can be added to existing code to affirm its accuracy. The naming convention of Test class names should end with Test and reside in the same namespace as the class being tested. For instance, the unit tests for the Microsoft.Example.AspNetCore class would be in the Microsoft.Example.AspNetCoreTest class in the test assembly. Also, unit test method names must be descriptive about what is being tested, under what conditions, and what the expectations are. A good unit test has three main parts to it in the following specified order: Arrange Act Assert We first arrange the code and then act on it and then do a series of asserts to check if the actual output matches the expected output. Let's have a look at them in detail: Arrange: All the parameter building, and method invocations needed for making a call in the act section must be declared in the arrange section. Act: The act stage should be one statement and as simple as possible. This one statement should be a call to the method that we are trying to test. Assert: The only reason method invocation may fail is if the method itself throws an exception, else, there should always be some state change or output from any meaningful method invocation. When we write the act statement, we anticipate an output and then do assertions if the actual output is the same as expected. If the method under test should throw an exception under normal circumstances, we can do assertions on the type of exception and the error message that should be thrown. We should be watchful while writing unit test cases, that we don't inject any dependencies on the infrastructure. Infrastructure dependencies should be taken care of in integration test cases, not in unit tests. We can maintain a strategic distance from these shrouded dependencies in our application code by following the Explicit Dependencies Principle and utilizing Dependency Injection to request our dependencies on the framework. We can likewise keep our unit tests in a different project from our integration tests and guarantee our unit test project doesn't have references to the framework. Testing using xUnit In this section, we will learn to write unit and integration tests for our controllers. There are a number of options available to us for choosing the test framework. We will use xUnit for all our unit tests and Moq for mocking objects. Let's create an xUnit test project by doing the following: Open the Let's Chat project in Visual Studio 2017 Create a new folder named  Test Right-click the Test folder and click Add | New Project Select xUnit Test Project (.NET Core) under Visual C# project templates, as shown here: Delete the default test class that gets created with the template Create a test class inside this project AuthenticationControllerUnitTests for the unit test We need to add some NuGet packages. Right-click the project in VS 2017 to edit the project file and add the references manually, or use the NuGet Package Manager to add these packages: // This package contains dependencies to ASP.NET Core <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" /> // This package is useful for the integration testing, to build a test host for the project to test. <PackageReference Include="Microsoft.AspNetCore.TestHost" Version="2.0.0" /> // Moq is used to create fake objects <PackageReference Include="Moq" Version="4.7.63" /> With this, we are now ready to write our unit tests. Let's start doing this, but before we do that, here's some quick theory about xUnit and Moq. The documentation from the xUnit website and Wikipedia tells us that xUnit.net is a free, open source, community-focused unit testing tool for the .NET Framework. It is the latest technology for unit testing C#, F#, Visual Basic .NET, and other .NET languages. All xUnit frameworks share the following basic component architecture: Test runner: It is an executable program that runs tests implemented using an xUnit framework and reports the test results. Test case: It is the most elementary class. All unit tests are inherited from here. Test fixtures: Test fixures (also known as a test context) are the set of preconditions or state needed to run a test. The developer should set up a known good state before the tests, and return to the original state after the tests. Test suites: It is a set of tests that all share the same fixture. The order of the tests shouldn't matter. xUnit.net includes support for two different major types of unit test: Facts: Tests which are always true. They test invariant conditions, that is, data-independent tests. Theories: Tests which are only true for a particular set of data. Moq is a mocking framework for C#/.NET. It is used in unit testing to isolate the class under test from its dependencies and ensure that the proper methods on the dependent objects are being called. Recall that in unit tests, we only test a unit or a layer/part of the software in isolation and hence do not bother about external dependencies, so we assume they work fine and just mock them using the mocking framework of our choice. Let's put this theory into action by writing a unit test for the following action in AuthenticationController: public class AuthenticationController : Controller { private readonly ILogger<AuthenticationController> logger; public AuthenticationController(ILogger<AuthenticationController> logger) { this.logger = logger; } [Route("signin")] public IActionResult SignIn() { logger.LogInformation($"Calling {nameof(this.SignIn)}"); return Challenge(new AuthenticationProperties { RedirectUri = "/" }); } } The unit test code depends on how the method to be tested is written. To understand this, let's write a unit test for a SignIn action. To test the SignIn method, we need to invoke the SignIn action in AuthenticationController. To do so, we need an instance of the AuthenticationController class, on which the SignIn action can be invoked. To create the instance of AuthenticationController, we need a logger object, as the AuthenticationController constructor expects it as a parameter. Since we are only testing the SignIn action, we do not bother about the logger and so we can mock it. Let's do it: /// <summary> /// Authentication Controller Unit Test - Notice the naming convention {ControllerName}Test /// </summary> public class AuthenticationControllerTest { /// <summary> /// Mock the dependency needed to initialize the controller. /// </summary> private Mock<ILogger<AuthenticationController>> mockedLogger = new Mock<ILogger<AuthenticationController>>(); /// <summary> /// Tests the SignIn action. /// </summary> [Fact] public void SignIn_Pass_Test() { // Arrange - Initialize the controller. Notice the mocked logger object passed as the parameter. var controller = new AuthenticationController(mockedLogger.Object); // Act - Invoke the method to be tested. var actionResult = controller.SignIn(); // Assert - Make assertions if actual output is same as expected output. Assert.NotNull(actionResult); Assert.IsType<ChallengeResult>(actionResult); Assert.Equal(((ChallengeResult)actionResult). Properties.Items.Count, 1); } } Reading the comments would explain the unit test code. The previous example shows how easy it is to write a unit test. Agreed, depending on the method to be tested, things can get complicated. But it is likely to be around mocking the objects and, with some experience on the mocking framework and binging around, mocking should not be a difficult task. The unit test for the SignOut action would be a bit complicated in terms of mocking as it uses HttpContext. The unit test for the SignOut action is left to the reader as an exercise. Let's explore a new feature introduced in Visual Studio 2017 called Live Unit Testing. Live Unit Testing It may disappoint you but Live Unit Testing (LUT) is available only in the Visual Studio 2017 Enterprise edition and not in the Community edition. What is Live Unit Testing? It's a new productivity feature, introduced in the Visual Studio 2017 Enterprise edition, that provides real-time feedback directly in the Visual Studio editor on how code changes are impacting unit tests and code coverage. All this happens live, while you write the code and hence it is called Live Unit Testing. This will help in maintaining the quality by keeping tests passing as changes are made. It will also remind us when we need to write additional unit tests, as we are making bug fixes or adding features. To start Live Unit Testing: Go to the Test menu item Click Live Unit Testing Click Start, as shown here: On clicking this, your CPU usage may go higher as Visual Studio spawns the MSBuild and tests runner processes in the background. In a short while, the editor will display the code coverage of the individual lines of code that are covered by the unit test. The following image displays the lines of code in AuthenticationController that are covered by the unit test. On clicking the right icon, it displays the tests covering this line of code and also provides the option to run and debug the test: Similarly, if we open the test file, it will show the indicator there as well. Super cool, right! If we navigate to Test|Live Unit Testing now, we would see the options to Stop and Pause. So, in case we wish to save  our resources after getting the data once, we can pause or stop Live Unit Testing: There are numerous icons which indicates the code coverage status of individual lines of code. These are: Red cross: Indicates that the line is covered by at least one failing test Green check mark: Indicates that the line is covered by only passing tests Blue dash: Indicates that the line is not covered by any test If you see a clock-like icon just below any of these icons, it indicates that the data is not up to date. With this productivity-enhancing feature, we conclude our discussion on basic unit testing. Next, we will learn about containers and how we can do the deployment and testing of our .NET Core 2.0 applications in containers. To summarize, we learned the importance of testing and how we can write unit tests using Moq and xUnit. We saw a new productivity-enhancing feature introduced in Visual Studio 2017 Enterprise edition called Live Unit Testing and how it helps us write better-quality code. You read an excerpt from a book written by Rishabh Verma and Neha Shrivastava, titled  .NET Core 2.0 By Example. This book will help you build cross-platform solutions with .NET Core 2.0 through real-life scenarios.   More on Testing: Unit Testing and End-To-End Testing Testing RESTful Web Services with Postman Selenium and data-driven testing: Interview insights
Read more
  • 0
  • 0
  • 5386

article-image-building-two-way-interactive-chatbot-twilio
Gebin George
04 May 2018
4 min read
Save for later

Building a two-way interactive chatbot with Twilio: A step-by-step guide

Gebin George
04 May 2018
4 min read
To build a chatbot that can communicate both ways we need to do two things: build the chatbot into the web app and modify setup configurations in Twilio. To do these, follow these steps: Create an index.js file in the root directory of the project. Install the express and body-parser libraries. These libraries will be used to make a web app: npm install body-parser --save npm install express --save Create a web app in index.js: // Two-way SMS Bot const express = require('express') const bodyParser = require('body-parser') const twilio = require('twilio') const app = express() app.set('port', (process.env.PORT || 5000)) Chapter 5 [ 185 ] // Process application/x-www-form-urlencoded app.use(bodyParser.urlencoded({extended: false})) // Process application/json app.use(bodyParser.json()) // Spin up the server app.listen(app.get('port'), function() { console.log('running on port', app.get('port')) }) // Index route app.get('/', function (req, res) { res.send('Hello world, I am SMS bot.') }) //Twilio webhook app.post('/sms/', function (req, res) { var botSays = 'You said: ' + req.body.Body; var twiml = new twilio.TwimlResponse(); twiml.message(botSays); res.writeHead(200, {'Content-Type': 'text/xml'}); res.end(twiml.toString()); }) The preceding code creates a web app that looks for incoming messages from users and responds to them. The response is currently to repeat what the user has said. Push it onto the cloud: git add . git commit -m webapp git push heroku master Now we have a web app on the cloud at https://ms-notification-bot.herokuapp.com/sms/ that can be called when an incoming SMS message arrives. This app will generate an appropriate chatbot response to the incoming message. Go to the Twilio Programmable SMS Dashboard page at https://www.twilio.com/ console/sms/dashboard. Select Messaging Services on the menu and click Create new Messaging Service: Give it a name and select Chat Bot/Interactive 2-Way as the use case: This will take you to the Configure page with a newly-assigned service ID: Under Inbound Settings, specify the URL of the web app we have created in the REQUEST URL field (that is, https://sms-notification-bot.herokuapp.com/sms/): Now all the inbound messages will be routed to this web app. Go back to the SMS console page at https://www.twilio com/console/sms/services. Here you will notice your new messaging service listed along with the inbound request URL: Click the service to attach a number to the service: You can either add a new number, in which case you need to buy one or choose the number you already have. We already have one sending notifications that can be reused. Click Add an Existing Number. Select the number by checking the box on the right and click Add Selected: Once added, it will be listed on the Numbers page as follows: In Advanced settings, we can add multiple numbers for serving different geographic regions and have them respond as if the chatbot is responding over a local number. The final step is to try sending an SMS message to the number and receive a response. Send a message using any SMS app on your phone and observe the response: Congratulations! You now have a two-way interactive chatbot. This tutorial is an excerpt from the book, Hands-On Chatbots and Conversational UI Development written by  Srini Janarthanam. If you found our post useful, do check out this book to get real-world examples of voice-enabled UIs for personal and home assistance. How to build a basic server side chatbot using Go Build a generative chatbot using recurrent neural networks (LSTM RNNs) Top 4 chatbot development frameworks for developers    
Read more
  • 0
  • 0
  • 5404
Banner background image

article-image-build-a-foodie-bot-with-javascript
Gebin George
03 May 2018
7 min read
Save for later

Build a foodie bot with JavaScript

Gebin George
03 May 2018
7 min read
Today, we are going to build a chatbot that can search for restaurants based on user goals and preferences. Let us begin by building Node.js modules to get data from Zomato based on user preferences. Create a file called zomato.js. Add a request module to the Node.js libraries using the following command in the console: This tutorial has been taken from Hands-On Chatbots and Conversational UI Development. > npm install request --save In zomato.js, add the following code to begin with: var request = require('request'); var baseURL = 'https://developers.zomato.com/api/v2.1/'; var apiKey = 'YOUR_API_KEY'; var catergories = null; var cuisines = null; getCategories(); getCuisines(76); Replace YOUR_API_KEY with your Zomato key. Let's build functions to get the list of categories and cuisines at startup. These queries need not be run when the user asks for a restaurant search because this information is pretty much static: function getCuisines(cityId){ var options = { uri: baseURL + 'cuisines', headers: { 'user-key': apiKey }, qs: {'city_id':cityId}, method: 'GET' } var callback = function(error, response, body) { if (error) { console.log('Error sending messages: ', error) } else if (response.body.error) { console.log('Error: ', response.body.error) } else { console.log(body); cuisines = JSON.parse(body).cuisines; } } request(options,callback); } The preceding code will fetch a list of cuisines available in a particular city (identified by a Zomato city ID). Let us add the code for identifying the list of categories: function getCategories(){ var options = { uri: baseURL + 'categories', headers: { 'user-key': apiKey }, qs: {}, method: 'GET' } var callback = function(error, response, body) { if (error) { console.log('Error sending messages: ', error) } else if (response.body.error) { console.log('Error: ', response.body.error) } else { categories = JSON.parse(body).categories; } } request(options,callback); } Now that we have the basic functions out of our way, let us code in the restaurant search code: function getRestaurant(cuisine, location, category){ var cuisineId = getCuisineId(cuisine); var categoryId = getCategoryId(category); var options = { uri: baseURL + 'locations', headers: { 'user-key': apiKey }, qs: {'query':location}, method: 'GET' } var callback = function(error, response, body) { if (error) { console.log('Error sending messages: ', error) } else if (response.body.error) { console.log('Error: ', response.body.error) } else { console.log(body); locationInfo = JSON.parse(body).location_suggestions; search(locationInfo[0], cuisineId, categoryId); } } request(options,callback); } function search(location, cuisineId, categoryId){ var options = { uri: baseURL + 'search', headers: { 'user-key': apiKey }, qs: {'entity_id': location.entity_id, 'entity_type': location.entity_type, 'cuisines': [cuisineId], 'categories': [categoryId]}, method: 'GET' } var callback = function(error, response, body) { if (error) { console.log('Error sending messages: ', error) } else if (response.body.error) { console.log('Error: ', response.body.error) } else { console.log('Found restaurants:') var results = JSON.parse(body).restaurants; console.log(results); } } request(options,callback); } The preceding code will look for restaurants in a given location, cuisine, and category. For instance, you can search for a list of Indian restaurants in Newington, Edinburgh that do delivery. We now need to integrate this with the chatbot code. Let us create a separate file called index.js. Let us begin with the basics: var restify = require('restify'); var builder = require('botbuilder'); var request = require('request'); var baseURL = 'https://developers.zomato.com/api/v2.1/'; var apiKey = 'YOUR_API_KEY'; var catergories = null; var cuisines = null; Chapter 6 [ 247 ] getCategories(); //setTimeout(function(){getCategoryId('Delivery')}, 10000); getCuisines(76); //setTimeout(function(){getCuisineId('European')}, 10000); // Setup Restify Server var server = restify.createServer(); server.listen(process.env.port || process.env.PORT || 3978, function () { console.log('%s listening to %s', server.name, server.url); }); // Create chat connector for communicating with // the Bot Framework Service var connector = new builder.ChatConnector({ appId: process.env.MICROSOFT_APP_ID, appPassword: process.env.MICROSOFT_APP_PASSWORD }); // Listen for messages from users server.post('/foodiebot', connector.listen()); Add the bot dialog code to carry out the restaurant search. Let us design the bot to ask for cuisine, category, and location before proceeding to the restaurant search: var bot = new builder.UniversalBot(connector, [ function (session) { session.send("Hi there! Hungry? Looking for a restaurant?"); session.send("Say 'search restaurant' to start searching."); session.endDialog(); } ]); // Search for a restaurant bot.dialog('searchRestaurant', [ function (session) { session.send('Ok. Searching for a restaurant!'); builder.Prompts.text(session, 'Where?'); }, function (session, results) { session.conversationData.searchLocation = results.response; builder.Prompts.text(session, 'Cuisine? Indian, Italian, or anything else?'); }, function (session, results) { session.conversationData.searchCuisine = results.response; builder.Prompts.text(session, 'Delivery or Dine-in?'); }, function (session, results) { session.conversationData.searchCategory = results.response; session.send('Ok. Looking for restaurants..'); getRestaurant(session.conversationData.searchCuisine, session.conversationData.searchLocation, session.conversationData.searchCategory, session); } ]) .triggerAction({ matches: /^search restaurant$/i, confirmPrompt: 'Your restaurant search task will be abandoned. Are you sure?' }); Notice that we are calling the getRestaurant() function with four parameters. Three of these are ones that we have already defined: cuisine, location, and category. To these, we have to add another: session. This passes the session pointer that can be used to send messages to the emulator when the data is ready. Notice how this changes the getRestaurant() and search() functions: function getRestaurant(cuisine, location, category, session){ var cuisineId = getCuisineId(cuisine); var categoryId = getCategoryId(category); var options = { uri: baseURL + 'locations', headers: { 'user-key': apiKey }, qs: {'query':location}, method: 'GET' } var callback = function(error, response, body) { if (error) { console.log('Error sending messages: ', error) } else if (response.body.error) { console.log('Error: ', response.body.error) } else { console.log(body); locationInfo = JSON.parse(body).location_suggestions; search(locationInfo[0], cuisineId, categoryId, session); } } request(options,callback); } function search(location, cuisineId, categoryId, session){ var options = { uri: baseURL + 'search', headers: { 'user-key': apiKey }, qs: {'entity_id': location.entity_id, 'entity_type': location.entity_type, 'cuisines': [cuisineId], 'category': categoryId}, method: 'GET' } var callback = function(error, response, body) { if (error) { console.log('Error sending messages: ', error) } else if (response.body.error) { console.log('Error: ', response.body.error) } else { console.log('Found restaurants:') console.log(body); //var results = JSON.parse(body).restaurants; //console.log(results); var resultsCount = JSON.parse(body).results_found; console.log('Found:' + resultsCount); session.send('I have found ' + resultsCount + ' restaurants for you!'); session.endDialog(); } } request(options,callback); } Once the results are obtained, the bot responds using session.send() and ends the dialog: Now that we have the results, let's present them in a more visually appealing way using cards. To do this, we need a function that can take the results of the search and turn them into an array of cards: function presentInCards(session, results){ var msg = new builder.Message(session); msg.attachmentLayout(builder.AttachmentLayout.carousel) var heroCardArray = []; var l = results.length; if (results.length > 10){ l = 10; } for (var i = 0; i < l; i++){ var r = results[i].restaurant; var herocard = new builder.HeroCard(session) .title(r.name) .subtitle(r.location.address) .text(r.user_rating.aggregate_rating) .images([builder.CardImage.create(session, r.thumb)]) .buttons([ builder.CardAction.imBack(session, "book_table:" + r.id, "Book a table") ]); heroCardArray.push(herocard); } msg.attachments(heroCardArray); return msg; } And we call this function from the search() function: function search(location, cuisineId, categoryId, session){ var options = { uri: baseURL + 'search', headers: { 'user-key': apiKey }, qs: {'entity_id': location.entity_id, 'entity_type': location.entity_type, 'cuisines': [cuisineId], 'category': categoryId}, method: 'GET' } var callback = function(error, response, body) { if (error) { console.log('Error sending messages: ', error) } else if (response.body.error) { console.log('Error: ', response.body.error) } else { console.log('Found restaurants:') console.log(body); var results = JSON.parse(body).restaurants; var msg = presentInCards(session, results); session.send(msg); session.endDialog(); } } request(options,callback); } Here is how it looks: We saw how to build a restaurant search bot, that gives you restaurant suggestions as per your preference. If you found our post useful check out Chatbots and Conversational UI Development. Top 4 chatbot development frameworks for developers How to create a conversational assistant using Python My friend, the robot: Artificial Intelligence needs Emotional Intelligence    
Read more
  • 0
  • 0
  • 7072

article-image-angular-pipes-angular-4
Packt Editorial Staff
30 Apr 2018
13 min read
Save for later

8 built-in Angular Pipes in Angular 4 that you should know

Packt Editorial Staff
30 Apr 2018
13 min read
Angular is a mature technology with introduction to new way to build applications. Think of Angular Pipes as modernized version of filters comprising functions or helps used to format the values within the template. Pipes in Angular are basically extension of what filters were in Angular v1. There are many useful built-in Pipes we can use easily in our templates. In today’s tutorial we will learn about Built-in Pipes as well as create our own custom user-defined pipe. Angular Pipes - overview Pipes allows us to format the values within the view of the templates before it's displayed. For example, in most modern applications, we want to display terms, such as today, tomorrow, and so on and not system date formats such as April 13 2017 08:00. Let's look  more real-world scenarios. You want the hint text in the application to always be lowercase? No problem; define and use lowercasePipe. In weather app, if you want to show month name as MAR or APR instead of full month name, use DatePipe. Cool, right? You get the point. Pipes helps you add your business rules, so you can transform the data before it's actually displayed in the templates. A good way to relate Angular Pipes is similar to Angular 1.x filters. Pipes do a lot more than just filtering. We have used Angular Router to define Route Path, so we have all the Pipes functionalities in one page. You can create in same or different apps. Feel free to use your creativity. In Angular 1.x, we had filters--Pipes are replacement of filters. Defining a Pipe The pipe operator is defined with a pipe symbol (|) followed by the name of the pipe: {{ appvalue | pipename }} The following is an example of a simple lowercase pipe: {{"Sridhar  Rao"  |  lowercase}} In the preceding code, we are transforming the text to lowercase using the lowercase pipe. Now, let's write an example component using the lowercase pipe example: @Component({ selector: 'demo-pipe', template: ` Author name is {{authorName | lowercase}} ` }) export class DemoPipeComponent { authorName = 'Sridhar Rao'; } Let's analyze the preceding code in detail: We are defining a DemoPipeComponent component class We are creating string variable authorName and assigning the value 'Sridhar Rao'. In the template view, we display authorName, but before we print it in the UI we transform it using the lowercase pipe Run the preceding code, and you should see the screenshot shown as follows as an output: Well done! In the preceding example, we have used a Built-in Pipe. In next sections, you will learn more about the Built-in Pipes and also create a few custom Pipes. Note that the pipe operator only works in your templates and not inside controllers. Built-in Pipes Angular Pipes are modernized version of Angular 1.x filters. Angular comes with a lot of predefined Built-in Pipes. We can use them directly in our views and transform the data on the fly. The following is the list of all the Pipes that Angular has built-in support for: DatePipe DecimalPipe CurrencyPipe LowercasePipe and UppercasePipe JSON Pipe SlicePipe async Pipe In the following sections, let's implement and learn more about the various pipes and see them in action. DatePipe DatePipe, as the name itself suggest, allows us to format or transform the values that are date related. DatePipe can also be used to transform values in different formats based on parameters passed at runtime. The general syntax is shown in the following code snippet: {{today | date}} // prints today's date and time {{ today | date:'MM-dd-yyyy' }} //prints only Month days and year {{ today | date:'medium' }} {{ today | date:'shortTime' }} // prints short format Let's analyze the preceding code snippets in detail: As explained in the preceding section, the general syntax is variable followed with a (|) pipe operator followed by name of the pipe operator We use the date pipe to transform the today variable Also, in the preceding example, you will note that we are passing few parameters to the pipe operator. We will cover passing parameters to the pipe in the following section Now, let's create a complete example of the date pipe component. The following is the code snippet for implementing the DatePipe component: import { Component } from '@angular/core'; @Component({ template: ` <h5>Built-In DatePipe</h5> <ol> <li> <strong>DatePipe example expression</strong> <p>Today is {{today | date}} <p>{{ today | date:'MM-dd-yyyy' }} <p>{{ today | date:'medium' }} <p>{{ today | date:'shortTime' }} </li> </ol> `, })   Let's analyze the preceding code snippet in detail: We are creating a PipeComponent component class. We define a today variable. In the view, we are transforming the value of variable into various expressions based on different parameters. Run the application, and we should see the output as shown in the following screenshot: We learned the date pipe in this section. In the following sections, we will continue to learn and implement other Built-in Pipes and also create some custom user-defined pipes. DecimalPipe In this section, you will learn about yet another Built-in Pipe--DecimalPipe. DecimalPipe allows us to format a number according to locale rules. DecimalPipe can also be used to transform a number in different formats. The general syntax is shown as follows: appExpression  |  number  [:digitInfo] In the preceding code snippet, we use the number pipe, and optionally, we can pass the parameters. Let's look at how to create a DatePipe implementing decimal points. The following is an example code of the same: import { Component } from '@angular/core'; @Component({ template: ` state_tax (.5-5): {{state_tax | number:'.5-5'}} state_tax (2.10-10): {{state_tax | number:'2.3-3'}} `, }) export class PipeComponent { state_tax: number = 5.1445; } Let's analyze the preceding code snippet in detail: We defie a component class--PipeComponent. We define a variable--state_tax. We then transform state_tax in the view. The first pipe operator tells the expression to print the decimals up to five decimal places. The second pipe operator tells the expression to print the value to three decimal places. The output of the preceding pipe component example is given as follows: Undoubtedly, number pipe is one of the most useful and used pipe across various applications. We can transform the number values specially dealing with decimals and floating points. CurrencyPipe Applications that intent to cater to multi-national geographies, we need to show country- specific codes and their respective currency values. That's where CurrencyPipe comes to our rescue. The CurrencyPipe operator is used to append the country codes or currency symbol in front of the number values. Take a look the code snippet implementing the CurrencyPipe operator: {{  value  |  currency:'USD'  }} Expenses  in  INR: {{  expenses  |  currency:'INR'  }} Let's analyze the preceding code snippet in detail: The first line of code shows the general syntax of writing a currency pipe. The second line shows the currency syntax, and we use it to transform the expenses value and append the Indian currency symbol to it. So now that we know how to use a currency pipe operator, let's put together an example to display multiple currency and country formats. The following is the complete component class, which implements a currency pipe operator: import { Component } from '@angular/core'; @Component({ selector: 'currency-pipe', template: ` <h5>Built-In CurrencyPipe</h5> <ol> <li> <p>Salary in USD: {{ salary | currency:'USD':true }}</p> <p>Expenses in INR: {{ expenses | currency:'INR':false }}</p> </li> </ol> ` }) export class CurrencyPipeComponent { salary: number = 2500; expenses: number = 1500; } Let's analyze the the preceding code in detail: We created a component class, CurrencyPipeComponent, and declared few variables, namely salary and expenses. In the component template, we transformed the display of the variables by adding the country and currency details. In the first pipe operator, we used 'currency :  USD', which will append the ($) dollar symbol before the variable. In the second pipe operator, we used 'currency :  'INR':false', which will add the currency code, and false will tell not to print the symbol. Launch the app, and we should see the output as shown in the following screenshot: In this section, we learned about and implemented CurrencyPipe. In the following sections, we will keep exploring and learning about other Built-in Pipes and much more. import { Component } from '@angular/core'; @Component({ selector: 'currency-pipe', template: ` <h5>Built-In CurrencyPipe</h5> <ol> <li> <p>Salary in USD: {{ salary | currency:'USD':true }}</p> <p>Expenses in INR: {{ expenses | currency:'INR':false }}</p> </li> </ol> ` }) export class CurrencyPipeComponent { salary: number = 2500; expenses: number = 1500; } The LowercasePipe and UppercasePipe, as the name suggests, help in transforming the text into lowercase and uppercase, respectively. Take a look at the following code snippet: Author  is  Lowercase {{authorName  |  lowercase  }} Author  in  Uppercase  is {{authorName  |  uppercase  }} Let's analyze the preceding code in detail: The first line of code transforms the value of authorName into a lowercase using the lowercase pipe The second line of code transforms the value of authorName into an uppercase using the uppercase pipe. Now that we saw how to define lowercase and uppercase pipes, it's time we create a complete component example, which implements the Pipes to show author name in both lowercase and uppercase. Take a look at the following code snippet: import { Component } from '@angular/core'; @Component({ selector: 'textcase-pipe', template: ` <h5>Built-In LowercasPipe and UppercasePipe</h5> <ol> <li> <strong>LowercasePipe example</strong> <p>Author in lowercase is {{authorName | lowercase}} </li> <li> <strong>UpperCasePipe example</strong> <p>Author in uppercase is {{authorName | uppercase}} </li> </ol> ` }) export class TextCasePipeComponent { authorName = "Sridhar Rao"; } Let's analyze the preceding code in detail: We create a component class, TextCasePipeComponent, and define a variable authorName. In the component view, we use the lowercase and uppercase pipes. The first pipe will transform the value of the variable to the lowercase text. The second pipe will transform the value of the variable to uppercase text. Run the application, and we should see the output as shown in the following screenshot: In this section, you learned how to use lowercase and uppercase pipes to transform the values. JSON Pipe Similar to JSON filter in Angular 1.x, we have JSON Pipe, which helps us transform the string into a JSON format string. In lowercase or uppercase pipe, we were transforming the strings; using JSON Pipe, we can transform and display the string into a JSON format string. The general syntax is shown in the following code snippet: <pre>{{  myObj  |  json  }}</pre> Now, let's use the preceding syntax and create a complete component example, which uses the JSON Pipe: import { Component } from '@angular/core'; @Component({ template: ` <h5>Author Page</h5> <pre>{{ authorObj | json }}</pre> ` }) export class JSONPipeComponent { authorObj: any; constructor() { this.authorObj = { name: 'Sridhar Rao', website: 'http://packtpub.com', Books: 'Mastering Angular2' }; } } Let's analyze the preceding code in detail: We created a component class JSONPipeComponent and authorObj and assigned the JSON string to the variable. In the component template view, we transformed and displayed the JSON string. Run the app, and we should see the output as shown in the following screenshot: JSON is soon becoming defacto standard of web applications to integrate between services and client technologies. Hence, JSON Pipe comes in handy every time we need to transform our values to JSON structure in the view. Slice pipe Slice Pipe is very similar to array slice JavaScript function. It gets a sub string from a strong certain start and end positions. The general syntax to define a slice pipe is given as follows: {{email_id  |  slice:0:4  }} In the preceding code snippet, we are slicing the e-mail address to show only the first four characters of the variable value email_id. Now that we know how to use a slice pipe, let's put it together in a component. The following is the complete complete code snippet implementing the slice pipe: import { Component } from '@angular/core'; @Component({ selector: 'slice-pipe', template: ` <h5>Built-In Slice Pipe</h5> <ol> <li> <strong>LowercasePipe example</strong> <p> Email Id is {{ emailAddress }} </li> <li> <strong>LowercasePipe example</strong> <p>Sliced Email Id is {{emailAddress | slice : 0: 4}} </li> </ol> ` }) export class SlicePipeComponent { emailAddress = "test@packtpub.com"; } Let's analyze the preceding code snippet in detail: We are creating a class SlicePipeComponent. We defined a string variable emailAddress and assign it a value, test@packtpub.com. Then, we applied the slice pipe to the {{emailAddress |  slice  :  0:  4}} variable. We get the sub string starting 0 position and get four characters from the variable value of emailAddress. Run the app, and we should the output as shown in the following screenshot: SlicePipe is certainly a very helpful Built-in Pipe specially dealing with strings or substrings. async Pipe async Pipe allows us to directly map a promises or observables into our template view. To understand async Pipe better, let me throw some light on an Observable first. Observables are Angular-injectable services, which can be used to stream data to multiple sections in the application. In the following code snippet, we are using async Pipe as a promise to resolve the list of authors being returned: <ul id="author-list"> <li *ngFor="let author of authors | async"> <!-- loop the object here --> </li> </ul> The async pipe now subscribes to the observable (authors) and retrieve the last value. Let's look at examples of how we can use the async pipe as both promise and an observable. Add the following lines of code in our app.component.ts file: getAuthorDetails(): Observable<Author[]> { return this.http.get(this.url).map((res: Response) => res.json()); } getAuthorList(): Promise<Author[]> { return this.http.get(this.url).toPromise().then((res: Response) => res.json()); } Let's analyze the preceding code snippet in detail: We created a method called getAuthorDetails and attached an observable with the same. The method will return the response from the URL--which is a JSON output. In the getAuthorList method, we are binding a promise, which needs to be resolved or rejected in the output returned by the url called through a http request. In this section, we have seen how the async pipe works. You will find it very similar to dealing with services. We can either map a promise or an observable and map the result to the template. To summarize, we demonstrated Angular Pipes by explaining in detail about various built-in Pipes such as DatePipe, DecimalPipe, CurrencyPipe, LowercasePipe and UppercasePipe, JSON Pipe, SlicePipe, and async Pipe. [box type="note" align="" class="" width=""]The above article is an excerpt from the book Expert Angular, written by Sridhar Rao, Rajesh Gunasundaram, and Mathieu Nayrolles. This book will help you learn everything you need to build highly scalable and robust web applications using Angular 4. What are you waiting for, check out the book now to become an expert Angular developer![/box] Get Familiar with Angular Interview - Why switch to Angular for web development Building Components Using Angular    
Read more
  • 0
  • 0
  • 17693

article-image-how-to-deploy-nodejs-application-to-the-web-using-heroku
Sunith Shetty
26 Apr 2018
19 min read
Save for later

How to deploy a Node.js application to the web using Heroku

Sunith Shetty
26 Apr 2018
19 min read
Heroku is a tool that helps you manage cloud hosted web applications. It's a really great service. It makes creating, deploying, and updating apps really easy. Now Heroku, like GitHub, does not require a credit card to sign up and there is a free tier, which we'll use. They have paid plans for just about everything, but we can get away with the free tier for everything we'll do in this section. In this tutorial, you'll learn to deploy your live Node.js app to the Web using Heroku. By the end of this tutorial, you'll have the URL that you can share with anybody to view the application from their browser. Installing Heroku command-line tools To kick things off, we'll open up the browser and go to Heroku's website here. Here we can go ahead and sign up for a new account. Take a quick moment to either log in to your existing one or sign up for a new one. Once logged in, it'll show you the dashboard. Now your dashboard will look something like this: Although there might be a greeting telling you to create a new application, which you can ignore. I have a bunch of apps. You might not have these. That is perfectly fine. The next thing we'll do is install the Heroku command-line tools. This will let us create apps, deploy apps, open apps, and do all sorts of really cool stuff from the Terminal, without having to come into the web app. That will save us time and make development a lot easier. We can grab the download by going to toolbelt.heroku.com. Here we're able to grab the installer for whatever operating system, you happen to be running on. So, let's start the download. It's a really small download so it should happen pretty quickly. Once it's done, we can go ahead and run through the process: This is a simple installer where you just click on Install. There is no need to customize anything. You don't have to enter any specific information about your Heroku account. Let's go ahead and complete the installer. This will give us a new command from the Terminal that we can execute. Before we can do that, we do have to log in locally in the Terminal and that's exactly what we'll do next. Log in to Heroku account locally Now we will start off the Terminal. If you already have it running, you might need to restart it in order for your operating system to recognize the new command. You can test that it got installed properly by running the following command: heroku --help When you run this command, you'll see that it's installing the CLI for the first time and then we'll get all the help information. This will tell us what commands we have access to and exactly how they work: Now we will need to log in to the Heroku account locally. This process is pretty simple. In the preceding code output, we have all of the commands available and one of them happens to be login. We can run heroku login just like this to start the process: heroku login I'll run the login command and now we just use the email and password that we had set up before: I'll type in my email and password. Typing for Password is hidden because it's secure. And when I do that you see Logged in as garyngreig@gmail.com shows up and this is fantastic: Now we're logged in and we're able to successfully communicate between our machine's command line and the Heroku servers. This means we can get started creating and deploying applications. Getting SSH key to Heroku Now before going ahead, we'll use the clear command to clear the Terminal output and get our SSH key on Heroku, kind of like what we did with GitHub, only this time we can do it via the command line. So it's going to be a lot easier. In order to add our local keys to Heroku, we'll run the heroku keys:add command. This will scan our SSH directory and add the key up: heroku keys:add Here you can see it found a key the id_rsa.pub file: Would you like to upload it to Heroku? Type Yes and hit enter: Now we have our key uploaded. That is all it took. Much easier than it was to configure with GitHub. From here, we can use the heroku keys command to print all the keys currently on our account: heroku keys We could always remove them using heroku keys:remove command followed by the email related to that key. In this case, we'll keep the Heroku key that we have. Next up, we can test our connection using SSH with the v flag and git@heroku.com: ssh -v git@heroku.com This will communicate with the Heroku servers: As shown, we can see it's asking that same question: The authenticity of the host 'heroku.com' can't be established, Are you sure you want to continue connecting? Type Yes. You will see the following output: Now when you run that command, you'll get a lot of cryptic output. What you're looking for is authentication succeeded and then public key in parentheses. If things did not go well, you'll see the permission denied message with public key in parentheses. In this case, the authentication was successful, which means we are good to go. I'll run clear again, clearing the Terminal output. Setting up in the application code for Heroku Now we can turn our attention towards the application code because before we can deploy to Heroku, we will need to make two changes to the code. These are things that Heroku expects your app to have in place in order to run properly because Heroku does a lot of things automatically, which means you have to have some basic stuff set up for Heroku to work. It's not too complex—some really simple changes, a couple one-liners. Changes in the server.js file First up in the server.js file down at the very bottom of the file, we have the port and our app.listen statically coded inside server.js: app.listen(3000, () => { console.log('Server is up on port 3000'); }); We need to make this port dynamic, which means we want to use a variable. We'll be using an environment variable that Heroku is going to set. Heroku will tell your app which port to use because that port will change as you deploy your app, which means that we'll be using that environment variable so we don't have to swap out our code every time we want to deploy. With environment variables, Heroku can set a variable on the operating system. Your Node app can read that variable and it can use it as the port. Now all machines have environment variables. You can actually view the ones on your machine by running the env command on Linux or macOS or the set command on Windows. What you'll get when you do that is a really long list of key-value pairs, and this is all environment variables are: Here, we have a LOGNAME environment variable set to Andrew. I have a HOME environment variable set to my home directory, all sorts of environment variables throughout my operating system. One of these that Heroku is going to set is called PORT, which means we need to go ahead and grab that port variable and use it in server.js instead of 3000. Up at the very top of the server.js file, we'd to make a constant called port, and this will store the port that we'll use for the app: const express = require('express');. const hbs = require('hbs'); const fs = require('fs'); const port Now the first thing we'll do is grab a port from process.env. The process.env is an object that stores all our environment variables as key-value pairs. We're looking for one that Heroku is going to set called PORT: const port = process.env.PORT; This is going to work great for Heroku, but when we run the app locally, the PORT environment variable is not going to exist, so we'll set a default using the OR (||) operator in this statement. If process.env.port does not exist, we'll set port equal to 3000 instead: const port = process.env.PORT || 3000; Now we have an app that's configured to work with Heroku and to still run locally, just like it did before. All we have to do is take the PORT variable and use that in app.listen instead of 3000. As shown, I'm going to reference port and inside our message, I'll swap it out for template strings and now I can replace 3000 with the injected port variable, which will change over time: app.listen(port, () => { console.log(`Server is up on port ${port}`); }); With this in place, we have now fixed the first problem with our app. I'll now run node server.js from the Terminal. node server.js We still get the exact same message: Server is up on port 3000, so your app will still works locally as expected: Changes in the package.json file Next up, we have to specify a script in package.json. Inside package.json, you might have noticed we have a scripts object, and in there we have a test script. This gets set by default for npm: We can create all sorts of scripts inside the scripts object that do whatever we like. A script is nothing more than a command that we run from the Terminal, so we could take this command, node server.js, and turn it into a script instead, and that's exactly what we're going to do. Inside the scripts object, we'll add a new script. The script needs to be called start: This is a very specific, built-in script and we'll set it equal to the command that starts our app. In this case, it will be node server.js: "start": "node server.js" This is necessary because when Heroku tries to start our app, it will not run Node with your file name because it doesn't know what your file name is called. Instead, it will run the start script and the start script will be responsible for doing the proper thing; in this case, booting up that server file. Now we can run our app using that start script from the Terminal by using the following command: npm start When I do that, we get a little output related to npm and then we get Server is up on port 3000. The big difference is that we are now ready for Heroku. We could also run the test script using from the Terminal npm test: npm test Now, we have no tests specified and that is expected: Making a commit in Heroku The next step in the process will be to make the commit and then we can finally start getting it up on the Web. First up, git status. When we run git status, we have something a little new: Instead of new files, we have modified files here as shown in the code output here. We have a modified package.json file and we have a modified server.js file. These are not going to be committed if we were to run a git commit just yet; we still have to use git add. What we'll do is run git add with the dot as the next argument. Dot is going to add every single thing showing up and get status to the next commit. Now I only recommend using the syntax of everything you have listed in the Changes not staged for commit header. These are the things you actually want to commit, and in our case, that is indeed what we want. If I run git add and then a rerun git status, we can now see what is going to be committed next, under the Changes to be committed header: Here we have our package.json file and the server.js file. Now we can go ahead and make that commit. I'll run a git commit command with the m flag so we can specify our message, and a good message for this commit would be something like Setup start script and heroku Port: git commit -m 'Setup start script and heroku port' Now we can go ahead and run that command, which will make the commit. Now we can go ahead and push that up to GitHub using the git push command, and we can leave off the origin remote because the origin is the default remote. I'll go ahead and run the following command: git push This will push it up to GitHub, and now we are ready to actually create the app, push our code up, and view it over in the browser: Running the Heroku create command The next step in the process will be to run a command called heroku create from the Terminal. heroku create needs to get executed from inside your application: heroku create Just like we run our Git commands, when I run heroku create, a couple things are going to happen: First up, it's going to make a real new application over in the Heroku web app It's also going to add a new remote to your Git repository Now remember we have an origin remote, which points to our GitHub repository. We'll have a Heroku remote, which points to our Heroku Git repository. When we deploy to the Heroku Git repository, Heroku is going to see that. It will take the changes and it will deploy them to the Web. When we run Heroku create, all of that happens: Now we do still have to push up to this URL in order to actually do the deploying process, and we can do that using git push followed by heroku: git push heroku The brand new remote was just added because we ran heroku create. Now pushing it this time around will go through the normal process. You'll then start seeing some logs. These are logs coming back from Heroku letting you know how your app is deploying. It's going through the entire process, showing you what happens along the way. This will take about 10 seconds and at the very end we have a success message—Verifying deploy... done: It also verified that the app was deployed successfully and that did indeed pass. From here we actually have a URL we can visit (https://sleepy-retreat-32096.herokuapp.com/). We can take it, copy it, and paste it in the browser. What I'll do instead is use the following command: heroku open The heroku open will open up the Heroku app in the default browser. When I run this, it will switch over to Chrome and we get our application showing up just as expected: We can switch between pages and everything works just like it did locally. Now we have a URL and this URL was given to us by Heroku. This is the default way Heroku generates app URLs. If you have your own domain registration company, you can go ahead and configure its DNS to point to this application. This will let you use a custom URL for your Heroku app. You'll have to refer to the specific instructions for your domain registrar in order to do that, but it can indeed be done. Now that we have this in place, we have successfully deployed our Node applications live to Heroku, and this is just fantastic. In order to do this, all we had to do is make a commit to change our code and push it up to a new Git remote. It could not be easier to deploy our code. You can also manage your application by going back over to the Heroku dashboard. If you give it a refresh, you should see that brand new URL somewhere on the dashboard. Remember mine was sleepy retreat. Yours is going to be something else. If I click on the sleepy retreat, I can view the app page: Here we can do a lot of configuration. We can manage Activity and Access so we can collaborate with others. We have metrics, we have Resources, all sorts of really cool stuff. With this in place, we are now done with our basic deploying section. In the next section, your challenge will be to go through that process again. You'll add some changes to the Node app. You'll commit them, deploy them, and view them live in the Web. We'll get started by creating the local changes. That means I'll register a new URL right here using app.get. We'll create a new page/projects, which is why I have that as the route for my HTTP get handler. Inside the second argument, we can specify our callback function, which will get called with request and response, and like we do for the other routes above, the root route and our about route, we'll be calling response.render to render our template. Inside the render arguments list, we'll provide two. The first one will be the file name. The file doesn't exist, but we can still go ahead and call render. I'll call it projects.hbs, then we can specify the options we want to pass to the template. In this case, we'll set page title, setting it equal to Projects with a capital P. Excellent! Now with this in place, the server file is all done. There are no more changes there. What I'll do is go ahead and go to the views directory, creating a new file called projects.hbs. In here, we'll be able to configure our template. To kick things off, I'm going to copy the template from the about page. Since it's really similar, I'll copy it. Close about, paste it into projects, and I'm just going to change this text to project page text would go here. Then we can save the file and make our last change. The last thing we want to do is update the header. We now have a brand new projects page that lives at /projects. So we'll want to go ahead and add that to the header links list. Right here, I'll create a new paragraph tag and then I'll make an anchor tag. The text for the link will be Projects with a capital P and the href, which is the URL to visit when that link is clicked. We'll set that equal to /projects, just like we did for about, where we set it equal to /about. Now that we have this in place, all our changes are done and we are ready to test things out locally. I'll fire up the app locally using Node with server.js as the file. To start, we're up on localhost 3000. So over in the browser, I can move to the localhost tab, as opposed to the Heroku app tab, and click on Refresh. Right here we have Home, which goes to home, we have About which goes to about, and we have Projects which does indeed go to /projects, rendering the projects page. Project page text would go here. With this in place we're now done locally. We have the changes, we've tested them, now it's time to go ahead and make that commit. That will happen over inside the Terminal. I'll shut down the server and run Git status. This will show me all the changes to my repository as of the last commit. I have two modified files: the server file and the header file, and I have my brand new projects file. All of this looks great. I want to add all of this to the next commit, so I can use a Git add with the . to do just that. Now before I actually make the commit, I do like to test that the proper things got added by running Git status. Right here I can see my changes to be committed are showing up in green. Everything looks great. Next up, we'll run a Git commit to actually make the commit. This is going to save all of the changes into the Git repository. A message for this one would be something like adding a project page. With a commit made, the next thing you needed to do was push it up to GitHub. This will back our code up and let others collaborate on it. I'll use Git push to do just that. Remember we can leave off the origin remote as origin is the default remote, so if you leave off a remote it'll just use that anyway. With our GitHub repository updated, the last thing to do is deploy to Heroku and we do that by pushing up the Git repository, using Git push, to the Heroku remote. When we do this, we get our long list of logs as the Heroku server goes through the process of installing our npm modules, building the app, and actually deploying it. Once it's done, we'll get brought back to the Terminal like we are here, and then we can open up the URL in the\ browser. Now I can copy it from here or run Heroku open. Since I already have a tab open with the URL in place, I'll simply give it a refresh. Now you might have a little delay as you refresh your app. Sometimes starting up the app right after a new app was deployed can take about 10 to 15 seconds. That will only happen as you first visit it. Other times where you click on the Refresh button, it should reload instantly. Now we have the projects page and if I visit it, everything looks awesome. The navbar is working great and the projects page is indeed rendering at /projects. With this in place, we are now done. We've gone through the process of adding a new feature, testing it locally, making a Git commit, pushing it up to GitHub, and deploying it to Heroku. We now have a workflow for building real-world web applications using Node.js. This tutorial has been taken from Learning Node.js Development. More Heroku tutorials Deploy a Game to Heroku Managing Heroku from the command line
Read more
  • 0
  • 0
  • 4245
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at $19.99/month. Cancel anytime
article-image-building-a-real-time-dashboard-with-meteor-and-vue-js
Kunal Chaudhari
25 Apr 2018
14 min read
Save for later

Building a real-time dashboard with Meteor and Vue.js

Kunal Chaudhari
25 Apr 2018
14 min read
In this article, we will use Vue.js with an entirely different stack--Meteor! We will discover this full-stack JavaScript framework and build a real-time dashboard with Meteor to monitor the production of some products. We will cover the following topics: Installing Meteor and setting up a project Storing data into a Meteor collection with a Meteor method Subscribing to the collection and using the data in our Vue components The app will have a main page with some indicators, such as: It will also have another page with buttons to generate fake measures since we won't have real sensors available. Setting up the project In this first part, we will cover Meteor and get a simple app up and running on this platform. What is Meteor? Meteor is a full-stack JavaScript framework for building web applications. The mains elements of the Meteor stack are as follows: Web client (can use any frontend library, such as React or Vue); it has a client-side database called Minimongo Server based on nodejs; it supports the modern ES2015+ features, including the import/export syntax Real-time database on the server using MongoDB Communication between clients and the server is abstracted; the client-side and server-side databases can be easily synchronized in real-time Optional hybrid mobile app (Android and iOS), built in one command Integrated developer tools, such as a powerful command-line utility and an easy- to-use build tool Meteor-specific packages (but you can also use npm packages) As you can see, JavaScript is used everywhere. Meteor also encourages you to share code between the client and the server. Since Meteor manages the entire stack, it offers very powerful systems that are easy to use. For example, the entire stack is fully reactive and real-time--if a client sends an update to the server, all the other clients will receive the new data and their UI will automatically be up to date. Meteor has its own build system called "IsoBuild" and doesn't use Webpack. It focuses on ease of use (no configuration), but is, as a result, also less flexible. Installing Meteor If you don't have Meteor on your system, you need to open the Installation Guide on the official Meteor website. Follow the instructions there for your OS to install Meteor. When you are done, you can check whether Meteor was correctly installed with the following command: meteor --version The current version of Meteor should be displayed. Creating the project Now that Meteor is installed, let's set up a new project: Let's create our first Meteor project with the meteor create command: meteor create --bare <folder> cd <folder> The --bare argument tells Meteor we want an empty project. By default, Meteor will generate some boilerplate files we don't need, so this keeps us from having to delete them. Then, we need two Meteor-specific packages--one for compiling the Vue components, and one for compiling Stylus inside those components. Install them with the meteor add command: meteor add akryum:vue-component akryum:vue-stylus We will also install the vue and vue-router package from npm: meteor npm i -S vue vue-router Note that we use the meteor npm command instead of just npm. This is to have the same environment as Meteor (nodejs and npm versions). To start our Meteor app in development mode, just run the meteor command: Meteor Meteor should start an HTTP proxy, a MongoDB, and the nodejs server: It also shows the URL where the app is available; however, if you open it right now, it will be blank. Our first Vue Meteor app In this section, we will display a simple Vue component in our app: Create a new index.html file inside the project directory and tell Meteor we want div in the page body with the app id: <head> <title>Production Dashboard</title> </head> <body> <div id="app"></div>      </body> This is not a real HTML file. It is a special format where we can inject additional elements to the head or body section of the final HTML page. Here, Meteor will add a title into the head section and the <div> into the body section. Create a new client folder, new components subfolder, and a new App.vue component with a simple template: <!-- client/components/App.vue --> <template> <div id="#app"> <h1>Meteor</h1> </div>   </template> Download (https://github.com/Akryum/packt-vue-project-guide/tree/ master/chapter8-full/client) this stylus file in the client folder and add it to the main App.vue component: <style lang="stylus" src="../style.styl" /> Create a main.js file in the client folder that starts the Vue application inside the Meteor.startup hook: import { Meteor } from 'meteor/meteor' import Vue from 'vue' import App from './components/App.vue' Meteor.startup(() => { new Vue({ el: '#app', ...App, }) }) In a Meteor app, it is recommended that you create the Vue app inside the Meteor.startup hook to ensure that all the Meteor systems are ready before starting the frontend. This code will only be run on the client because it is located in a client folder. You should now have a simple app displayed in your browser. You can also open the Vue devtools and check whether you have the App component present on the page. Routing Let's add some routing to the app; we will have two pages--the dashboard with indicators and a page with buttons to generate fake data: In the client/components folder, create two new components--ProductionGenerator.vue and ProductionDashboard.vue. Next to the main.js file, create the router in a router.js file: import Vue from 'vue' import VueRouter from 'vue-router' import ProductionDashboard from './components/ProductionDashboard.vue' import ProductionGenerator from './components/ProductionGenerator.vue' Vue.use(VueRouter) const routes = [ { path: '/', name: 'dashboard', component: ProductionDashboard }, { path: '/generate', name: 'generate', component: ProductionGenerator }, ] const router = new VueRouter({ mode: 'history', routes, }) export default router    Then, import the router in the main.js file and inject it into the app.    In the App.vue main component, add the navigation menu and the router view: <nav> <router-link :to="{ name: 'dashboard' }" exact>Dashboard </router-link> <router-link :to="{ name: 'generate' }">Measure</router-link> </nav> <router-view /> The basic structure of our app is now done: Production measures The first page we will make is the Measures page, where we will have two buttons: The first one will generate a fake production measure with current date and random value The second one will also generate a measure, but with the error property set to true All these measures will be stored in a collection called "Measures". Meteor collections integration A Meteor collection is a reactive list of objects, similar to a MongoDB collection (in fact, it uses MongoDB under the hood). We need to use a Vue plugin to integrate the Meteor collections into our Vue app in order to update it automatically: Add the vue-meteor-tracker npm package: meteor npm i -S vue-meteor-tracker    Then, install the library into Vue: import VueMeteorTracker from 'vue-meteor-tracker' Vue.use(VueMeteorTracker)    Restart Meteor with the meteor command. The app is now aware of the Meteor collection and we can use them in our components, as we will do in a moment. Setting up data The next step is setting up the Meteor collection where we will store our measures data Adding a collection We will store our measures into a Measures Meteor collection. Create a new lib folder in the project directory. All the code in this folder will be executed first, both on the client and the server. Create a collections.js file, where we will declare our Measures collection: import { Mongo } from 'meteor/mongo' export const Measures = new Mongo.Collection('measures') Adding a Meteor method A Meteor method is a special function that will be called both on the client and the server. This is very useful for updating collection data and will improve the perceived speed of the app--the client will execute on minimongo without waiting for the server to receive and process it. This technique is called "Optimistic Update" and is very effective when the network quality is poor.  Next to the collections.js file in the lib folder, create a new methods.js file. Then, add a measure.add method that inserts a new measure into the Measures collection: import { Meteor } from 'meteor/meteor' import { Measures } from './collections' Meteor.methods({ 'measure.add' (measure) { Measures.insert({ ...measure, date: new Date(), }) }, }) We can now call this method with the Meteor.call function: Meteor.call('measure.add', someMeasure) The method will be run on both the client (using the client-side database called minimongo) and on the server. That way, the update will be instant for the client. Simulating measures Without further delay, let's build the simple component that will call this measure.add Meteor method: Add two buttons in the template of ProductionGenerator.vue: <template> <div class="production-generator"> <h1>Measure production</h1> <section class="actions"> <button @click="generateMeasure(false)">Generate Measure</button> <button @click="generateMeasure(true)">Generate Error</button> </section> </div> </template> Then, in the component script, create the generateMeasure method that generates some dummy data and then call the measure.add Meteor method: <script> import { Meteor } from 'meteor/meteor' export default { methods: { generateMeasure (error) { const value = Math.round(Math.random() * 100) const measure = { value, error, } Meteor.call('measure.add', measure) }, }, } </script> The component should look like this: If you click on the buttons, nothing visible should happen. Inspecting the data There is an easy way to check whether our code works and to verify that you can add items in the Measures collection. We can connect to the MongoDB database in a single command. In another terminal, run the following command to connect to the app's database: meteor mongo Then, enter this MongoDB query to fetch the documents of the measures collection (the argument used when creating the Measures Meteor collection): db.measures.find({}) If you clicked on the buttons, a list of measure documents should be displayed This means that our Meteor method worked and objects were inserted in our MongoDB database. Dashboard and reporting Now that our first page is done, we can continue with the real-time dashboard. Progress bars library To display some pretty indicators, let's install another Vue library that allows drawing progress bars along SVG paths; that way, we can have semi-circular bars: Add the vue-progress-path npm package to the project: meteor npm i -S vue-progress-path We need to tell the Vue compiler for Meteor not to process the files in node_modules where the package is installed. Create a new .vueignore file in the project root directory. This file works like a .gitignore: each line is a rule to ignore some paths. If it ends with a slash /, it will ignore only corresponding folders. So, the content of .vueignore should be as follows: node_modules/ Finally, install the vue-progress-path plugin in the client/main.js file: import 'vue-progress-path/dist/vue-progress-path.css' import VueProgress from 'vue-progress-path' Vue.use(VueProgress, { defaultShape: 'semicircle', }) Meteor publication To synchronize data, the client must subscribe to a publication declared on the server. A Meteor publication is a function that returns a Meteor collection query. It can take arguments to filter the data that will be synchronized. For our app, we will only need a simple measures publication that sends all the documents of the Measures collection: This code should only be run on the server. So, create a new server in the project folder and a new publications.js file inside that folder: import { Meteor } from 'meteor/meteor' import { Measures } from '../lib/collections' Meteor.publish('measures', function () { return Measures.find({}) }) This code will only run on the server because it is located in a folder called server. Creating the Dashboard component We are ready to build our ProductionDashboard component. Thanks to the vue- meteor-tracker we installed earlier, we have a new component definition option-- meteor. This is an object that describes the publications that need to be subscribed to and the collection data that needs to be retrieved for that component.    Add the following script section with the meteor definition option: <script> export default { meteor: { // Subscriptions and Collections queries here }, } </script> Inside the meteor option, subscribe to the measures publication with the $subscribe object: meteor: { $subscribe: { 'measures': [], }, }, Retrieve the measures with a query on the Measures Meteor collection inside the meteor option: meteor: { // ... measures () { return Measures.find({}, { sort: { date: -1 }, }) }, }, The second parameter of the find method is an options object very similar to the MongoDB JavaScript API. Here, we are sorting the documents by their date in descending order, thanks to the sort property of the options object. Finally, create the measures data property and initialize it to an empty array. The script of the component should now look like this: <script> import { Measures } from '../../lib/collections' export default { data () { return { measures: [], } }, meteor: { $subscribe: { 'measures': [], }, measures () { return Measures.find({}, { sort: { date: -1 }, }) }, }, } </script> In the browser devtools, you can now check whether the component has retrieved the items from the collection. Indicators We will create a separate component for the dashboard indicators, as follows: In the components folder, create a new ProductionIndicator.vue component. Declare a template that displays a progress bar, a title, and additional info text: <template> <div class="production-indicator"> <loading-progress :progress="value" /> <div class="title">{{ title }}</div> <div class="info">{{ info }}</div> </div> </template> Add the value, title, and info props: <script> export default { props: { value: { type: Number, required: true, }, title: String, info: [String, Number], }, } </script> Back in our ProductionDashboard component, let's compute the average of the values and the rate of errors: computed: { length () { return this.measures.length }, average () { if (!this.length) return 0 let total = this.measures.reduce( (total, measure) => total += measure.value, 0 ) return total / this.length }, errorRate () { if (!this.length) return 0 let total = this.measures.reduce( (total, measure) => total += measure.error ? 1 : 0, 0 ) return total / this.length }, }, 5. Add two indicators in the templates - one for the average value and one for the error rate: <template> <div class="production-dashboard"> <h1>Production Dashboard</h1> <section class="indicators"> <ProductionIndicator :value="average / 100" title="Average" :info="Math.round(average)" /> <ProductionIndicator class="danger" :value="errorRate" title="Errors" :info="`${Math.round(errorRate * 100)}%`" /> </section> </div> </template> The indicators should look like this: Listing the measures Finally, we will display a list of the measures below the indicators:  Add a simple list of <div> elements for each measure, displaying the date if it has an error and the value: <section class="list"> <div v-for="item of measures" :key="item._id" > <div class="date">{{ item.date.toLocaleString() }}</div> <div class="error">{{ item.error ? 'Error' : '' }}</div> <div class="value">{{ item.value }}</div> </div> </section> The app should now look as follows, with a navigation toolbar, two indicators, and the measures list: If you open the app in another window and put your windows side by side, you can see the full-stack reactivity of Meteor in action. Open the dashboard in one window and the generator page in the other window. Then, add fake measures and watch the data update on the other window in real time. If you want to learn more about Meteor, check out the official website and the Vue integration repository. To summarize, we created a project using Meteor. We integrated Vue into the app and set up a Meteor reactive collection. Using a Meteor method, we inserted documents into the collection and displayed in real-time the data in a dashboard component. You read an excerpt from a book written by Guillaume Chau, titled Vue.js 2 Web Development Projects. This book will help you build exciting real world web projects from scratch and become proficient with Vue.js Web Development. Read More Building your first Vue.js 2 Web application Why has Vue.js become so popular? Installing and Using Vue.js    
Read more
  • 0
  • 3
  • 13970

article-image-building-a-web-service-with-laravel-5
Kunal Chaudhari
24 Apr 2018
15 min read
Save for later

Building a Web Service with Laravel 5

Kunal Chaudhari
24 Apr 2018
15 min read
A web service is an application that runs on a server and allows a client (such as a browser) to remotely write/retrieve data to/from the server over HTTP. In this article we will be covering the following set of topics: Using Laravel to create a web service Writing database migrations and seed files Creating API endpoints to make data publicly accessible Serving images from Laravel The interface of a web service will be one or more API endpoints, sometimes protected with authentication, that will return data in an XML or JSON payload: Web services are a speciality of Laravel, so it won't be hard to create one for Vuebnb. We'll use routes for our API endpoints and represent the listings with Eloquent models that Laravel will seamlessly synchronize with the database: Laravel also has inbuilt features to add API architectures such as REST, though we won't need this for our simple use case. Mock data The mock listing data is in the file database/data.json. This file includes a JSON- encoded array of 30 objects, with each object representing a different listing. Having built the listing page prototype, you'll no doubt recognize a lot of the same properties on these objects, including the title, address, and description. database/data.json: [ { "id": 1, "title": "Central Downtown Apartment with Amenities", "address": "...", "about": "...", "amenity_wifi": true, "amenity_pets_allowed": true, "amenity_tv": true, "amenity_kitchen": true, "amenity_breakfast": true, "amenity_laptop": true, "price_per_night": "$89" "price_extra_people": "No charge", "price_weekly_discount": "18%", "price_monthly_discount": "50%", }, { "id": 2, ... }, ... ] Each mock listing includes several images of the room as well. Images aren't really part of a web service, but they will be stored in a public folder in our app to be served as needed. Database Our web service will require a database table for storing the mock listing data. To set this up we'll need to create a schema and migration. We'll then create a seeder that will load and parse our mock data file and insert it into the database, ready for use in the app. Migration A migration is a special class that contains a set of actions to run against the database, such as creating or modifying a database table. Migrations ensure your database gets set up identically every time you create a new instance of your app, for example, installing in production or on a teammate's machine. To create a new migration, use the make:migration Artisan CLI command. The argument of the command should be a snake-cased description of what the migration will do: $ php artisan make:migration create_listings_table You'll now see your new migration in the database/migrations directory. You'll notice the filename has a prefixed timestamp, such as 2017_06_20_133317_create_listings_table.php. The timestamp allows Laravel to determine the proper order of the migrations, in case it needs to run more than one at a time. Your new migration declares a class that extends Migration. It overrides two methods: up, which is used to add new tables, columns, or indexes to your database; and down, which is used to delete them. We'll implement these methods shortly. You'll now see your new migration in the database/migrations directory. You'll notice the filename has a prefixed timestamp, such as 2017_06_20_133317_create_listings_table.php. The timestamp allows Laravel to determine the proper order of the migrations, in case it needs to run more than one at a time. Your new migration declares a class that extends Migration. It overrides two methods: up, which is used to add new tables, columns, or indexes to your database; and down, which is used to delete them. We'll implement these methods shortly. 2017_06_20_133317_create_listings_table.php: <?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateListingsTable extends Migration { public function up() { // } public function down() { // } } Schema A schema is a blueprint for the structure of a database. For a relational database such as MySQL, the schema will organize data into tables and columns. In Laravel, schemas are declared by using the Schema facade's create method. We'll now make a schema for a table to hold Vuebnb listings. The columns of the table will match the structure of our mock listing data. Note that we set a default false value for the amenities and allow the prices to have a NULL value. All other columns require a value. The schema will go inside our migration's up method. We'll also fill out the down with a call to Schema::drop. 2017_06_20_133317_create_listings_table.php: public function up() { Schema::create('listings', function (Blueprint $table) { $table->primary('id'); $table->unsignedInteger('id'); $table->string('title'); $table->string('address'); $table->longText('about'); // Amenities $table->boolean('amenity_wifi')->default(false); $table->boolean('amenity_pets_allowed')->default(false); $table->boolean('amenity_tv')->default(false); $table->boolean('amenity_kitchen')->default(false); $table->boolean('amenity_breakfast')->default(false); $table->boolean('amenity_laptop')->default(false); // Prices $table->string('price_per_night')->nullable(); $table->string('price_extra_people')->nullable(); $table->string('price_weekly_discount')->nullable(); $table->string('price_monthly_discount')->nullable(); }); } public function down() { Schema::drop('listings'); } A facade is an object-oriented design pattern for creating a static proxy to an underlying class in the service container. The facade is not meant to provide any new functionality; its only purpose is to provide a more memorable and easily readable way of performing a common action. Think of it as an object-oriented helper function. Execution Now that we've set up our new migration, let's run it with this Artisan command: $ php artisan migrate You should see an output like this in the Terminal: Migrating: 2017_06_20_133317_create_listings_table Migrated:            2017_06_20_133317_create_listings_table To confirm the migration worked, let's use Tinker to show the new table structure. If you've never used Tinker, it's a REPL tool that allows you to interact with a Laravel app on the command line. When you enter a command into Tinker it will be evaluated as if it were a line in your app code. Firstly, open the Tinker shell: $ php artisan tinker Now enter a PHP statement for evaluation. Let's use the DB facade's select method to run an SQL DESCRIBE query to show the table structure: >>>> DB::select('DESCRIBE listings;'); The output is quite verbose so I won't reproduce it here, but you should see an object with all your table details, confirming the migration worked. Seeding mock listings Now that we have a database table for our listings, let's seed it with the mock data. To do so we're going to have to do the following:  Load the database/data.json file  Parse the file  Insert the data into the listings table Creating a seeder Laravel includes a seeder class that we can extend called Seeder. Use this Artisan command to implement it: $ php artisan make:seeder ListingsTableSeeder When we run the seeder, any code in the run method is executed. database/ListingsTableSeeder.php: <?php use Illuminate\Database\Seeder; class ListingsTableSeeder extends Seeder { public function run() { // } } Loading the mock data Laravel provides a File facade that allows us to open files from disk as simply as File::get($path). To get the full path to our mock data file we can use the base_path() helper function, which returns the path to the root of our application directory as a string. It's then trivial to convert this JSON file to a PHP array using the built-in json_decode method. Once the data is an array, it can be directly inserted into the database given that the column names of the table are the same as the array keys. database/ListingsTableSeeder.php: public  function  run() { $path  = base_path()  . '/database/data.json'; $file  = File::get($path); $data  = json_decode($file,  true); } Inserting the data In order to insert the data, we'll use the DB facade again. This time we'll call the table method, which returns an instance of Builder. The Builder class is a fluent query builder that allows us to query the database by chaining constraints, for example, DB::table(...)->where(...)->join(...) and so on. Let's use the insert method of the builder, which accepts an array of column names and values. database/seeds/ListingsTableSeeder.php: public  function  run() { $path  = base_path()  . '/database/data.json'; $file  = File::get($path); $data  = json_decode($file,  true); DB::table('listings')->insert($data); } Executing the seeder To execute the seeder we must call it from the DatabaseSeeder.php file, which is in the same directory. database/seeds/DatabaseSeeder.php: <?php use Illuminate\Database\Seeder; class DatabaseSeeder extends Seeder { public function run() { $this->call(ListingsTableSeeder::class); } } With that done, we can use the Artisan CLI to execute the seeder: $ php artisan db:seed You should see the following output in your Terminal: Seeding: ListingsTableSeeder We'll again use Tinker to check our work. There are 30 listings in the mock data, so to confirm the seed was successful, let's check for 30 rows in the database: $ php artisan tinker >>>> DB::table('listings')->count(); # Output: 30 Finally, let's inspect the first row of the table just to be sure its content is what we expect: >>>> DB::table('listings')->get()->first(); Here is the output: => {#732 +"id": 1, +"title": "Central Downtown Apartment with Amenities", +"address": "No. 11, Song-Sho Road, Taipei City, Taiwan 105", +"about": "...", +"amenity_wifi": 1, +"amenity_pets_allowed": 1, +"amenity_tv": 1, +"amenity_kitchen": 1, +"amenity_breakfast": 1, +"amenity_laptop": 1, +"price_per_night": "$89", +"price_extra_people": "No charge", +"price_weekly_discount": "18%", +"price_monthly_discount": "50%" } If yours looks like that you're ready to move on! Listing model We've now successfully created a database table for our listings and seeded it with mock listing data. How do we access this data now from the Laravel app? We saw how the DB facade lets us execute queries on our database directly. But Laravel provides a more powerful way to access data via the Eloquent ORM. Eloquent ORM Object-Relational Mapping (ORM) is a technique for converting data between incompatible systems in object-oriented programming languages. Relational databases such as MySQL can only store scalar values such as integers and strings, organized within tables. We want to make use of rich objects in our app, though, so we need a means of robust conversion. Eloquent is the ORM implementation used in Laravel. It uses the active record design pattern, where a model is tied to a single database table, and an instance of the model is tied to a single row. To create a model in Laravel using Eloquent ORM, simply extend the Illuminate\Database\Eloquent\Model class using Artisan: $ php artisan make:model Listing This generates a new file. app/Listing.php: <?php namespace App; use Illuminate\Database\Eloquent\Model; class Listing extends Model { // } How do we tell the ORM what table to map to, and what columns to include? By default, the Model class uses the class name (Listing) in lowercase (listing) as the table name to use. And, by default, it uses all the fields from the table. Now, any time we want to load our listings we can use code such as this, anywhere in our app: <?php // Load all listings $listings = \App\Listing::all(); // Iterate listings, echo the address foreach ($listings as $listing) { echo $listing->address . '\n' ; } /* * Output: * * No. 11, Song-Sho Road, Taipei City, Taiwan 105 * 110, Taiwan, Taipei City, Xinyi District, Section 5, Xinyi Road, 7 * No. 51, Hanzhong Street, Wanhua District, Taipei City, Taiwan 108 * ... */ Casting The data types in a MySQL database don't completely match up to those in PHP. For example, how does an ORM know if a database value of 0 is meant to be the number 0, or the Boolean value of false? An Eloquent model can be given a $casts property to declare the data type of any specific attribute. $casts is an array of key/values where the key is the name of the attribute being cast, and the value is the data type we want to cast to. For the listings table, we will cast the amenities attributes as Booleans. app/Listing.php: <?php namespace App; use Illuminate\Database\Eloquent\Model; class Listing extends Model { protected $casts = [ 'amenity_wifi' => 'boolean', 'amenity_pets_allowed' => 'boolean', 'amenity_tv' => 'boolean', 'amenity_kitchen' => 'boolean', 'amenity_breakfast' => 'boolean', 'amenity_laptop' => 'boolean' ]; } Now these attributes will have the correct type, making our model more robust: echo  gettype($listing->amenity_wifi()); //  boolean Public interface The final piece of our web service is the public interface that will allow a client app to request the listing data. Since the Vuebnb listing page is designed to display one listing at a time, we'll at least need an endpoint to retrieve a single listing. Let's now create a route that will match any incoming GET requests to the URI /api/listing/{listing} where {listing} is an ID. We'll put this in the routes/api.php file, where routes are automatically given the /api/ prefix and have middleware optimized for use in a web service by default. We'll use a closure function to handle the route. The function will have a $listing argument, which we'll type hint as an instance of the Listing class, that is, our model. Laravel's service container will resolve this as an instance with the ID matching {listing}. We can then encode the model as JSON and return it as a response. routes/api.php: <?php use App\Listing; Route::get('listing/{listing}', function(Listing $listing) { return $listing->toJson(); }); We can test this works by using the curl command from the Terminal: $ curl http://vuebnb.test/api/listing/1 The response will be the listing with ID 1: Controller We'll be adding more routes to retrieve the listing data as the project progresses. It's a best practice to use a controller class for this functionality to keep a separation of concerns. Let's create one with Artisan CLI: $ php artisan make:controller ListingController We'll then move the functionality from the route into a new method, get_listing_api. app/Http/Controllers/ListingController.php: <?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Listing; class ListingController extends Controller { public function get_listing_api(Listing $listing) { return $listing->toJson(); } } For the Route::get method we can pass a string as the second argument instead of a closure function. The string should be in the form [controller]@[method], for example, ListingController@get_listing_web. Laravel will correctly resolve this at runtime. routes/api.php: <?php Route::get('/listing/{listing}', 'ListingController@get_listing_api'); Images As stated at the beginning of the article, each mock listing comes with several images of the room. These images are not in the project code and must be copied from a parallel directory in the code base called images. Copy the contents of this directory into the public/images folder: $ cp -a ../images/. ./public/images Once you've copied these files, public/images will have 30 sub-folders, one for each mock listing. Each of these folders will contain exactly four main images and a thumbnail image: Accessing images Files in the public directory can be directly requested by appending their relative path to the site URL. For example, the default CSS file, public/css/app.css, can be requested at http://vuebnb.test/css/app.css. The advantage of using the public folder, and the reason we've put our images there, is to avoid having to create any logic for accessing them. A frontend app can then directly call the images in an img tag. You may think it's inefficient for our web server to serve images like this, and you'd be right. Let's try to open one of the mock listing images in our browser to test this thesis: http://vuebnb.test/images/1/Image_1.jpg: Image links The payload for each listing in the web service should include links to these new images so a client app knows where to find them. Let's add the image paths to our listing API payload so it looks like this: { "id": 1, "title": "...", "description": "...", ... "image_1": "http://vuebnb.test/app/image/1/Image_1.jpg", "image_2": "http://vuebnb.test/app/image/1/Image_2.jpg", "image_3": "http://vuebnb.test/app/image/1/Image_3.jpg", "image_4": "http://vuebnb.test/app/image/1/Image_4.jpg" } To implement this, we'll use our model's toArray method to make an array representation of the model. We'll then easily be able to add new fields. Each mock listing has exactly four images, numbered 1 to 4, so we can use a for loop and the asset helper to generate fully- qualified URLs to files in the public folder. We finish by creating an instance of the Response class by calling the response helper. We use the json; method and pass in our array of fields, returning the result. app/Http/Controllers/ListingController.php: public function get_listing_api(Listing $listing) { $model = $listing->toArray(); for($i = 1; $i <=4; $i++) { $model['image_' . $i] = asset( 'images/' . $listing->id . '/Image_' . $i . '.jpg' ); } return response()->json($model); } The /api/listing/{listing} endpoint is now ready for consumption by a client app. To summarize, we built a web service with Laravel to make the data publicly accessible. This involved setting up a database table using a migration and schema, then seeding the database with mock listing data. We then created a public interface for the web service using routes. You enjoyed an excerpt from a book written by Anthony Gore, titled Full-Stack Vue.js 2 and Laravel 5 which would help you bring the frontend and backend together with Vue, Vuex, and Laravel. Read More Testing RESTful Web Services with Postman How to develop RESTful web services in Spring        
Read more
  • 0
  • 0
  • 21970

article-image-data-bindings-with-knockout-js
Vijin Boricha
23 Apr 2018
7 min read
Save for later

Data bindings with Knockout.js

Vijin Boricha
23 Apr 2018
7 min read
Today, we will learn about three data binding abilities of Knockout.js. Data bindings are attributes added by the framework for the purpose of data access between elements and view scope. While Observable arrays are efficient in accessing the list of objects with the number of operations on top of the display of the list using the foreach function, Knockout.js has provided three additional data binding abilities: Control-flow bindings Appearance bindings Interactive bindings Let us review these data bindings in detail in the following sections. Control-flow bindings As the name suggests, control-flow bindings help us access the data elements based on a certain condition. The if, if-not, and with are the control-flow bindings available from the Knockout.js. In the following example, we will be using if and with control-flow bindings. We have added a new attribute to the Employee object called age; we are displaying the age value in green only if it is greater than 20. Similarly, we have added another markedEmployee. With control-flow binding, we can limit the scope of access to that specific employee object in the following paragraph. Add the following code snippet to index.html and run the program to see the if and with control-flow bindings working: <!DOCTYPE html> <html> <head> <title>Knockout JS</title> </head> <body> <h1>Welcome to Knockout JS programming</h1> <table border="1" > <tr > <th colspan="2" style="padding:10px;"> <b>Employee Data - Organization : <span style="color:red" data-bind='text: organizationName'> </span> </b> </th> </tr> <tr> <td style="padding:10px;">Employee First Name:</td> <td style="padding:10px;"> <span data-bind='text: empFirstName'></span> </td> </tr> <tr> <td style="padding:10px;">Employee Last Name:</td> <td style="padding:10px;"> <span data-bind='text: empLastName'></span> </td> </tr> </table> <p>Organization Full Name : <span style="color:red" data-bind='text: orgFullName'></span> </p> <!-- Observable Arrays--> <h2>Observable Array Example : </h2> <table border="1"> <thead><tr> <th style="padding:10px;">First Name</th> <th style="padding:10px;">Last Name</th> <th style="padding:10px;">Age</th> </tr></thead> <tbody data-bind='foreach: organization'> <tr> <td style="padding:10px;" data-bind='text: firstName'></td> <td style="padding:10px;" data-bind='text: lastName'></td> <td data-bind="if: age() > 20" style="color: green;padding:10px;"> <span data-bind='text:age'></span> </td> </tr> </tbody> </table> <!-- with control flow bindings --> <p data-bind='with: markedEmployee'> Employee <strong data-bind="text: firstName() + ', ' + lastName()"> </strong> is marked with the age <strong data-bind='text: age'> </strong> </p> <h2>Add New Employee to Observable Array</h2> First Name : <input data-bind="value: newFirstName" /> Last Name : <input data-bind="value: newLastName" /> Age : <input data-bind="value: newEmpAge" /> <button data-bind='click: addEmployee'>Add Employee</button> <!-- JavaScript resources --> <script type='text/javascript' src='js/knockout-3.4.2.js'></script> <script type='text/javascript'> function Employee (firstName, lastName,age) { this.firstName = ko.observable(firstName); this.lastName = ko.observable(lastName); this.age = ko.observable(age); }; this.addEmployee = function() { this.organization.push(new Employee (employeeViewModel.newFirstName(), employeeViewModel.newLastName(), employeeViewModel.newEmpAge())); }; var employeeViewModel = { empFirstName: "Tony", empLastName: "Henry", //Observable organizationName: ko.observable("Sun"), newFirstName: ko.observable(""), newLastName: ko.observable(""), newEmpAge: ko.observable(""), //With control flow object markedEmployee: ko.observable(new Employee("Garry", "Parks", "65")), //Observable Arrays organization : ko.observableArray([ new Employee("John", "Kennedy", "24"), new Employee("Peter", "Hennes","18"), new Employee("Richmond", "Smith","54") ]) }; //Computed Observable employeeViewModel.orgFullName = ko.computed(function() { return employeeViewModel.organizationName() + " Limited"; }); ko.applyBindings(employeeViewModel); employeeViewModel.organizationName("Oracle"); </script> </body> </html> Run the preceding program to see the if control-flow acting on the Age field, and the with control-flow showing a marked employee record with age 65: Appearance bindings Appearance bindings deal with displaying the data from binding elements on view components in formats such as text and HTML, and applying styles with the help of a set of six bindings, as follows: Text: <value>—Sets the value to an element. Example: <td data-bind='text: name'></td> HTML: <value>—Sets the HTML value to an element. Example: //JavaScript: function Employee(firstname, lastname, age) { ... this.formattedName = ko.computed(function() { return "<strong>" + this.firstname() + "</strong>"; }, this); } //Html: <span data-bind='html: markedEmployee().formattedName'></span> Visible: <condition>—An element can be shown or hidden based on the condition. Example: <td data-bind='visible: age() > 20' style='color: green'> span data-bind='text:age'> CSS: <object>—An element can be associated with a CSS class. Example: //CSS: .strongEmployee { font-weight: bold; } //HTML: <span data-bind='text: formattedName, css: {strongEmployee}'> </span> Style: <object>—Associates an inline style to the element. Example: <span data-bind='text: age, style: {color: age() > 20 ? "green" :"red"}'> </span> Attr: <object>—Defines an attribute for the element. Example: <p><a data-bind='attr: {href: featuredEmployee().populatelink}'> View Employee</a></p> Interactive bindings Interactive bindings help the user interact with the form elements to be associated with corresponding viewmodel methods or events to be triggered in the pages. Knockout JS supports the following interactive bindings: Click: <method>—An element click invokes a ViewModel method. Example: <button data-bind='click: addEmployee'>Submit</button> Value:<property>—Associates the form element value to the ViewModel attribute. Example: <td>Age: <input data-bind='value: age' /></td> Event: <object>—With an user-initiated event, it invokes a method. Example: <p data-bind='event: {mouseover: showEmployee, mouseout: hideEmployee}'> Age: <input data-bind='value: Age' /> </p> Submit: <method>—With a form submit event, it can invoke a method. Example: <form data-bind="submit: addEmployee"> <!—Employee form fields --> <button type="submit">Submit</button> </form> Enable: <property>—Conditionally enables the form elements. Example: last name field is enabled only after adding first name field. Disable: <property>—Conditionally disables the form elements. Example: last name field is disabled after adding first name: <p>Last Name: <input data-bind='value: lastName, disable: firstName' /> </p> Checked: <property>—Associates a checkbox or radio element to the ViewModel attribute. Example: <p>Gender: <input data-bind='checked:gender' type='checkbox' /></p> Options: <array>—Defines a ViewModel array for the<select> element. Example: //Javascript: this.designations = ko.observableArray(['manager', 'administrator']); //Html: Designation: <select data-bind='options: designations'></select> selectedOptions: <array>—Defines the active/selected element from the <select> element. Example: Designation: <select data-bind='options: designations, optionsText:"Select", selectedOptions:defaultDesignation'> </select> hasfocus: <property>—Associates the focus attribute to the element. Example: First Name: <input data-bind='value: firstName, hasfocus: firstNameHasFocus' /> We learned about data binding abilities of Knockout.js. You can know more about external data access and Hybrid Mobile Application Development from the book Oracle JET for Developers. Read More Text and appearance bindings and form field bindings Getting to know KnockoutJS Templates    
Read more
  • 0
  • 0
  • 3369

article-image-test-node-applications-using-mocha-framework
Sunith Shetty
20 Apr 2018
12 min read
Save for later

How to test node applications using Mocha framework

Sunith Shetty
20 Apr 2018
12 min read
In today’s tutorial, you will learn how to create your very first test case that tests whether your code is working as expected. If we make a function that's supposed to add two numbers together, we can automatically verify it's doing that. And if we have a function that's supposed to fetch a user from the database, we can make sure it's doing that as well. Now to get started in this section, we'll look at the very basics of setting up a testing suite inside a Node.js project. We'll be testing a real-world function. Installing the testing module In order to get started, we will make a directory to store our code for this chapter. We'll make one on the desktop using mkdir and we'll call this directory node-tests: mkdir node-tests Then we'll change directory inside it using cd, so we can go ahead and run npm init. We'll be installing modules and this will require a package.json file: cd node-tests npm init We'll run npm init using the default values for everything, simply hitting enter throughout every single step: Now once that package.json file is generated, we can open up the directory inside Atom. It's on the desktop and it's called node-tests. From here, we're ready to actually define a function we want to test. The goal in this section is to learn how to set up testing for a Node project, so the actual functions we'll be testing are going to be pretty trivial, but it will help illustrate exactly how to set up our tests. Testing a Node project To get started, let's make a fake module. This module will have some functions and we'll test those functions. In the root of the project, we'll create a brand new directory and I'll call this directory utils: We can assume this will store some utility functions, such as adding a number to another number, or stripping out whitespaces from a string, anything kind of hodge-podge that doesn't really belong to any specific location. We'll make a new file in the utils folder called utils.js, and this is a similar pattern to what we did when we created the weather and location directories in our weather app: You're probably wondering why we have a folder and a file with the same name. This will be clear when we start testing. Now before we can write our first test case to make sure something works, we need something to test. I'll make a very basic function that takes two numbers and adds them together. We'll create an adder function as shown in the following code block: module.exports.add = () => { } This arrow function (=>) will take two arguments, a and b, and inside the function, we'll return the value a + b. Nothing too complex here: module.exports.add = () => { return a + b; }; Now since we just have one expression inside our arrow function (=>) and we want to return it, we can actually use the arrow function (=>) expression syntax, which lets us add our expression as shown in the following code, a + b, and it'll be implicitly returned: module.exports.add = (a, b) => a + b; There's no need to explicitly add a return keyword on to the function. Now that we have utils.js ready to go, let's explore testing. We'll be using a framework called Mocha in order to set up our test suite. This will let us configure our individual test cases and also run all of our test files. This will be really important for creating and running tests. The goal here is to make testing simple and we'll use Mocha to do just that. Now that we have a file and a function we actually want to test, let's explore how to create and run a test suite. Mocha – the testing framework We'll be doing the testing using the super popular testing framework Mocha, which you can find at mochajs.org. This is a fantastic framework for creating and running test suites. It's super popular and their page has all the information you'd ever want to know about setting it up, configuring it, and all the cool bells and whistles it has included: If you scroll down on this page, you'll be able to see a table of contents: Here you can explore everything Mocha has to offer. We'll be covering most of it in this article, but for anything we don't cover, I do want to make you aware you can always learn about it on this page. Now that we've explored the Mocha documentation page, let's install it and start using it. Inside the Terminal, we'll install Mocha. First up, let's clear the Terminal output. Then we'll install it using the npm install command. When you use npm install, you can also use the shortcut npm i. This has the exact same effect. I'll use npm i with mocha, specifying the version @3.0.0. This is the most recent version of the library as of this filming: npm i mocha@3.0.0 Now we do want to save this into the package.json file. Previously, we've used the save flag, but we'll talk about a new flag, called save-dev. The save-dev flag is will save this package for development purposes only—and that's exactly what Mocha will be for. We don't actually need Mocha to run our app on a service like Heroku. We just need Mocha locally on our machine to test our code. When you use the save-dev flag, it installs the module much the same way: npm i mocha@5.0.0 --save-dev But if you explore package.json, you'll see things are a little different. Inside our package.json file, instead of a dependencies attribute, we have a devDependencies attribute: In there we have Mocha, with the version number as the value. The devDependencies are fantastic because they're not going to be installed on Heroku, but they will be installed locally. This will keep the Heroku boot times really, really quick. It won't need to install modules that it's not going to actually need. We'll be installing both devDependencies and dependencies in most of our projects from here on out. Creating a test file for the add function Now that we have Mocha installed, we can go ahead and create a test file. In the utils folder, we'll make a new file called utils.test.js:   This file will store our test cases. We'll not store our test cases in utils.js. This will be our application code. Instead, we'll make a file called utils.test.js. When we use this test.js extension, we're basically telling our app that this will store our test cases. When Mocha goes through our app looking for tests to run, it should run any file with this Extension. Now we have a test file, the only thing left to do is create a test case. A test case is a function that runs some code, and if things go well, great, the test is considered to have passed. And if things do not go well, the test is considered to have failed. We can create a new test case, using it. It is a function provided by Mocha. We'll be running our project test files through Mocha, so there's no reason to import it or do anything like that. We simply call it just like this: it(); Now it lets us define a new test case and it takes two arguments. These are: The first argument is a string The second argument is a function First up, we'll have a string description of what exactly the test is doing. If we're testing that the adder function works, we might have something like: it('should add two numbers'); Notice here that it plays into the sentence. It should read like this, it should add two numbers; describes exactly what the test will verify. This is called behavior-driven development, or BDD, and that's the principles that Mocha was built on. Now that we've set up the test string, the next thing to do is add a function as the second argument: it('should add two numbers', () => { }); Inside this function, we'll add the code that tests that the add function works as expected. This means it will probably call add and check that the value that comes back is the appropriate value given the two numbers passed in. That means we do need to import the util.js file up at the top. We'll create a constant, call utils, setting it equal to the return result from requiring utils. We're using ./ since we will be requiring a local file. It's in the same directory so I can simply type utils without the js extension as shown here: const utils = require('./utils'); it('should add two numbers', () => { }); Now that we have the utils library loaded in, inside the callback we can call it. Let's make a variable to store the return results. We'll call this one results. And we'll set it equal to utils.add passing in two numbers. Let's use something like 33 and 11: const utils = require('./utils'); it('should add two numbers', () => { var res = utils.add(33, 11); }); We would expect it to get 44 back. Now at this point, we do have some code inside of our test suites so we run it. We'll do that by configuring the test script. Currently, the test script simply prints a message to the screen saying that no tests exist. What we'll do instead is call Mocha. As shown in the following code, we'll be calling Mocha, passing in as the one and only argument the actual files we want to test. We can use a globbing pattern to specify multiple files. In this case, we'll be using ** to look in every single directory. We're looking for a file called utils.test.js: "scripts": { "test": "mocha **/utils.test.js" }, Now this is a very specific pattern. It's not going to be particularly useful. Instead, we can swap out the file name with a star as well. Now we're looking for any file on the project that has a file name ending in .test.js: "scripts": { "test": "mocha **/*.test.js" }, And this is exactly what we want. From here, we can run our test suite by saving package.json and moving to the Terminal. We'll use the clear command to clear the Terminal output and then we can run our test script using command shown as follows: npm test When we run this, we'll execute that Mocha command: It'll go off. It'll fetch all of our test files. It'll run all of them and print the results on the screen inside Terminal as shown in the preceding screenshot. Here we can see we have a green checkmark next to our test, should add two numbers. Next, we have a little summary, one passing test, and it happened in 8 milliseconds. It'll go off. It'll fetch all of our test files. It'll run all of them and print the results on the screen inside Terminal as shown in the preceding screenshot. Here we can see we have a green checkmark next to our test, should add two numbers. Next, we have a little summary, one passing test, and it happened in 8 milliseconds. Now in our case, we don't actually assert anything about the number that comes back. It could be 700 and we wouldn't care. The test will always pass. To make a test fail what we have to do is throw an error. That means we can throw a new error and we pass into the constructor function whatever message we want to use as the error as shown in the following code block. In this case, I could say something like Value not correct: const utils = require('./utils'); it('should add two numbers', () => { var res = utils.add(33, 11); throw new Error('Value not correct') }); Now with this in place, I can save the test file and rerun things from the Terminal by rerunning npm test, and when we do that now we have 0 tests passing and we have 1 test failing: Next we can see the one test is should add two numbers, and we get our error message, Value not correct. When we throw a new error, the test fails and that's exactly what we want to do for add. Creating the if condition for the test Now, we'll create an if statement for the test. If the response value is not equal to 44, that means we have a problem on our hands and we'll throw an error: const utils = require('./utils'); it('should add two numbers', () => { var res = utils.add(33, 11); if (res != 44){ } }); Inside the if condition, we can throw a new error and we'll use a template string as our message string because I do want to use the value that comes back in the error message. I'll say Expected 44, but got, then I'll inject the actual value, whatever happens to come back: const utils = require('./utils'); it('should add two numbers', () => { var res = utils.add(33, 11); if (res != 44){ throw new Error(`Expected 44, but got ${res}.`); } }); Now in our case, everything will line up great. But what if the add method wasn't working correctly? Let's simulate this by simply tacking on another addition, adding on something like 22 in utils.js: module.exports.add = (a, b) => a + b + 22; I'll save the file, rerun the test suite: Now we get an error message: Expected 44, but got 66. This error message is fantastic. It lets us know that something is going wrong with the test and it even tells us exactly what we got back and what we expected. This will let us go into the add function, look for errors, and hopefully fix them. Creating test cases doesn't need to be something super complex. In this case, we have a simple test case that tests a simple function. To summarize, we looked into basic testing of a node app. We explored the testing framework, Mocha which can be used for creating and running test suites. You read an excerpt from a book written by Andrew Mead, titled Learning Node.js Development. In this book, you will learn how to build, deploy, and test Node apps. Developing Node.js Web Applications How is Node.js Changing Web Development?        
Read more
  • 0
  • 0
  • 3344
article-image-how-to-build-a-basic-server-side-chatbot-using-go
Sunith Shetty
19 Apr 2018
20 min read
Save for later

How to build a basic server side chatbot using Go

Sunith Shetty
19 Apr 2018
20 min read
It's common nowadays to see chatbots (also known as agents) service the needs of website users for a wide variety of purposes, from deciding what shoes to purchase to providing tips on what stocks would look good on a client's portfolio. In a real-world scenario, this functionality would be an attractive proposition for both product sales and technical support usage scenarios. For instance, if a user has a particular question on a product listed on the website, they can freely browse through the website and have a live conversation with the agent. In today’s tutorial, we will examine the functionality required to implement the live chat feature on the server side chatbot. Let’s look at how to implement a live chat feature on various product related pages. In order to have the chat box present in all sections of the website, we will need to place the chat box div container right below the primary content div container in the web page layout template (layouts/webpage_layout.tmpl): <!doctype html> <html> {{ template "partials/header_partial" . }} <div id="primaryContent" class="pageContent"> {{ template "pagecontent" . }} </div> <div id="chatboxContainer" class="containerPulse"> </div> {{ template "partials/footer_partial" . }} </html> The chat box will be implemented as a partial template in the chatbox_partial.tmpl source file in the shared/templates/partials folder: <div id="chatbox"> <div id="chatboxHeaderBar" class="chatboxHeader"> <div id="chatboxTitle" class="chatboxHeaderTitle"><span>Chat with {{.AgentName}}</span></div> <div id="chatboxCloseControl">X</div> </div> <div class="chatboxAgentInfo"> <div class="chatboxAgentThumbnail"><img src="{{.AgentThumbImagePath}}" height="81px"></div> <div class="chatboxAgentName">{{.AgentName}}</div> <div class="chatboxAgentTitle">{{.AgentTitle}}</div> </div> <div id="chatboxConversationContainer"> </div> <div id="chatboxMsgInputContainer"> <input type="text" id="chatboxInputField" placeholder="Type your message here..."> </input> </div> <div class="chatboxFooter"> <a href="http://www.isomorphicgo.org" target="_blank">Powered by Isomorphic Go</a> </div> </div> This is the HTML markup required to implement the wireframe design of the live chat box. Note that the input textfield having the id "chatboxInputField". This is the input field where the user will be able to type their message. Each message created, both the one that the user writes, as well as the one that the bot writes, will use the livechatmsg_partial.tmpl template: <div class="chatboxMessage"> <div class="chatSenderName">{{.Name}}</div> <div class="chatSenderMsg">{{.Message}}</div> </div> Each message is inside its own div container that has two div containers (shown in bold) housing the name of the sender of the message and the message itself. There are no buttons necessary in the live chat feature, since we will be adding an event listener to listen for the press of the Enter key to submit the user's message to the server over the WebSocket connection. Now that we've implemented the HTML markup that will be used to render the chat box, let's examine the functionality required to implement the live chat feature on the server side. Live chat's server-side functionality When the live chat feature is activated, we will create a persistent, WebSocket connection, between the web client and the web server. The Gorilla Web Toolkit provides an excellent implementation of the WebSocket protocol in their websocket package. To fetch the websocket package, you may issue the following command: $ go get github.com/gorilla/websocket The Gorilla web toolkit also provides a useful example web chat application. Rather than reinventing the wheel, we will repurpose Gorilla's example web chat application to fulfill the live chat feature. The source files needed from the web chat example have been copied over to the chat folder. There are three major changes we need to make to realize the live chat feature using the example chat application provided by Gorilla: Replies from the chatbot (the agent) should be targeted to a specific user, and not be sent out to every connected user We need to create the functionality to allow the chatbot to send a message back to the user We need to implement the front-end portion of the chat application in Go Let's consider each of these three points in more detail. First, Gorilla's web chat example is a free-for-all chat room. Any user can come in, type a message, and all other users connected to the chat server will be able to see the message. A major requirement for the live chat feature is that each conversation between the chatbot and the human should be exclusive. Replies from the agent must be targeted to a specific user, and not to all connected users. Second, the example web chat application from the Gorilla web toolkit doesn't send any messages back to the user. This is where the custom chatbot comes into the picture. The agent will communicate directly with the user over the established WebSocket connection. Third, the front-end portion of the example web chat application is implemented as a HTML document containing inline CSS and JavaScript. As you may have guessed already, we will implement the front-end portion for the live chat feature in Go, and the code will reside in the client/chat folder. Now that we have established our plan of action to implement the live chat feature using the Gorilla web chat example as a foundation to start from, let's begin the implementation. The modified web chat application that we will create contains two main types: Hub and Client. The hub type The chat hub is responsible for maintaining a list of client connections and directing the chatbot to broadcast a message to the relevant client. For example, if Alice asked the question "What is Isomorphic Go?", the answer from the chatbot should go to Alice and not to Bob (who may not have even asked a question yet). Here's what the Hub struct looks like: type Hub struct {  chatbot bot.Bot  clients map[*Client]bool  broadcastmsg chan *ClientMessage register chan *Client  unregister chan *Client } The chatbot is a chat bot (agent) that implements the Bot interface. This is the brain that will answer the questions received from clients. The clients map is used to register clients. The key-value pair stored in the map consists of the key, a pointer to a Client instance, and the value consists of a Boolean value set to true to indicate that the client is connected. Clients communicate with the hub over the broadcastmsg, register, and unregister channels. The register channel registers a client with the hub. The unregister channel, unregisters a client with the hub. The client sends the message entered by the user over the broadcastmsg channel, a channel of type ClientMessage. Here's the ClientMessage struct that we have introduced: type ClientMessage struct {  client *Client  message []byte } To fulfill the first major change we laid out previously, that is, the exclusivity of the conversation between the agent and the user, we use the ClientMessage struct to store, both the pointer to the Client instance that sent the user's message along with the user's message itself (a byte slice). The constructor function, NewHub, takes in chatbot that implements the Bot interface and returns a new Hub instance: func NewHub(chatbot bot.Bot) *Hub {  return &Hub{    chatbot: chatbot,    broadcastmsg: make(chan *ClientMessage), register: make(chan    *Client), unregister:        make(chan *Client),    clients: make(map[*Client]bool),  } } We implement an exported getter method, ChatBot, so that the chatbot can be accessed from the Hub object: func (h *Hub) ChatBot() bot.Bot {  return h.chatbot } This action will be significant when we implement a Rest API endpoint to send the bot's details (its name, title, and avatar image) to the client. The SendMessage method is responsible for broadcasting a message to a particular client: func (h *Hub) SendMessage(client *Client, message []byte) {  client.send <- message } The method takes in a pointer to Client, and the message, which is a byte slice, that should be sent to that particular client. The message will be sent over the client's send channel. The Run method is called to start the chat hub: func (h *Hub) Run() { for { select { case client := <-h.register: h.clients[client] = true greeting := h.chatbot.Greeting() h.SendMessage(client, []byte(greeting)) case client := <-h.unregister: if _, ok := h.clients[client]; ok { delete(h.clients, client) close(client.send) } case clientmsg := <-h.broadcastmsg: client := clientmsg.client reply := h.chatbot.Reply(string(clientmsg.message)) h.SendMessage(client, []byte(reply)) } } } We use the select statement inside the for loop to wait on multiple client operations. In the case that a pointer to a Client comes in over the hub's register channel, the hub will register the new client by adding the client pointer (as the key) to the clients map and set a value of true for it. We will fetch a greeting message to return to the client by calling the Greeting method on chatbot. Once we get the greeting (a string value), we call the SendMessage method passing in the client and the greeting converted to a byte slice. In the case that a pointer to a Client comes in over the hub's unregister channel, the hub will remove the entry in map for the given client and close the client's send channel, which signifies that the client won't be sending any more messages to the server. In the case that a pointer to a ClientMessage comes in over the hub's broadcastmsg channel, the hub will pass the client's message (as a string value) to the Reply method of the chatbot object. Once we get reply (a string value) from the agent, we call the SendMessage method passing in the client and the reply converted to a byte slice. The client type The Client type acts as a broker between Hub and the websocket connection. Here's what the Client struct looks like: type Client struct {  hub *Hub  conn *websocket.Conn send chan []byte } Each Client value contains a pointer to Hub, a pointer to a websocket connection, and a buffered channel, send, meant for outbound messages. The readPump method is responsible for relaying inbound messages coming in over the websocket connection to the hub: func (c *Client) readPump() { defer func() { c.hub.unregister <- c c.conn.Close() }() c.conn.SetReadLimit(maxMessageSize) c.conn.SetReadDeadline(time.Now().Add(pongWait)) c.conn.SetPongHandler(func(string) error { c.conn.SetReadDeadline(time.Now().Add(pongWait)); return nil }) for { _, message, err := c.conn.ReadMessage() if err != nil { if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) { log.Printf("error: %v", err) } break } message = bytes.TrimSpace(bytes.Replace(message, newline, space, -1)) // c.hub.broadcast <- message clientmsg := &ClientMessage{client: c, message: message} c.hub.broadcastmsg <- clientmsg } } We had to make a slight change to this function to fulfill the requirements of the live chat feature. In the Gorilla web chat example, the message alone was relayed over to Hub. Since we are directing chat bot responses, back to the client that sent them, not only do we need to send the message to the hub, but also the client that happened to send the message (shown in bold). We do so by creating a ClientMessage struct: type ClientMessage struct {  client *Client  message []byte } The ClientMessage struct contains fields to hold both the pointer to the client as well as the message, a byte slice. Going back to the readPump function in the client.go source file, the following two lines are instrumental in allowing the Hub to know which client sent the message: clientmsg := &ClientMessage{client: c, message: message}  c.hub.broadcastmsg <- clientmsg The writePump method is responsible for relaying outbound messages from the client's send channel over the websocket connection: func (c *Client) writePump() { ticker := time.NewTicker(pingPeriod) defer func() { ticker.Stop() c.conn.Close() }() for { select { case message, ok := <-c.send: c.conn.SetWriteDeadline(time.Now().Add(writeWait)) if !ok { // The hub closed the channel. c.conn.WriteMessage(websocket.CloseMessage, []byte{}) return } w, err := c.conn.NextWriter(websocket.TextMessage) if err != nil { return } w.Write(message) // Add queued chat messages to the current websocket message. n := len(c.send) for i := 0; i < n; i++ { w.Write(newline) w.Write(<-c.send) } if err := w.Close(); err != nil { return } case <-ticker.C: c.conn.SetWriteDeadline(time.Now().Add(writeWait)) if err := c.conn.WriteMessage(websocket.PingMessage, []byte{}); err != nil { return } } } } The ServeWS method is meant to be registered as an HTTP handler by the web application: func ServeWs(hub *Hub) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { conn, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Println(err) return } client := &Client{hub: hub, conn: conn, send: make(chan []byte, 256)} client.hub.register <- client go client.writePump() client.readPump() }) } This method performs two important tasks. The method upgrades the normal HTTP connection to a websocket connection and registers the client to the hub. Now that we've set up the code for our web chat server, it's time to activate it in our web application. Activating the chat server In the igweb.go source file, we have included a function called startChatHub, which is responsible for starting the Hub: func startChatHub(hub *chat.Hub) {  go hub.Run() } We add the following code in the main function to create a new chatbot, associate it with the Hub, and start the Hub: chatbot := bot.NewAgentCase() hub := chat.NewHub(chatbot) startChatHub(hub) When we call the registerRoutes function to register all the routes for the server-side web application, note that we also pass in the hub value to the function: r := mux.NewRouter() registerRoutes(&env, r, hub) In the registerRoutes function, we need the hub to register the route handler for the Rest API endpoint that returns the agent's information: r.Handle("/restapi/get-agent-info", endpoints.GetAgentInfoEndpoint(env, hub.ChatBot())) The hub is also used to register the route handler for the WebSocket route, /ws. We register the ServeWS handler function, passing in the hub: r.Handle("/ws", chat.ServeWs(hub)) Now that we have everything in place to activate the chat server, it's time to focus on the star of the live chat feature—the chat agent. The agent's brain The chat bot type that we will use for the live chat feature, AgentCase, will implement the following Bot interface: type Bot interface { Greeting() string Reply(string) string Name() string Title() string ThumbnailPath() string SetName(string) SetTitle(string) SetThumbnailPath(string) } The Greeting method will be used to send an initial greeting to the user, enticing them to interact with the chat bot. The Reply method accepts a question (a string) and returns a reply (also a string) for the given question. The rest of the methods implemented are for purely psychological reasons to give humans the illusion that they are communicating with someone, rather than something. The Name method is a getter method that returns the chat bot's name. The Title method is a getter method that returns the chat bot's title. The ThumbnailPath method is a getter method that returns the path to the chat bot's avatar image. Each of the getter methods has a corresponding setter method: SetName, SetTitle, and SetThumbnailPath. By defining the Bot interface, we are clearly stating the expectations of a chat bot. This allows us to make the chat bot solution extensible in the future. For example, the intelligence that Case exhibits may be too rudimentary and limiting. In the near future, we may want to implement a bot named Molly, whose intelligence may be implemented using a more powerful algorithm. As long as the Molly chat bot implements the Bot interface, the new chat bot can be easily plugged into our web application. In fact, from the perspective of the server-side web application, it would just be a one-line code change. Instead of instantiating an AgentCase instance, we would instantiate an AgentMolly instance instead. Besides the difference in intelligence, the new chat bot, Molly, would come with its own name, title, and avatar image, so humans would be able to differentiate it from Case. Here's the AgentCase struct: type AgentCase struct { Bot name string title string thumbnailPath string knowledgeBase map[string]string knowledgeCorpus []string sampleQuestions []string } We have embedded the Bot interface to the struct definition, indicating that the AgentCase type will implement the Bot interface. The field name is for the name of the agent. The field title is for the title of the agent. The field thumbnailPath is used to specify the path to the chat bot's avatar image. The knowledgeBase field is  map of type map[string]string. This is essentially the agent's brain. Keys in the map are the common terms found in a particular question. Values in the map are the answers to the question. The knowledgeCorpus field, a string byte slice, is a knowledge corpus of the terms that may exist in questions that the bot will be asked. We use the keys of the knowledgeBase map to construct the knowledgeCorpus. A corpus is a collection of text that is used to conduct linguistic analysis. In our case, we will conduct the linguistic analysis based on the question (the query) that the human user provided to the bot. The sampleQuestions field, a string byte slice, will contain a list of sample questions that the user may ask the chat bot. The chat bot will provide the user with a sample question when it greets them to entice the human user into a conversation. It is understood that the human user is free to paraphrase the sample question or ask an entirely different question depending on their preference. The initializeIntelligence method is used to initialize Case's brain: func (a *AgentCase) initializeIntelligence() { a.knowledgeBase = map[string]string{ "isomorphic go isomorphic go web applications": "Isomorphic Go is the methodology to create isomorphic web applications using the Go (Golang) programming language. An isomorphic web application, is a web application, that contains code which can run, on both the web client and the web server.", "kick recompile code restart web server instance instant kickstart lightweight mechanism": "Kick is a lightweight mechanism to provide an instant kickstart to a Go web server instance, upon the modification of a Go source file within a particular project directory (including any subdirectories). An instant kickstart consists of a recompilation of the Go code and a restart of the web server instance. Kick comes with the ability to take both the go and gopherjs commands into consideration when performing the instant kickstart. This makes it a really handy tool for isomorphic golang projects.", "starter code starter kit": "The isogoapp, is a basic, barebones web app, intended to be used as a starting point for developing an Isomorphic Go application. Here's the link to the github page: https://github.com/isomorphicgo/isogoapp", "lack intelligence idiot stupid dumb dummy don't know anything": "Please don't question my intelligence, it's artificial after all!", "find talk topic presentation lecture subject": "Watch the Isomorphic Go talk by Kamesh Balasubramanian at GopherCon India: https://youtu.be/zrsuxZEoTcs", "benefits of the technology significance of the technology importance of the technology": "Here are some benefits of Isomorphic Go: Unlike JavaScript, Go provides type safety, allowing us to find and eliminate many bugs at compile time itself. Eliminates mental context-shifts between back- end and front-end coding. Page loading prompts are not necessary.", "perform routing web app register routes define routes": "You can implement client-side routing in your web application using the isokit Router preventing the dreaded full page reload.", "render templates perform template rendering": "Use template sets, a set of project templates that are persisted in memory and are available on both the server-side and the client-side", "cogs reusable components react-like react": "Cogs are reuseable components in an Isomorphic Go web application.", } a.knowledgeCorpus = make([]string, 1) for k, _ := range a.knowledgeBase { a.knowledgeCorpus = append(a.knowledgeCorpus, k) } a.sampleQuestions = []string{"What is isomorphic go?", "What are the benefits of this technology?", "Does isomorphic go offer anything react- like?", "How can I recompile code instantly?", "How can I perform routing in my web app?", "Where can I get starter code?", "Where can I find a talk on this topic?"} } There are three important tasks that occur within this method: First, we set Case's knowledge base. Second, we set Case's knowledge corpus. Third, we set the sample questions, which Case will utilize when greeting the human user. The first task we must take care of is to set Case's knowledge base. This consists of setting the knowledgeBase property of the AgentCase instance. As mentioned earlier, the keys in the map refer to terms found in the question, and the values in the map are the answers to the question. For example, the "isomorphic go isomorphic go web applications" key could service the following questions: What is Isomorphic Go? What can you tell me about Isomorphic Go? Due to the the large amount of text contained within the map literal declaration for the knowledgeBase map, I encourage you to view the source file, agentcase.go, on a computer. The second task we must take care of is to set Case's corpus, the collection of text used for linguistic analysis used against the user's question. The corpus is constructed from the keys of the knowledgeBase map. We set the knowledgeCorpus field property of the AgentCase instance to a newly created string byte slice using the built-in make function. Using a for loop, we iterate through all the entries in the knowledgeBase map and append each key to the knowledgeCorpus field slice. The third and last task we must take care of is to set the sample questions that Case will present to the human user. We simply populate the sampleQuestions property of the AgentCase instance. We use the string literal declaration to populate all the sample questions that are contained in the string byte slice. Here are the getter and setter methods of the AgentCase type: func (a *AgentCase) Name() string { return a.name } func (a *AgentCase) Title() string { return a.title } func (a *AgentCase) ThumbnailPath() string { return a.thumbnailPath } func (a *AgentCase) SetName(name string) { a.name = name } func (a *AgentCase) SetTitle(title string) { a.title = title } func (a *AgentCase) SetThumbnailPath(thumbnailPath string) { a.thumbnailPath = thumbnailPath } These methods are used to get and set the name, title, and thumbnailPath fields of the AgentCase object. Here's the constructor function used to create a new AgentCase instance: func NewAgentCase() *AgentCase {  agentCase := &AgentCase{name: "Case", title: "Resident Isomorphic  Gopher Agent",     thumbnailPath: "/static/images/chat/Case.png"}  agentCase.initializeIntelligence() return agentCase } We declare and initialize the agentCase variable with a new AgentCase instance, setting the fields for name, title, and thumbnailPath. We then call the initializeIntelligence method to initialize Case's brain. Finally, we return the newly created and initialized AgentCase instance. To summarize, we introduced you to the websocket package from the Gorilla toolkit project. We learned how to establish a persistent connection between the web server and the web client to create a server-side chatbot using WebSocket functionality. You read an excerpt from a book written by Kamesh Balasubramanian titled Isomorphic Go. In this book, you will learn how to build and deploy Isomorphic Go web applications. Top 4 chatbot development frameworks for developers How to create a conversational assistant or chatbot using Python Build a generative chatbot using recurrent neural networks (LSTM RNNs)    
Read more
  • 0
  • 0
  • 9285

article-image-packaging-and-publishing-an-oracle-jet-hybrid-mobile-application
Vijin Boricha
17 Apr 2018
4 min read
Save for later

Packaging and publishing an Oracle JET Hybrid mobile application

Vijin Boricha
17 Apr 2018
4 min read
Today, we will learn how to package and publish an Oracle JET mobile application on Apple Store and Android Play Store. We can package and publish Oracle JET-based hybrid mobile applications to Google Play or Apple App stores, using framework support and third-party tools. Packaging a mobile application An Oracle JET Hybrid mobile application can be packaged with the help of Grunt build release commands, as described in the following steps: The Grunt release command can be issued with the desired platform as follows: grunt build:release --platform={ios|android} Code sign the application based on the platform in the buildConfig.json component. Note: Further details regarding code sign per platform are available at: Android: https:// cordova.apache.org/docs/en/latest/guide/platforms/android/tools. html.iOS:https:// cordova.apache.org/docs/en/latest/guide/platforms/ios/tools.Html. We can pass the code sign details and rebuild the application using the following command: grunt build:release --platform={ios|android} --buildConfig=path/buildConfig.json The application can be tested after the preceding changes using the following serve command: grunt serve:release --platform=ios|android [--web=true --serverPort=server-port-number --livereloadPort=live-reload-port-number - -destination=emulator-name|device] --buildConfig==path/buildConfig.json Publishing a mobile application Publishing an Oracle JET hybrid mobile application is as per the platform-specific guidelines. Each platform has defined certain standards and procedures to distribute an app on the respective platforms. Publishing on an iOS platform The steps involved in publishing iOS applications include: Enrolling in the Apple Developer Program to distribute the app. Adding advanced, integrated services based on the application type. Preparing our application with approval and configuration according to iOS standards. Testing our app on numerous devices and application releases. Submitting and releasing the application as a mobile app in the store. Alternatively, we can also distribute the app outside the store. The iOS distribution process is represented in the following diagram: Please note that the process for distributing applications on iOS presented in the preceding diagram is the latest, as of writing this chapter. It may be altered by the iOS team at a later point. The preceding said process is up-to-date, as of writing this chapter. Note: For the latest iOS app distribution procedure, please refer to the official iOS documentation at: https://developer.apple.com/library/ios/documentation/IDEs/ Conceptual/AppDistributionGuide/Introduction/Introduction.html Publishing on an Android platform There are multiple approaches to publish our application on Android platforms. The following are the steps involved in publishing the app on Android: Preparing the app for release. We need to perform the following activities to prepare an app for release: Configuring the app for release, including logs and manifests. Testing the release version of the app on multiple devices. Updating the application resources for the release. Preparing any remote applications or services the app interacts with. 2. Releasing the app to the market through Google Play. We need to perform the following activities to prepare an app for release through Google Play: Prepare any promotional documentation required for the app. Configure all the default options and prepare the components. Publish the prepared release version of the app to Google Play. 3. Alternately, we can publish the application through email, or through our own website, for users to download and install. The steps involved in publishing Android applications are advised in the following diagram: Please note that the process for distributing applications on Android presented in the preceding diagram is the latest, as of writing this chapter. It may be altered by the Android team at a later point. Note: For the latest Android app distribution procedure, please refer to the official Android documentation at http://developer.android.com/tools/publishing/publishing_overview. html#publishing-release. You enjoyed an excerpt  from Oracle JET for Developers written by Raja Malleswara Rao Pattamsetti.  With this book, you will learn to leverage Oracle JavaScript Extension Toolkit (JET) to develop efficient client-side applications. Auditing Mobile Applications Creating and configuring a basic mobile application    
Read more
  • 0
  • 0
  • 2543

article-image-building-first-vue-js-web-application
Kunal Chaudhari
17 Apr 2018
11 min read
Save for later

Building your first Vue.js 2 Web application

Kunal Chaudhari
17 Apr 2018
11 min read
Vue is a relative newcomer in the JavaScript frontend landscape, but a very serious challenger to the current leading libraries. It is simple, flexible, and very fast, while still providing a lot of features and optional tools that can help you build a modern web app efficiently. In today’s tutorial, we will explore Vue.js library and then we will start creating our first web app. Why another frontend framework? Its creator, Evan You, calls it the progressive framework. Vue is incrementally adoptable, with a core library focused on user interfaces that you can use in existing projects You can make small prototypes all the way up to large and sophisticated web applications Vue is approachable-- beginners can pick up the library easily, and confirmed developers can be productive very quickly Vue roughly follows a Model-View-ViewModel architecture, which means the View (the user interface) and the Model (the data) are separated, with the ViewModel (Vue) being a mediator between the two. It handles the updates automatically and has been already optimized for you. Therefore, you don't have to specify when a part of the View should update because Vue will choose the right way and time to do so. The library also takes inspiration from other similar libraries such as React, Angular, and Polymer. The following is an overview of its core features: A reactive data system that can update your user interface automatically, with a lightweight virtual-DOM engine and minimal optimization efforts, is required Flexible View declaration--artist-friendly HTML templates, JSX (HTML inside JavaScript), or hyperscript render functions (pure JavaScript) Composable user interfaces with maintainable and reusable components Official companion libraries that come with routing, state management, scaffolding, and more advanced features, making Vue a non-opinionated but fully fleshed out frontend framework Vue.js - A trending project Evan You started working on the first prototype of Vue in 2013, while working at Google, using Angular. The initial goal was to have all the cool features of Angular, such as data binding and data-driven DOM, but without the extra concepts that make a framework opinionated and heavy to learn and use. The first public release was published on February 2014 and had immediate success the very first day, with HackerNews frontpage, /r/javascript at the top spot and 10k unique visits on the official website. The first major version 1.0 was reached in October 2015, and by the end of that year, the npm downloads rocketed to 382k ytd, the GitHub repository received 11k stars, the official website had 363k unique visitors, and the popular PHP framework Laravel had picked Vue as its official frontend library instead of React. The second major version, 2.0, was released in September 2016, with a new virtual DOM- based renderer and many new features such as server-side rendering and performance improvements. This is the version we will use in this article. It is now one of the fastest frontend libraries, outperforming even React according to a comparison refined with the React team. At the time of writing this article, Vue was the second most popular frontend library on GitHub with 72k stars, just behind React and ahead of Angular 1. The next evolution of the library on the roadmap includes more integration with Vue-native libraries such as Weex and NativeScript to create native mobile apps with Vue, plus new features and improvements. Today, Vue is used by many companies such as Microsoft, Adobe, Alibaba, Baidu, Xiaomi, Expedia, Nintendo, and GitLab. Compatibility requirements Vue doesn't have any dependency and can be used in any ECMAScript 5 minimum- compliant browser. This means that it is not compatible with Internet Explorer 8 or less, because it needs relatively new JavaScript features such as Object.defineProperty, which can't be polyfilled on older browsers. In this article, we are writing code in JavaScript version ES2015 (formerly ES6), so you will need a modern browser to run the examples (such as Edge, Firefox, or Chrome). At some point, we will introduce a compiler called Babel that will help us make our code compatible with older browsers. One-minute setup Without further ado, let's start creating our first Vue app with a very quick setup. Vue is flexible enough to be included in any web page with a simple script tag. Let's create a very simple web page that includes the library, with a simple div element and another script tag: <html> <head> <meta charset="utf-8"> <title>Vue Project Guide setup</title> </head> <body> <!-- Include the library in the page --> <script src="https://unpkg.com/vue/dist/vue.js"></script> <!-- Some HTML --> <div id="root"> <p>Is this an Hello world?</p> </div> <!-- Some JavaScript →> <script> console.log('Yes! We are using Vue version', Vue.version) </script> </body> </html> In the browser console, we should have something like this: Yes! We are using Vue version 2.0.3 As you can see in the preceding code, the library exposes a Vue object that contains all the features we need to use it. We are now ready to go. Creating an app For now, we don't have any Vue app running on our web page. The whole library is based on Vue instances, which are the mediators between your View and your data. So, we need to create a new Vue instance to start our app: // New Vue instance var app = new Vue({ // CSS selector of the root DOM element el: '#root', // Some data data () { return { message: 'Hello Vue.js!', } }, }) The Vue constructor is called with the new keyword to create a new instance. It has one argument--the option object. It can have multiple attributes (called options). For now, we are using only two of them. With the el option, we tell Vue where to add (or "mount") the instance on our web page using a CSS selector. In the example, our instance will use the <div id="root"> DOM element as its root element. We could also use the $mount method of the Vue instance instead of the el option: var app = new Vue({ data () { return { message: 'Hello Vue.js!', } }, }) // We add the instance to the page app.$mount('#root') Most of the special methods and attributes of a Vue instance start with a dollar character. We will also initialize some data in the data option with a message property that contains a string. Now the Vue app is running, but it doesn't do much, yet. You can add as many Vue apps as you like on a single web page. Just create a new Vue instance for each of them and mount them on different DOM elements. This comes in handy when you want to integrate Vue in an existing project. Vue devtools An official debugger tool for Vue is available on Chrome as an extension called Vue.js devtools. It can help you see how your app is running to help you debug your code. You can download it from the Chrome Web Store (https://chrome.google.com/webstore/ search/vue) or from the Firefox addons registry (https://addons.mozilla.org/en-US/ firefox/addon/vue-js-devtools/?src=ss). For the Chrome version, you need to set an additional setting. In the extension settings, enable Allow access to file URLs so that it can detect Vue on a web page opened from your local drive: On your web page, open the Chrome Dev Tools with the F12 shortcut (or Shift + command + c on OS X) and search for the Vue tab (it may be hidden in the More tools... dropdown). Once it is opened, you can see a tree with our Vue instance named Root by convention. If you click on it, the sidebar displays the properties of the instance: You can drag and drop the devtools tab to your liking. Don't hesitate to place it among the first tabs, as it will be hidden in the page where Vue is not in development mode or is not running at all. You can change the name of your instance with the name option: var app = new Vue({ name: 'MyApp', // ...         }) This will help you see where your instance in the devtools is when you will have many more: Templates make your DOM dynamic With Vue, we have several systems at our disposal to write our View. For now, we will start with templates. A template is the easiest way to describe a View because it looks like HTML a lot, but with some extra syntax to make the DOM dynamically update very easily. Displaying text The first template feature we will see is the text interpolation, which is used to display dynamic text inside our web page. The text interpolation syntax is a pair of double curly braces containing a JavaScript expression of any kind. Its result will replace the interpolation when Vue will process the template. Replace the <div id="root"> element with the following: <div id="root"> <p>{{ message }}</p> </div> The template in this example has a <p> element whose content is the result of the message JavaScript expression. It will return the value of the message attribute of our instance. You should now have a new text displayed on your web page--Hello Vue.js!. It doesn't seem like much, but Vue has done a lot of work for us here--we now have the DOM wired with our data. To demonstrate this, open your browser console and change the app.message value and press Enter on the keyboard: app.message = 'Awesome!' The message has changed. This is called data-binding. It means that Vue is able to automatically update the DOM whenever your data changes without requiring anything from your part. The library includes a very powerful and efficient reactivity system that keeps track of all your data and is able to update what's needed when something changes. All of this is very fast indeed. Adding basic interactivity with directives Let's add some interactivity to our otherwise quite static app, for example, a text input that will allow the user to change the message displayed. We can do that in templates with special HTML attributes called directives. All the directives in Vue start with v- and follow the kebab-case syntax. That means you should separate the words with a dash. Remember that HTML attributes are case insensitive (whether they are uppercase or lowercase doesn't matter). The directive we need here is v-model, which will bind the value of our <input> element with our message data property. Add a new <input> element with the v-model="message" attribute inside the template: <div id="root"> <p>{{ message }}</p> <!-- New text input --> <input v-model="message" /> </div> Vue will now update the message property automatically when the input value changes. You can play with the content of the input to verify that the text updates as you type and the value in the devtools changes: There are many more directives available in Vue, and you can even create your own. To summarize, we quickly set up a web page to get started using Vue and wrote a simple app. We created a Vue instance to mount the Vue app on the page and wrote a template to make the DOM dynamic. Inside this template, we used a JavaScript expression to display text, thanks to text interpolations. Finally, we added some interactivity with an input element that we bound to our data with the v-model directive. You read an excerpt from a book written by Guillaume Chau, titled Vue.js 2 Web Development Projects. Its a project-based, practical guide to get hands-on into Vue.js 2.5 development by building beautiful, functional and performant web. Why has Vue.js become so popular? Building a real-time dashboard with Meteor and Vue.js      
Read more
  • 0
  • 0
  • 5070
article-image-how-to-develop-restful-web-services-in-spring
Vijin Boricha
13 Apr 2018
6 min read
Save for later

How to develop RESTful web services in Spring

Vijin Boricha
13 Apr 2018
6 min read
Today, we will explore the basics of creating a project in Spring and how to leverage Spring Tool Suite for managing the project. To create a new project, we can use a Maven command prompt or an online tool, such as Spring Initializr (http://start.spring.io), to generate the project base. This website comes in handy for creating a simple Spring Boot-based web project to start the ball rolling. Creating a project base Let's go to http://start.spring.io in our browser and configure our project by filling in the following parameters to create a project base: Group: com.packtpub.restapp Artifact: ticket-management Search for dependencies: Web (full-stack web development with Tomcat and Spring MVC) After configuring our project, it will look as shown in the following screenshot: Now you can generate the project by clicking Generate Project. The project (ZIP file) should be downloaded to your system. Unzip the .zip file and you should see the files as shown in the following screenshot: Copy the entire folder (ticket-management) and keep it in your desired location. Working with your favorite IDE Now is the time to pick the IDE. Though there are many IDEs used for Spring Boot projects, I would recommend using Spring Tool Suite (STS), as it is open source and easy to manage projects with. In my case, I use sts-3.8.2.RELEASE. You can download the latest STS from this link: https://spring. io/tools/sts/ all. In most cases, you may not need to install; just unzip the file and start using it: After extracting the STS, you can start using the tool by running STS.exe (shown in the preceding screenshot). In STS, you can import the project by selecting Existing Maven Projects, shown as follows: After importing the project, you can see the project in Package Explorer, as shown in the following screenshot: You can see the main Java file (TicketManagementApplication) by default: To simplify the project, we will clean up the existing POM file and update the required dependencies. Add this file configuration to pom.xml: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.packtpub.restapp</groupId> <artifactId>ticket-management</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>ticket-management</name> <description>Demo project for Spring Boot</description> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.0.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>1.5.7.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <version>1.5.7.RELEASE</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.2</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.0.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.0.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <version>1.5.7.RELEASE</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> In the preceding configuration, you can check that we have used the following libraries: spring-web spring-boot-starter spring-boot-starter-tomcat spring-bind jackson-databind As the preceding dependencies are needed for the project to run, we have added them to our pom.xml file. So far we have got the base project ready for Spring Web Service. Let's add a basic REST code to the application. First, remove the @SpringBootApplication annotation from the TicketManagementApplication class and add the following annotations: @Configuration @EnableAutoConfiguration @ComponentScan @Controller These annotations will help the class to act as a web service class. I am not going to talk much about what these configurations will do in this chapter. After adding the annotations, please add a simple method to return a string as our basic web service method: @ResponseBody @RequestMapping("/") public String sayAloha(){ return "Aloha"; } Finally, your code will look as follows: package com.packtpub.restapp.ticketmanagement; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Configuration @EnableAutoConfiguration @ComponentScan @Controller public class TicketManagementApplication { @ResponseBody @RequestMapping("/") public String sayAloha(){ return "Aloha"; } public static void main(String[] args) { SpringApplication.run(TicketManagementApplication.class, args); } } Once all the coding changes are done, just run the project on Spring Boot App (Run As | Spring Boot App). You can verify the application has loaded by checking this message in the console: Tomcat started on port(s): 8080 (http) Once verified, you can check the API on the browser by simply typing localhost:8080. Check out the following screenshot: If you want to change the port number, you can configure a different port number in application.properties, which is in src/main/resources/application.properties. Check out the following screenshot: You read an excerpt from Building RESTful Web Services with Spring 5 - Second Edition written by Raja CSP Raman. From this book, you will learn to implement the REST architecture to build resilient software in Java. Check out other related posts: Starting with Spring Security Testing RESTful Web Services with Postman Applying Spring Security using JSON Web Token (JWT)
Read more
  • 0
  • 0
  • 3718

article-image-how-to-publish-a-microservice-as-a-service-onto-a-docker
Pravin Dhandre
12 Apr 2018
6 min read
Save for later

How to publish Microservice as a service onto a Docker

Pravin Dhandre
12 Apr 2018
6 min read
In today’s tutorial, we will show a step-by-step approach to publishing a prebuilt microservice onto a docker so you can scale and control it further. Once the swarm is ready, we can use it to create services that we can use for scaling, but first, we will create a shared registry in our swarm. Then, we will build a microservice and publish it into a Docker. Creating a registry When we create a swarm's service, we specify an image that will be used, but when we ask Docker to create the instances of the service, it will use the swarm master node to do it. If we have built our Docker images in our machine, they are not available on the master node of the swarm, so it will create a registry service that we can use to publish our images and reference when we create our own services. First, let's create the registry service: docker service create --name registry --publish 5000:5000 registry Now, if we list our services, we should see our registry created: docker service ls ID NAME MODE REPLICAS IMAGE PORTS os5j0iw1p4q1 registry replicated 1/1 registry:latest *:5000->5000/tcp And if we visit http://localhost:5000/v2/_catalog, we should just get: {"repositories":[]} This Docker registry is ephemeral, meaning that if we stop the service or start it again, our images will disappear. For that reason, we recommend to use it only for development. For a real registry, you may want to use an external service. We discussed some of them in Chapter 7, Creating Dockers. Creating a microservice In order to create a microservice, we will use Spring Initializr, as we have been doing in previous chapters. We can start by visiting the URL: https:/​/​start.​spring.​io/​: Creating a project in Spring Initializr We have chosen to create a Maven Project using Kotlin and Spring Boot 2.0.0 M7. We chose the Group to be com.Microservices and the Artifact to be chapter08. For Dependencies, we have set Web. Now, we can click Generate Project to download it as a zip file. After we unzip it, we can open it with IntelliJ IDEA to start working on our project. After a few minutes, our project will be ready and we can open the Maven window to see the different lifecycle phases and Maven plugins and their goals. We covered how to use Spring Initializr, Maven, and IntelliJ IDEA in Chapter 2, Getting Started with Spring Boot 2.0. You can check out this chapter to learn about topics not covered in this section. Now, we will add RestController to our project, in IntelliJ IDEA, in the Project window. Right-click our com.Microservices.chapter08 package and then choose New | Kotlin File/Class. In the pop-up window, we will set its name as HelloController and in the Kind drop-down, choose Class. Let's modify our newly created controller: package com.microservices.chapter08 import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RestController import java.util.* import java.util.concurrent.atomic.AtomicInteger @RestController class HelloController { private val id: String = UUID.randomUUID().toString() companion object { val total: AtomicInteger = AtomicInteger() } @GetMapping("/hello") fun hello() = "Hello I'm $id and I have been called ${total.incrementAndGet()} time(s)" } This small controller will display a message with a GET request to the /hello URL. The message will display a unique id that we establish when the object is created and it will show how many times it has been called. We have used AtomicInteger to guarantee that no other requests are modified on our number concurrently. Finally, we will rename application.properties in the resources folder, using Shift + F6 to get application.yml, and edit it: logging.level.org.springframework.web: DEBUG We will establish that we have the log in the debug level for the Sprint Web Framework, so for the latter, we could view the information that will be needed in our logs. Now, we can run our microservice, either using IntelliJ IDEA Maven Project window with the springboot:run target, or by executing it on the command line: mvnw spring-boot:run Either way, when we visit the http://localhost:8080/hello URL, we should see something like: Hello I'm a0193477-b9dd-4a50-85cc-9d9405e02299 and I have been called 1 time(s) Doing consecutive calls will increase the number. Finally, we can see at the end of our log that we have several requests. The following should appear: Hello I'm a0193477-b9dd-4a50-85cc-9d9405e02299 and I have been called 1 time(s) Now, we will stop the microservice to create our Docker. Creating our Docker Now that our microservice is running, we need to create a Docker. To simplify the process, we will just use Dockerfile. To create this file on the top of the Project window, rightclick chapter08 and then select New | File and type Dockerfile in the drop-down menu. In the next window, click OK and the file will be created. Now, we can add this to our Dockerfile: FROM openjdk:8-jdk-alpine ADD target/*.jar app.jar ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar", "App.jar"] In this case, we tell the JVM to use dev/urandom instead of dev/random to generate random numbers required by our ID generation and this will make the operation much faster. You may think that urandom is less secure than random, but read this article for more information: https:/​/www.​2uo.​de/​myths-​about-​urandom/​.​ From our microservice directory, we will use the command line to create our package: mvnw package Then, we will create a Docker for it: docker build . -t hello Now, we need to tag our image in our shared registry service, using the following command: docker tag hello localhost:5000/hello Then, we will push our image to the shared registry service: docker push localhost:5000/hello Creating the service Finally, we will add the microservice as a service to our swarm, exposing the 8080 port: docker service create --name hello-service --publish 8080:8080 localhost:5000/hello Now, we can navigate to http://localhost:8888/application/default to get the same results as before, but now we run our microservice in a Docker swarm. If you found this tutorial useful, do check out the book Hands-On Microservices with Kotlin  to work with Kotlin, Spring and Spring Boot for building reactive and cloud-native microservices. Also check out other posts: How to publish Docker and integrate with Maven Understanding Microservices How to build Microservices using REST framework
Read more
  • 0
  • 0
  • 3535