<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Kelly Andrews</title>
    <description>The latest articles on DEV Community by Kelly Andrews (@kellyjandrews).</description>
    <link>https://dev.to/kellyjandrews</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F844%2Ff0fb5051-982b-4af3-a475-724e899b58e7.jpg</url>
      <title>DEV Community: Kelly Andrews</title>
      <link>https://dev.to/kellyjandrews</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kellyjandrews"/>
    <language>en</language>
    <item>
      <title>Navigating the World of Developer Relations</title>
      <dc:creator>Kelly Andrews</dc:creator>
      <pubDate>Thu, 19 Jan 2023 13:26:26 +0000</pubDate>
      <link>https://dev.to/kellyjandrews/navigating-the-world-of-developer-relations-13fj</link>
      <guid>https://dev.to/kellyjandrews/navigating-the-world-of-developer-relations-13fj</guid>
      <description>&lt;p&gt;Welcome to the world of developer relations! As a developer relations professional, you play a critical role in building and maintaining relationships between a company and its developer community. Whether you're working for a startup or a large enterprise, the importance of developer relations in the tech industry cannot be overstated.&lt;/p&gt;

&lt;p&gt;From technical evangelism to community management, developer relations professionals wear many hats. They act as the voice of the developer community inside the company, providing valuable feedback and insights to help shape product development. They also serve as the company's voice in the developer community, sharing updates, resources, and best practices.&lt;/p&gt;

&lt;p&gt;So, whether you're just starting in developer relations or a seasoned pro, this post will give you a better understanding of the field and help you navigate the many roles and responsibilities of a developer relations professional. Let's dive in!&lt;/p&gt;

&lt;h2&gt;
  
  
  Skills
&lt;/h2&gt;

&lt;p&gt;When it comes to excelling in developer relations, there are a few essential and critical skills. The first is strong communication skills. As a developer relations professional, you will interact with developers from all backgrounds, colleagues, and stakeholders from other teams. Communicating effectively verbally and in writing is crucial to building trust and establishing solid relationships.&lt;/p&gt;

&lt;p&gt;Another essential skill is technical acumen. While you don't need to be a software developer yourself (although it does help a bit), having a solid understanding of the technical side of things is critical to understand developers' needs and concerns and effectively advocating for them within the company. This can be achieved through experience working in a technical role or ongoing learning and education.&lt;/p&gt;

&lt;p&gt;In addition to these skills, building relationships and advocating for developers are also vital. Developer relations foster a sense of community and connection between a company and its developer base. Building relationships with developers, understanding their needs and concerns, and advocating for them within the company are critical to the success of a developer relations professional.&lt;/p&gt;

&lt;p&gt;Finally, empathizing with developers and understanding their perspectives is crucial to building trust and establishing effective relationships. This skill is often developed through experience and continuous learning of the developer ecosystem and its trends.&lt;/p&gt;

&lt;h2&gt;
  
  
  Roles
&lt;/h2&gt;

&lt;p&gt;The role of a developer relations professional can vary depending on the company and the specific needs of the developer community. However, a few key responsibilities are shared across the field.&lt;/p&gt;

&lt;p&gt;One of the primary roles of a developer relations professional is to act as the voice of the developer community within the company. This means gathering feedback and insights from developers and then sharing that information with other teams, such as product development, marketing, and customer support. This helps ensure that the needs and concerns of the developer community are taken into account when making decisions about products and services.&lt;/p&gt;

&lt;p&gt;Another critical responsibility of a developer relations professional is to act as the company's voice within the developer community. This means sharing updates and resources with developers, answering questions, and addressing concerns. This helps build trust and strong relationships with the developer community, which can lead to increased adoption of products and services.&lt;/p&gt;

&lt;p&gt;A developer relations professional also often plays a crucial role in community management. This includes organizing and hosting events, such as meetups and hackathons, and creating and maintaining online communities, such as forums and social media groups. Community management helps to foster a sense of community and connection among developers and can also be a great way to gather feedback and insights.&lt;/p&gt;

&lt;p&gt;Finally, a developer relations professional also serves as the company's technical evangelist. This means promoting and showcasing the company's products and services to developers and providing technical support and resources. Technical evangelism helps to increase awareness and adoption of the company's products and services among the developer community.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advice
&lt;/h2&gt;

&lt;p&gt;Transitioning into a developer relations role can seem daunting, but it can be a rewarding and fulfilling career path with the right mindset and approach. Here are some tips and advice on how to make the transition.&lt;/p&gt;

&lt;p&gt;Networking is one of the most important things you can do when transitioning into a developer relations role. Attend conferences and meetups, join online communities and groups, and connect with other developer relations professionals. Not only will you learn from others in the field, but you'll also have the opportunity to make connections that can lead to job opportunities.&lt;/p&gt;

&lt;p&gt;Gaining relevant experience is also crucial when making the transition. Participating in open-source projects, working in a technical role, or volunteering at developer events can help to build your skills and knowledge. It also allows you to showcase your experience and skills to potential employers.&lt;/p&gt;

&lt;p&gt;Building a personal brand can also be beneficial when making the transition. Creating a portfolio of your work, writing blog posts or articles, and sharing your knowledge and experience on social media help establish you as a thought leader. This can attract potential employers and showcase your skills and experience.&lt;/p&gt;

&lt;p&gt;It's also important to stay current with the latest trends and best practices in the field and to continuously learn and grow your skills. Reading industry publications, following influential people in the area, and taking online courses are great ways to stay up-to-date and continue developing your skills.&lt;/p&gt;

&lt;p&gt;Finally, don't be afraid to take risks and try new things. Developer relations is a field that is constantly evolving, and those who are willing to adapt and try new things are often the most successful. Keep an open mind, be ready to learn and grow, and don't hesitate to step out of your comfort zone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In conclusion, developer relations is a dynamic and critical field in the tech industry. It is vital in building and maintaining relationships between a company and its developer community. It is essential for the success of any organization that creates and distributes technology.&lt;/p&gt;

&lt;p&gt;By understanding a developer relations professional's various roles and responsibilities and the critical skills needed to excel in this field, you can transition into a developer relations role and help bridge the gap between companies and the developer community. We hope this post has provided you with valuable insights and resources to help you pursue a career in developer relations and make an impact in the tech industry.&lt;/p&gt;

&lt;p&gt;Remember to stay current with the latest trends and best practices in the field, continuously learn and grow your skills, and don't be afraid to take risks and try new things. Keep building connections and relationships, and always be open to new opportunities to improve your developer relations skills.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>My Attempt To Answer How I Lost Weight</title>
      <dc:creator>Kelly Andrews</dc:creator>
      <pubDate>Thu, 12 Jan 2023 14:28:56 +0000</pubDate>
      <link>https://dev.to/kellyjandrews/my-attempt-to-answer-how-i-lost-weight-25b9</link>
      <guid>https://dev.to/kellyjandrews/my-attempt-to-answer-how-i-lost-weight-25b9</guid>
      <description>&lt;p&gt;Over the last several months, I've been able to reconnect with people again after a couple of years. After their initial shock and surprise that they know who I am, they ask me: "how did you do it?"&lt;/p&gt;

&lt;p&gt;I honestly don't know how to answer the question because, even to me, it still is a mystery. This post will collect my thoughts and hopefully provide some answers to those curious.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Who
&lt;/h2&gt;

&lt;p&gt;I remember during my senior year of high school when I realized I had put on so much weight that my clothes no longer fit me, and I needed to buy larger sizes. What I didn't know at that time was that it would be a 25-year battle of self-image, self-loathing, and motivation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IoEmmByj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1673532682304/66604125-2b8a-4f32-a7d6-3a859484f895.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IoEmmByj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1673532682304/66604125-2b8a-4f32-a7d6-3a859484f895.jpeg" alt="" width="552" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Over that time, I've tried just about &lt;em&gt;everything&lt;/em&gt; to lose weight: Atkins, South Beach, Juice cleanses, Weight Watchers, Mediterranean, Cabbage, Paleo, Keto, Low Carb, Body For Life, Low Sugar, Calorie counting, Weight lifting, Cardio, Aerobics, Running, etc.&lt;/p&gt;

&lt;p&gt;Sometimes I took those efforts seriously, getting down to 280 pounds twice. 280 does not seem like a good number for a 5'11" male who is supposed to weigh under 190 lbs, but when you previously clocked in at 400 lbs or more, it feels incredible. However, I would always gain the weight back.&lt;/p&gt;

&lt;p&gt;I learned that diets are not sustainable and surgery doesn't work for everyone. More importantly, I started to understand that programs are designed to make you temporarily lose weight, are unsustainable, or worse for your health than you think.&lt;/p&gt;

&lt;p&gt;You would think that being diagnosed with Type 2 Diabetes would have pushed me to get things under control, but I had convinced myself that no matter what I weighed, I was healthy or that even thin people get sick. I became an expert at evading my efforts.&lt;/p&gt;

&lt;p&gt;Anything can be okay in moderation, but not when dieting is so far off course that even moderation is excess. I would eat plateful after plateful, never feeling full or satisfied. I would wake up hungry, despite eating 2500 calories for dinner the night before. I was sick but had convinced myself that I was healthy and that my body was naturally heavy and needed the extra weight.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Why
&lt;/h2&gt;

&lt;p&gt;Before I get to how I lost weight, I want to talk about my love of amusement parks and roller coasters. Around 13, our school went on a field trip to Cedar Point. It wasn't my first time at an amusement park, but this time I finally talked myself into riding a coaster with loops, and after that, I was hooked. Every summer, I would get to a park and ride as many roller coasters as I could. The atmosphere, the heat, the lines, all of it, I loved it.&lt;/p&gt;

&lt;p&gt;However, most rides don't cater to larger bodies. I recall countless times feeling dejected after waiting in line for a ride I couldn't fit in. I had to watch my kids enjoy riding coasters from the sidelines. Ultimately, this reality sinking in and watching my wife lose weight the year before finally pushed me towards action.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TkzIW7PO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1673533596664/ac103f6b-f0de-4e43-aa43-36ce3a170f88.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TkzIW7PO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1673533596664/ac103f6b-f0de-4e43-aa43-36ce3a170f88.jpeg" alt="" width="880" height="660"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The How
&lt;/h2&gt;

&lt;p&gt;Most people wish this were where I could say, "I did X," and that was it - end of the post. Typically, my answer to those who ask is, "I ate less." This answer never feels good enough or can even be condescending and rude. So let me try and explain what that means exactly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Eat Less
&lt;/h3&gt;

&lt;p&gt;I used to love eating at Wendy's. I would order a double (mayo and cheese only), large fries, and a large diet drink (saving calories, of course). Besides the two days' worth of caloric intake in a sitting, the number of addictive chemicals in that meal made me only want it more.&lt;/p&gt;

&lt;p&gt;The most important lesson was how addictive food could be. I used to think ice cream and pizza were "bad foods" or salads and veggies were "good." Both things are the same - food. The ingredients make all the difference.&lt;/p&gt;

&lt;p&gt;Two brands of peanut butter, with 200 calories/serving, can have completely different ingredients, depending on the amount of sugar and oils added. Removing processed foods from my diet didn't all happen at once. I backed down slowly. I think this is critical - &lt;strong&gt;&lt;em&gt;quitting anything this addictive without stepping down is dangerous&lt;/em&gt;&lt;/strong&gt; and fruitless. It tends to lead to severe levels of bounce back.&lt;/p&gt;

&lt;p&gt;A triple became a single, and fries became small. I could get the taste without as many calories. Over time, I wanted it less and less. The foods many of us eat, especially diet foods, contain so much stuff that our bodies don't know what to do with them.&lt;/p&gt;

&lt;p&gt;The more I eliminated fast foods - frozen meals, dining out, prepackaged foods - the more I lost. Do I still eat junk? Yep. Just so much less often and on a significantly lower amount.&lt;/p&gt;

&lt;h3&gt;
  
  
  Eat Less Often
&lt;/h3&gt;

&lt;p&gt;I found myself eating around the same time every day, regardless. The first habit I had to break was eating on a schedule, not when I was hungry. This behavior would lead me to eat 4000+ calories daily without thinking. I honestly didn't even know what hunger was anymore.&lt;/p&gt;

&lt;p&gt;Searching for what hunger felt like took some time, but I'm not sure how long. It took paying close attention to my body and waiting to eat only when I truly felt hungry. Asking the simple question, "am I hungry" I typically answer no.&lt;/p&gt;

&lt;p&gt;Eventually, I could turn this new understanding into a more rigorous fasting approach. I am now able to fast and control intake without the initial struggles.&lt;/p&gt;

&lt;h3&gt;
  
  
  Measuring Success
&lt;/h3&gt;

&lt;p&gt;My initial measurement of success was stepping on a scale 2-3 times a day. Any loss was a win and felt great. Setting weight goals helped - my first was to get under 300 lbs. After that, I used 20-pound increments to not overwhelm myself with taking on too big of a goal.&lt;/p&gt;

&lt;p&gt;Recording my weight was a big eye-opener. There was a pattern of loss/gain that I had never noticed before seeing the pattern and associating that with how I was eating and feeling at the time helped my brain comprehend what was happening. It was something I could repeat now, with consistent results.&lt;/p&gt;

&lt;p&gt;I also used roller coasters at a nearby theme park that year as a measurement - starting the season only fitting on a few to ending the year by riding them all. Clothing sizes also became a gauge. Going from 3XL to L and a 56" waist to 36" was a clear indicator that things were working.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cyMeWbcv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1673533475894/2c2e47c8-9cd1-43ae-936d-fea7e53afcf4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cyMeWbcv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1673533475894/2c2e47c8-9cd1-43ae-936d-fea7e53afcf4.png" alt="" width="880" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;While it may seem like a brush-off type of answer, "I eat less food" is the only way I can sum up a year of retraining my mind and body to understand how to feed itself again. The problem with asking me how is I am still in disbelief myself and do not believe I have any level of expertise that will ultimately help.&lt;/p&gt;

&lt;p&gt;What I can say is - you will have a different journey. You will find the patterns, habits, and foods that work best for you. If I have learned anything, it is this - no one else will do the work for you. No diet, book, video, class, or anything else will change you. It was not easy, but the extra time I may have with my family makes it worth it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XKMiVDPQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1673533562478/b9c80fa8-2bbb-45f6-875a-4f9b49ead028.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XKMiVDPQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1673533562478/b9c80fa8-2bbb-45f6-875a-4f9b49ead028.jpeg" alt="" width="880" height="565"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>From Magic Shows to Marching Bands: A Busy 2022</title>
      <dc:creator>Kelly Andrews</dc:creator>
      <pubDate>Thu, 05 Jan 2023 14:33:38 +0000</pubDate>
      <link>https://dev.to/kellyjandrews/from-magic-shows-to-marching-bands-a-busy-2022-4j5j</link>
      <guid>https://dev.to/kellyjandrews/from-magic-shows-to-marching-bands-a-busy-2022-4j5j</guid>
      <description>&lt;p&gt;Hey there! It's hard to believe that it's already 2023. It seems like just yesterday we were ringing in 2022, and now here we are at the start of a new year.&lt;/p&gt;

&lt;p&gt;Looking back on last year, there's no denying it was great. In April, I joined Zoom. I love being a part of such a fantastic team. I also had the opportunity to watch my son learn the vibraphone and play with the high school marching band, which was a fantastic experience. The family even took a trip to Universal Studios, which was so much fun.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ifcio9ib4s82bmpw5i3.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ifcio9ib4s82bmpw5i3.jpeg" width="800" height="602"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But perhaps the year's highlight was my first professional magic performance. I've always been interested in magic and have been practicing for years, but finally, being able to perform for a paying audience was a dream come true. It was a little nerve-wracking at first, but the reactions I got from the crowd made it all worth it.&lt;/p&gt;

&lt;p&gt;In addition to that, I was fortunate enough to be invited to speak at two conferences last year. It was an excellent opportunity to share my knowledge and experiences with others, and I hope to have the chance to do more of that in the future.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4c5laotewsnqy8hkybin.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4c5laotewsnqy8hkybin.jpeg" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As great as 2022 was, though, it went by fast, and now we are at the start of 2023. But I'm excited about all that this year has in store.&lt;/p&gt;

&lt;p&gt;At Zoom, we've got some inspiring initiatives that will significantly impact developers' lives. I'm also working on a small project that has the potential to turn into something huge in the long term.&lt;/p&gt;

&lt;p&gt;And on a personal level, my wife and I are planning a trip to Vegas, which we've wanted to do for a long time, and then later in the year to see Metallica. Who knows what other adventures and opportunities the year will bring?&lt;/p&gt;

&lt;p&gt;One thing I'm committed to this year is producing more content. I've always enjoyed blogging and streaming, and I look forward to doing more in 2023. I'm also hoping to have the chance to give more talks and possibly even host some workshops.&lt;/p&gt;

&lt;p&gt;Overall, I'm feeling pretty optimistic about the year ahead. Here's to an incredible 2023!&lt;/p&gt;

</description>
      <category>gratitude</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Reflecting on my time at Vonage</title>
      <dc:creator>Kelly Andrews</dc:creator>
      <pubDate>Fri, 01 Apr 2022 16:09:29 +0000</pubDate>
      <link>https://dev.to/kellyjandrews/reflecting-on-my-time-at-vonage-1b8j</link>
      <guid>https://dev.to/kellyjandrews/reflecting-on-my-time-at-vonage-1b8j</guid>
      <description>&lt;p&gt;It's my last day at Vonage today - no joke. While hard to completely grasp everything that's happened over the last couple of years, I wanted to try and take a moment and sum up everything since starting in August 2018.&lt;/p&gt;

&lt;h2&gt;
  
  
  Firebase
&lt;/h2&gt;

&lt;p&gt;One of the more forward-looking platforms used during my tenure was Firebase. I was able to spend a ton of time here learning how to use as much of the functionality that Firebase had to offer. Whether it was &lt;a href="https://kellyjandrews.hashnode.dev/real-time-sms-demo-with-react-node-and-google-translate" rel="noopener noreferrer"&gt;SMS translation&lt;/a&gt;, or &lt;a href="https://kellyjandrews.hashnode.dev/adding-2fa-to-a-react-app-using-firebase-function" rel="noopener noreferrer"&gt;adding two-factor authentication&lt;/a&gt;, the tool kit that Firebase gives you is extremely powerful, and always a consideration when I create new projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sentiment Analysis
&lt;/h2&gt;

&lt;p&gt;While easy to implement, Sentiment analysis is hard to get right and is far from perfect. However, as a general guide for intervention, it can do a good job of finding customers that may be more upset and can make that actionable. For call centers, it's a great tool.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.vonage.com/blog/19/10/17/sentiment-api-analysis-comparison-dr" rel="noopener noreferrer"&gt;Read my comparison - although it's a bit dusty now&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Chatbots
&lt;/h2&gt;

&lt;p&gt;Chatbots can be super fun, or really frustrating. While they can provide easy solutions to simple problems, covering all cases can be tricky, and it's easy to miss flows. Couple that with also trying to use speech transcription to match nouns and verbs programmatically, and now it's a disaster.&lt;/p&gt;

&lt;p&gt;With the right amount of effort and planning, however, they can be extremely powerful and handle quite a lot of typical use cases. You can always push the call to a human when the script isn't working as a last resort.&lt;/p&gt;

&lt;p&gt;You can read the tutorial for that &lt;a href="https://kellyjandrews.hashnode.dev/using-dialogflow-with-firebase-and-the-vonage-messages-sandbox" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Transcription
&lt;/h2&gt;

&lt;p&gt;I feel like transcription is really well solved in most cases. Listening to audio and transcribing it word for word is the main function of these APIs, and they all do it efficiently and accurately. Don't be afraid to use them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.vonage.com/blog/19/09/10/extending-nexmo-streaming-transcription-dr" rel="noopener noreferrer"&gt;Read another outdated comparison&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Translation
&lt;/h2&gt;

&lt;p&gt;Translation, much like transcription, has been fairly well solved. Every translation API has some kind of lexicon customization to cover industry-specific terms and can cost a lot more than the base service, however, the basic level of translation is really good in general. I plan on using these more in the future as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.vonage.com/blog/19/12/10/text-translation-api-comparison-dr" rel="noopener noreferrer"&gt;One more ancient review&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  XState
&lt;/h2&gt;

&lt;p&gt;One of my favorite tools in JavaScript these days is XState. The ability to define how an application should work as a state machine, and use that in any front or back end to control the flow of states - &lt;em&gt;chef's kiss&lt;/em&gt;. I found it extremely useful with things like video, as I could create states that matched exactly what was happening with the SDK and API.&lt;/p&gt;

&lt;p&gt;It's really a lot of fun to use - I recommend you &lt;a href="https://kellyjandrews.hashnode.dev/learn-and-apply-xstate-with-vonage-video" rel="noopener noreferrer"&gt;try it out&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Oclif and CLI Design
&lt;/h2&gt;

&lt;p&gt;I built the Vonage CLI using Oclif, and I've really learned to love using oclif, CLI best practices, CLI history, and the command line itself.&lt;/p&gt;

&lt;p&gt;Building a CLI isn't always the easiest thing to do, as it can run in so many environments, but solving these types of problems are fun for me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lerna/Monrepo
&lt;/h2&gt;

&lt;p&gt;While building the CLI and an updated SDK, I decided to work in a monorepo structure, using Lerna to manage the publication of the modules. I plan on writing more on how that is used in the future as well. It's a great resource, easy to understand, but hard to get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Typescript (sorta)
&lt;/h2&gt;

&lt;p&gt;Last, and well, least, Typescript. I have an appreciation for types now, and while I still feel like I have a long way to go, learning Typescript has been rewarding, if not frustrating. This was one of the harder things to learn for me, but I really am better off for doing it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Overall - it was a great learning experience. Being able to learn new things as a developer advocate is one of my favorite aspects of the job.&lt;/p&gt;

&lt;p&gt;I'm thankful for the opportunities I've had here, and look forward to the future.&lt;/p&gt;

</description>
      <category>writing</category>
      <category>productivity</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Learn and Apply XState with Vonage Video</title>
      <dc:creator>Kelly Andrews</dc:creator>
      <pubDate>Wed, 01 Jul 2020 13:55:12 +0000</pubDate>
      <link>https://dev.to/vonagedev/learn-and-apply-xstate-with-vonage-video-5dfg</link>
      <guid>https://dev.to/vonagedev/learn-and-apply-xstate-with-vonage-video-5dfg</guid>
      <description>&lt;p&gt;Over the last few months, I have heard more about &lt;a href="https://en.wikipedia.org/wiki/Finite-state_machine" rel="noopener noreferrer"&gt;state machines&lt;/a&gt; used for front-end development. The idea of a state machine is that it has only a finite number of states and can only be in one state at any given time. Conceptually this makes perfect sense for app development – there are only a certain number of states available.&lt;/p&gt;

&lt;p&gt;The concept of state machines and statecharts is not new, and it isn’t rooted in front-end development, either. It’s a mathematical model, and one used in many things around us. As an example, a light can be &lt;code&gt;OFF&lt;/code&gt; or &lt;code&gt;ON&lt;/code&gt;. You can describe anything with a state machine, even though this is a simple example.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2020%2F06%2Flightbulb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2020%2F06%2Flightbulb.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to XState
&lt;/h2&gt;

&lt;p&gt;Using a state machine in front-end development has become much less complicated with the creation of the package &lt;a href="https://xstate.js.org/docs/" rel="noopener noreferrer"&gt;XState&lt;/a&gt;. XState helps us define state machines, create events and effects, and control the entire application flow. XState uses JavaScript methods and objects to describe the state machine.&lt;/p&gt;

&lt;p&gt;The light bulb example from above would be written out like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lightBulb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Machine&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lightBulb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;initial&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;off&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;states&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;off&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;TURN_ON&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;on&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;TURN_OFF&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;off&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The state machine defined here shows the two states for the light bulb, &lt;code&gt;OFF&lt;/code&gt; and &lt;code&gt;ON&lt;/code&gt;, and the transitions from the events &lt;code&gt;TURN_ON&lt;/code&gt; and &lt;code&gt;TURN_OFF&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The object itself isn’t very complex to read, but as the state machine grows in complexity, it can be harder to understand. XState has create a tool to help out with this – the &lt;a href="https://xstate.js.org/viz/" rel="noopener noreferrer"&gt;XState visualizer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://xstate.js.org/viz/?gist=a8a33932a88951692a8c94de647db40b" rel="noopener noreferrer"&gt;https://xstate.js.org/viz/?gist=a8a33932a88951692a8c94de647db40b&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using the XState visualizer helps to see how the state machines work and are interactive, so playing with them is fun. If you want to check out the code for the machine, you can also click the code button to take a peek.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a Vonage Video State Chart
&lt;/h2&gt;

&lt;p&gt;When I set out to learn state machines, and XState, my overall goal was to build an application similar to Google Meet using &lt;a href="https://tokbox.com/developer/" rel="noopener noreferrer"&gt;Vonage Video&lt;/a&gt;. The app would allow a user to create a meeting room, share the URL, and have a meeting with multiple streams. To get to that point, I had to learn some of the various concepts for state charts and how to represent those in XState.&lt;/p&gt;

&lt;p&gt;Thinking through the possible application states is not an easy task, I found. There are many possibilities to explore, and ultimately finding the right solution takes some trial and error.&lt;/p&gt;

&lt;p&gt;The rest of this article will cover some basic concepts and build a state chart visualization that will mimic the eventual state machine. I will also provide some additional links and resources throughout so you can explore on your own.&lt;/p&gt;

&lt;h2&gt;
  
  
  States and State Nodes
&lt;/h2&gt;

&lt;p&gt;A &lt;a href="https://xstate.js.org/docs/guides/states.html" rel="noopener noreferrer"&gt;state&lt;/a&gt; is a representation of a machine at any given time. This moment can be defined and then made into a &lt;a href="https://xstate.js.org/docs/guides/statenodes.html" rel="noopener noreferrer"&gt;state node&lt;/a&gt; in XState, captured as a configuration.&lt;/p&gt;

&lt;p&gt;In my Vonage Video app, there are a couple of different possible solutions to this, but I’ve found that describing the states in as simple of terms as possible is the best way to get to a useful result.&lt;/p&gt;

&lt;p&gt;Creating a &lt;a href="https://xstate.js.org/docs/guides/machines.html" rel="noopener noreferrer"&gt;machine&lt;/a&gt; uses the following pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;machine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Machine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state_nodes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With a video state machine in mind, there are two compound states – &lt;code&gt;connected&lt;/code&gt; and &lt;code&gt;disconnected&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://xstate.js.org/viz/?gist=2d260c1f9c7b51ed47c4cf7bbc61b4df" rel="noopener noreferrer"&gt;https://xstate.js.org/viz/?gist=2d260c1f9c7b51ed47c4cf7bbc61b4df&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two state nodes may seem overly simplified, but there are only two states after some trial and error. Each of these states, however, are more complex than an atomic (no children) node. Instead of creating every possible state at the top level, XState helps us organize with hierarchical and parallel state nodes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hierarchical State Nodes
&lt;/h3&gt;

&lt;p&gt;XState provides the option to create nested states called &lt;a href="https://xstate.js.org/docs/guides/hierarchical.html" rel="noopener noreferrer"&gt;&lt;code&gt;hierarchical&lt;/code&gt; state nodes&lt;/a&gt;. When we first start the machine, we can set it to &lt;code&gt;idle&lt;/code&gt; first, as the machine will be ready but doing nothing. Why not just make another top-level atomic state node?&lt;/p&gt;

&lt;p&gt;Adding states to the top level is called “state explosion” and is a typical side-effect of finite state machines. Since Vonage Video is still technically &lt;code&gt;disconnected&lt;/code&gt;, nesting &lt;code&gt;idle&lt;/code&gt; makes sense as the video is both disconnected and idle. Another &lt;code&gt;disconnected&lt;/code&gt; substate should be &lt;code&gt;ready&lt;/code&gt;. The &lt;code&gt;disconnected.ready&lt;/code&gt; state would happen just before moving to the &lt;code&gt;connected&lt;/code&gt; state. The state machine also has a state node in-between &lt;code&gt;idle&lt;/code&gt; and &lt;code&gt;ready&lt;/code&gt; to get everything set up. This middle state can be called the &lt;code&gt;init&lt;/code&gt; phase.&lt;/p&gt;

&lt;p&gt;The state machine now would look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://xstate.js.org/viz/?gist=da00b68575ceb12f88b1ad7ad0219020" rel="noopener noreferrer"&gt;https://xstate.js.org/viz/?gist=da00b68575ceb12f88b1ad7ad0219020&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should notice that we don’t currently have a way to move in between the two nodes. We will cover events and actions in a moment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Parallel State Nodes
&lt;/h3&gt;

&lt;p&gt;A &lt;a href="https://xstate.js.org/docs/guides/parallel.html" rel="noopener noreferrer"&gt;&lt;code&gt;parallel&lt;/code&gt; state node&lt;/a&gt; allows the application to be in all of its substates at the same time. The Vonage Video state machine is highly event-driven, so we need to manage multiple states at once.&lt;/p&gt;

&lt;p&gt;To specify that a state node is parallel, we use &lt;code&gt;type:parallel&lt;/code&gt; in the configuration. After the transition to &lt;code&gt;connected&lt;/code&gt;, three parallel states will occur – &lt;code&gt;session&lt;/code&gt;, &lt;code&gt;publisher&lt;/code&gt;, and &lt;code&gt;subscribers&lt;/code&gt;. Each of these states will set up events and event listeners to control the Vonage Video service’s responses.&lt;/p&gt;

&lt;p&gt;The resulting visualization looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://xstate.js.org/viz/?gist=bf9c3dd275206505c12bb0bb88df5d58" rel="noopener noreferrer"&gt;https://xstate.js.org/viz/?gist=bf9c3dd275206505c12bb0bb88df5d58&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With these primary states, we can control what our application shows at particular times. Currently, however, we are unable to move between states. Let’s have a look at events and transitions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Events and Transitions
&lt;/h2&gt;

&lt;p&gt;Since a state node is just the configuration of an individual state, their inherently is not a way to move from state to state without declaring that in the state node.&lt;/p&gt;

&lt;p&gt;Each node listens for a sent &lt;a href="https://xstate.js.org/docs/guides/events.html" rel="noopener noreferrer"&gt;event&lt;/a&gt; to &lt;a href="https://xstate.js.org/docs/guides/transitions.html" rel="noopener noreferrer"&gt;transition&lt;/a&gt; to the next state. In the light bulb example, the &lt;code&gt;TURN_ON&lt;/code&gt; event sent tells the machine to transition to &lt;code&gt;on&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Transitions only occur between top-level nodes and within hierarchical nodes. Parallel nodes are not allowed to transition between each other. For our Vonage Video app, this means the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When the page is ready, we can send a &lt;code&gt;START&lt;/code&gt; event. This event will transition the state to &lt;code&gt;disconnected.init&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;disconnected.init&lt;/code&gt; state will transition out once the &lt;code&gt;VIDEO_ELEMENT_CREATED&lt;/code&gt; event has fired.&lt;/li&gt;
&lt;li&gt;Once we reach &lt;code&gt;disconnected.ready&lt;/code&gt;, we can allow the user to connect, sending the &lt;code&gt;CONNECT&lt;/code&gt; event, and transition to &lt;code&gt;connected&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If the application passed the &lt;code&gt;DISCONNECT&lt;/code&gt; event, the state machine would disconnect.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://xstate.js.org/viz/?gist=53c4772dc742ce1b84c40e3fa6669c6e" rel="noopener noreferrer"&gt;https://xstate.js.org/viz/?gist=53c4772dc742ce1b84c40e3fa6669c6e&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Declaring an event and transition in XState uses the following pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;EVENT_DESCRIPTOR&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nextState&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can add specific actions to the transition as well. I would recommend you read the sections on &lt;a href="https://xstate.js.org/docs/guides/transitions.html#internal-transitions" rel="noopener noreferrer"&gt;internal and external transitions&lt;/a&gt; in the documentation. They cover in great detail the various types of transitions possible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Guarded Transitions
&lt;/h3&gt;

&lt;p&gt;You may have noticed that one of the transitions has a &lt;code&gt;cond&lt;/code&gt; node in the transition. This conditional is what’s called a &lt;a href="https://xstate.js.org/docs/guides/guards.html#guards-condition-functions" rel="noopener noreferrer"&gt;&lt;code&gt;guarded&lt;/code&gt; transition&lt;/a&gt;. Guarded transitions help protect the machine from moving to a state that is not allowed based on certain conditions. In this case, I don’t want to transition to &lt;code&gt;ready&lt;/code&gt; until the token and video element are both created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;VIDEO_ELEMENT_CREATED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ready&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;cond&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;checkToken&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The guard condition &lt;code&gt;checkToken&lt;/code&gt; is a named reference to the guards object in the options paramater sent to machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;video&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Machine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;state_nodes&lt;/span&gt;&lt;span class="p"&gt;,{&lt;/span&gt;
  &lt;span class="na"&gt;guards&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;checkToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;In order to be more useful to an application, our state machine will need a longer living state, called an &lt;a href="https://xstate.js.org/docs/guides/context.html#initial-context" rel="noopener noreferrer"&gt;&lt;code&gt;extended state&lt;/code&gt;, or &lt;code&gt;context&lt;/code&gt;&lt;/a&gt;. The context object updates using various effects with the &lt;a href="https://xstate.js.org/docs/guides/context.html#assign-action" rel="noopener noreferrer"&gt;&lt;code&gt;assign()&lt;/code&gt; method&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Speaking of actions, let’s get to these now and finish out the rest of the skeleton.&lt;/p&gt;

&lt;h3&gt;
  
  
  Actions and Services
&lt;/h3&gt;

&lt;p&gt;There are what’s known as “side-effects” in state machines that XState puts into one of two categories:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;“Fire-and-forget” – where the effect doesn’t send events&lt;/li&gt;
&lt;li&gt;Invoked – where sending events are required&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Actions
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://xstate.js.org/docs/guides/actions.html" rel="noopener noreferrer"&gt;Actions&lt;/a&gt; are single effects and tend to be one of the more common effects in the video state machine. You can use actions when you enter or exit a node, or during a transition. Understanding the order of actions is incredibly important.&lt;/p&gt;

&lt;p&gt;An excellent resource for learning the action order (and all of the topics on XState) is a video published by &lt;a href="https://twitter.com/kyleshevlin" rel="noopener noreferrer"&gt;@kyleshvlin&lt;/a&gt; over at &lt;a href="https://egghead.io/lessons/xstate-how-action-order-affects-assigns-to-context-in-a-xstate-machine" rel="noopener noreferrer"&gt;Egghead.io&lt;/a&gt;. It helped me understand how actions fired.&lt;/p&gt;

&lt;p&gt;The bulk of the actions for this machine revolve around updating the context as a transition. When events are called, we can use the action to run the &lt;code&gt;assign()&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SOME_EVENT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;someContext&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;someValue&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Services
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://xstate.js.org/docs/guides/communication.html#the-invoke-property" rel="noopener noreferrer"&gt;Invoked Services&lt;/a&gt; are the other main effect in the video state machine. To use promises and event listeners, you need to invoke a service. This concept was, by far, the hardest for me to grasp. The main difficulty I had to work through was understanding that an invoked service stops when the state exits. If you transition too quickly, your promise or callback will disappear.&lt;/p&gt;

&lt;p&gt;There are two primary services that I’m using in the video state machine, promises, and callbacks. The &lt;a href="https://xstate.js.org/docs/guides/communication.html#invoking-promises" rel="noopener noreferrer"&gt;&lt;code&gt;invoke promises&lt;/code&gt; service&lt;/a&gt; allows the state machine to use a promise to either resolve or reject and then act accordingly. I used this to interact with the server asynchronously and then update the context when complete.&lt;/p&gt;

&lt;p&gt;The function signature of invoked promises looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rejected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Resolved&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="nx"&gt;onDone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/*success transition*/&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nl"&gt;onError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/*error transition*/&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second, and probably the most important part of this machine, is the &lt;a href="https://xstate.js.org/docs/guides/communication.html#invoking-callbacks" rel="noopener noreferrer"&gt;&lt;code&gt;invoked callbacks&lt;/code&gt;&lt;/a&gt;. The Vonage Video architecture relies heavily on events and event listeners. In a state machine, those are set up through a callback. Let me show you an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;initPublisher&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;publisher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;initPublisher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pubOptions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;publisher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;videoElementCreated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;VIDEO_ELEMENT_CREATED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;publisher&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;publisher&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;publisher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;off&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;videoElementCreated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function signature of an invoked callback looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onReceive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EVENT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;onReceive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;OTHER_EVENT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;cleanup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using actions and services, our Vonage Video state machine now looks like the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://xstate.js.org/viz/?gist=826cd253fd9eac80c2daa6bfa0924f50" rel="noopener noreferrer"&gt;https://xstate.js.org/viz/?gist=826cd253fd9eac80c2daa6bfa0924f50&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Don’t forget to click around, and click the &lt;code&gt;code&lt;/code&gt; tab to see what the state machine looks like as a configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources and Wrap-up
&lt;/h2&gt;

&lt;p&gt;Ok – so you’ve made it this far.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2020%2F06%2Fproudofyou.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2020%2F06%2Fproudofyou.gif" alt="'Ron Swanson saying I'm really proud of you." width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If this is your first time looking at XState, it’s a lot to take in all at once. I’m still exploring and learning new ways to do things. This post is just a small portion of what’s out there. As you are learning – here are a few great resources you will want to check out&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://egghead.io/courses/introduction-to-state-machines-using-xstate" rel="noopener noreferrer"&gt;Kyle Shevlin’s Intro to State Machines Using XState videos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://xstate.js.org/docs/guides/start.html" rel="noopener noreferrer"&gt;XState Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://flaviocopes.com/finite-state-machines/" rel="noopener noreferrer"&gt;Introduction to XState at flaviocopes.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.smashingmagazine.com/2018/01/rise-state-machines/" rel="noopener noreferrer"&gt;The Rist of State Machines – Smashing Magazine&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feel free to reach out if you have questions about XState, and we can learn something new together!&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://www.nexmo.com/blog/2020/07/01/learn-and-apply-xstate-with-vonage-video" rel="noopener noreferrer"&gt;Learn and Apply XState with Vonage Video&lt;/a&gt; appeared first on &lt;a href="https://www.nexmo.com" rel="noopener noreferrer"&gt;Vonage Developer Blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javasript</category>
      <category>statemachines</category>
      <category>xstate</category>
    </item>
    <item>
      <title>Using Dialogflow with Firebase and the Vonage Messages Sandbox</title>
      <dc:creator>Kelly Andrews</dc:creator>
      <pubDate>Mon, 01 Jun 2020 18:11:24 +0000</pubDate>
      <link>https://dev.to/vonagedev/using-dialogflow-with-firebase-and-the-vonage-messages-sandbox-1bfm</link>
      <guid>https://dev.to/vonagedev/using-dialogflow-with-firebase-and-the-vonage-messages-sandbox-1bfm</guid>
      <description>&lt;p&gt;Using &lt;a href="https://Dialogflow.com/" rel="noopener noreferrer"&gt;Dialogflow&lt;/a&gt; to build a chatbot to interact with your customer is a great way to handle incoming requests like reservations, bank inquiries, FAQs, and initial support. When you combine Dialogflow with &lt;a href="https://firebase.google.com/" rel="noopener noreferrer"&gt;Firebase&lt;/a&gt; and &lt;a href="https://developer.nexmo.com/messages/overview" rel="noopener noreferrer"&gt;Vonage Messages API&lt;/a&gt;, things start to heat up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;For this tutorial, you are connecting a Dialogflow agent with the Vonage Messages API using Firebase. When complete, you can send a message in Facebook Messenger to the Dialogflow agent and get a response based on the agent’s rules.&lt;/p&gt;

&lt;p&gt;You’ll want to make sure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://cloud.google.com/" rel="noopener noreferrer"&gt;Google Cloud Account&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://firebase.google.com/docs/cli" rel="noopener noreferrer"&gt;Firebase CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.nexmo.com/messages/concepts/messages-api-sandbox" rel="noopener noreferrer"&gt;Vonage Messages API Sandbox&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Vonage API Account
&lt;/h2&gt;

&lt;p&gt;To complete this tutorial, you will need a &lt;a href="http://developer.nexmo.com/ed?c=using-dialogflow-with-firebase-and-the-vonage-messages-sandbox-dr&amp;amp;ct=blog" rel="noopener noreferrer"&gt;Vonage API account&lt;/a&gt;. If you don’t have one already, you can &lt;a href="http://developer.nexmo.com/ed?c=using-dialogflow-with-firebase-and-the-vonage-messages-sandbox-dr&amp;amp;ct=blog" rel="noopener noreferrer"&gt;sign up today&lt;/a&gt; and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the &lt;a href="http://developer.nexmo.com/ed?c=using-dialogflow-with-firebase-and-the-vonage-messages-sandbox-dr&amp;amp;ct=blog" rel="noopener noreferrer"&gt;Vonage API Dashboard&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://developer.nexmo.com/ed?c=LAST%20PIECE%20OF%20URL&amp;amp;ct=blog_banner" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2020%2F05%2FStartBuilding_Footer.png" alt="Start building with Vonage" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a Firebase Application
&lt;/h2&gt;

&lt;p&gt;If this is your first time setting up a Firebase project, I would recommend you work through Google’s &lt;a href="https://firebase.google.com/docs/functions/get-started" rel="noopener noreferrer"&gt;Firebase getting started tutorial&lt;/a&gt; first to get yourself acclimated to the environment. If you are accustomed to Firebase or feeling adventurous, the first step is to create a new Firebase project. Feel free to name this anything memorable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.nexmo.com/wp-content/uploads/2020/05/firebase-project-setup.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2020%2F05%2Ffirebase-project-setup.png" alt="Create Firebase Project" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once through the initial creation process (less than 5 minutes), set up these two items in the dashboard of your project:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Upgrade to Blaze Pay-As-You-Go&lt;/strong&gt; You can locate this under Settings -&amp;gt; Usage and Billing -&amp;gt; Details &amp;amp; Settings -&amp;gt; Modify Plan. Firebase requires Blaze for any 3rd party integrations to work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pick a Resource Location&lt;/strong&gt; Find this in Settings -&amp;gt; Project Settings -&amp;gt; General&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once those are all set, you can set up the Dialogflow agent and associate it with the new Firebase/GCP project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set Up Dialogflow Agent
&lt;/h2&gt;

&lt;p&gt;Now you are ready to create a new Dialogflow agent—the chatbot that you will be interacting with later. Dialogflow uses Natural Language Processing to determine the user’s intents based on what they type or speak and return an action based on that intent.&lt;/p&gt;

&lt;p&gt;Next, import a “Prebuilt Agent” provided by Google to help get you started. If you are new to DialogFlow, you need to create a blank agent on the landing page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.nexmo.com/wp-content/uploads/2020/05/create-blank-dialogflow-agent.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2020%2F05%2Fcreate-blank-dialogflow-agent.png" alt="Create Blank Dialogflow Agent" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you have an agent, you can select the “Prebuilt Agents” from the left menu. You are presented with many different types of agents that might help you start learning how to build your chatbot. For this example, I picked “Easter Eggs.”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.nexmo.com/wp-content/uploads/2020/05/prebuilt-agents.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2020%2F05%2Fprebuilt-agents.png" alt="Prebuilt Agents" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Import an agent and wait for it to complete the build process. Once finished, get the credentials for the service account.&lt;/p&gt;

&lt;h3&gt;
  
  
  Download Service Account Keys
&lt;/h3&gt;

&lt;p&gt;Navigate to the GCP IAM &amp;amp; Admin service for &lt;a href="https://console.cloud.google.com/iam-admin/serviceaccounts" rel="noopener noreferrer"&gt;service accounts&lt;/a&gt;. Make sure you select the correct project that you have been using already.&lt;/p&gt;

&lt;p&gt;You should see a service account that looks similar to &lt;code&gt;dialogflow@myexampleproject.iam.gserviceaccount.com&lt;/code&gt;. Click the dots on the right and select &lt;code&gt;Create Key&lt;/code&gt; and then pick &lt;code&gt;JSON&lt;/code&gt; from the options. This process generates and downloads a &lt;code&gt;JSON&lt;/code&gt; file. Save this file for later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build Functions Locally
&lt;/h2&gt;

&lt;p&gt;You now have a Firebase project and a Dialogflow agent ready to go. The two systems need to communicate with each other and with Vonage APIs. To do that, you need a little code to make things work.&lt;/p&gt;

&lt;p&gt;The Firebase CLI has some helpful tools to get you started. Make sure you have the latest version and run the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;firebase init functions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command creates the project inside your root folder and asks you to connect it to an already existing project. After a few prompts, the command runs &lt;code&gt;npm install&lt;/code&gt; to install all of the requirements. Once complete, navigate to the functions folder and use this command to install the other packages you need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i @google-cloud/Dialogflow axios
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this time, you should also move the service account &lt;code&gt;JSON&lt;/code&gt; file over to the &lt;code&gt;functions&lt;/code&gt; directory. Once you’ve done that, make sure to add it to your &lt;code&gt;.gitignore&lt;/code&gt; file as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Code
&lt;/h3&gt;

&lt;p&gt;Inside the &lt;code&gt;functions&lt;/code&gt; directory is &lt;code&gt;index.js&lt;/code&gt;. They provide some sample code to get you started, but you can delete and replace it with the following code to send a message to the Vonage Messages Sandbox. Make sure to have your Vonage API key and secret handy for this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase-functions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// the service account JSON file downloaded earlier - make sure this is named properly&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;serviceAccount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./service_account.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Dialogflow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@google-cloud/Dialogflow&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// This method takes the TO_ID, FROM_ID, MSG from the webhook defined later&lt;/span&gt;
&lt;span class="c1"&gt;// DialogFlow responses will be sent using this function&lt;/span&gt;
&lt;span class="c1"&gt;// You will need to get your API Key and Secret from the Vonage Dashboard.&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TO_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FROM_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MSG&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://messages-sandbox.nexmo.com/v0.1/messages&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;from&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;messenger&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FROM_ID&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;to&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;messenger&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TO_ID&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MSG&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;API_KEY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;API_SECRET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next function is the gateway between Firebase and Dialogflow. The incoming message from Vonage is sent to the Dialogflow agent to determine the intent of the message. Once the intent is determined, Dialogflow passes back a message to forward on to the client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;DialogflowGateway&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sessionId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sessionClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Dialogflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SessionsClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;serviceAccount&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sessionPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sessionClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;projectAgentSessionPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR-GOOGLE-PROJECT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sessionId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;sessionPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;queryInput&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;languageCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en-US&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;sessionClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;detectIntent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Vonage Messages Sandbox uses an inbound webhook to receive the messages using a POST method to Firebase.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webhook&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// the message from the user is sent to Dialogflow, and a response is returned&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nc"&gt;DialogflowGateway&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// the response from Dialogflow is sent back to the user through Vonage&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;queryResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fulfillmentText&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These three functions should be inside the &lt;code&gt;index.js&lt;/code&gt; file and saved. All that is left is to deploy these functions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploy Functions
&lt;/h3&gt;

&lt;p&gt;Using the Firebase CLI, deploy the functions to Firebase using this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;firebase deploy --only functions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On successful deployment, you get the webhook required for the &lt;a href="https://dashboard.nexmo.com/messages/sandbox" rel="noopener noreferrer"&gt;Vonage Messages Sandbox &lt;code&gt;Inbound&lt;/code&gt; webhook&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="err"&gt;✔&lt;/span&gt;  &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Finished&lt;/span&gt; &lt;span class="nx"&gt;running&lt;/span&gt; &lt;span class="nx"&gt;predeploy&lt;/span&gt; &lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;i&lt;/span&gt;  &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ensuring&lt;/span&gt; &lt;span class="nx"&gt;required&lt;/span&gt; &lt;span class="nx"&gt;API&lt;/span&gt; &lt;span class="nx"&gt;cloudfunctions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;googleapis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;com&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="err"&gt;✔&lt;/span&gt;  &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;required&lt;/span&gt; &lt;span class="nx"&gt;API&lt;/span&gt; &lt;span class="nx"&gt;cloudfunctions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;googleapis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;com&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;enabled&lt;/span&gt;
&lt;span class="nx"&gt;i&lt;/span&gt;  &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;preparing&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt; &lt;span class="nx"&gt;directory&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;uploading&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="nx"&gt;i&lt;/span&gt;  &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;packaged&lt;/span&gt; &lt;span class="nf"&gt;functions &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;47.86&lt;/span&gt; &lt;span class="nx"&gt;KB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;uploading&lt;/span&gt;
&lt;span class="err"&gt;✔&lt;/span&gt;  &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt; &lt;span class="nx"&gt;folder&lt;/span&gt; &lt;span class="nx"&gt;uploaded&lt;/span&gt; &lt;span class="nx"&gt;successfully&lt;/span&gt;
&lt;span class="nx"&gt;i&lt;/span&gt;  &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;creating&lt;/span&gt; &lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;js&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;webhook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;us&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;central1&lt;/span&gt;&lt;span class="p"&gt;)...&lt;/span&gt;
&lt;span class="err"&gt;✔&lt;/span&gt;  &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;us&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;central1&lt;/span&gt;&lt;span class="p"&gt;)]:&lt;/span&gt; &lt;span class="nx"&gt;Successful&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt; &lt;span class="nx"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="err"&gt;✔&lt;/span&gt;  &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;webhook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;us&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;central1&lt;/span&gt;&lt;span class="p"&gt;)]:&lt;/span&gt; &lt;span class="nx"&gt;Successful&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt; &lt;span class="nx"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nb"&gt;Function&lt;/span&gt; &lt;span class="nc"&gt;URL &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;webhook&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//us-central1-myexampleproject.cloudfunctions.net/webhook&lt;/span&gt;
&lt;span class="err"&gt;✔&lt;/span&gt;  &lt;span class="nx"&gt;Deploy&lt;/span&gt; &lt;span class="nx"&gt;complete&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you have the webhook updated, you can test it out on Facebook Messenger.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.nexmo.com/wp-content/uploads/2020/05/messenger-example.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2020%2F05%2Fmessenger-example.png" alt="Facebook Messenger Example" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feel free to change intents and actions in Dialogflow to start to see how it can work in your communication strategy.&lt;/p&gt;

&lt;p&gt;If you’d like to see a full version of this and other Google Cloud examples, you can find it here – &lt;a href="https://github.com/nexmo-community/google-cloud-sample-code" rel="noopener noreferrer"&gt;https://github.com/nexmo-community/google-cloud-sample-code&lt;/a&gt;. If you have any questions or requests for other examples with Google Cloud, Dialogflow or Firebase, open up a pull request or shoot me a message &lt;a href="https://twitter.com/kellyjandrews" rel="noopener noreferrer"&gt;on Twitter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://www.nexmo.com/blog/2020/06/01/using-dialogflow-with-firebase-and-the-vonage-messages-sandbox-dr" rel="noopener noreferrer"&gt;Using Dialogflow with Firebase and the Vonage Messages Sandbox&lt;/a&gt; appeared first on &lt;a href="https://www.nexmo.com" rel="noopener noreferrer"&gt;Vonage Developer Blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>firebase</category>
      <category>dialogflow</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Adding 2FA to a React App Using Firebase Functions</title>
      <dc:creator>Kelly Andrews</dc:creator>
      <pubDate>Wed, 01 Apr 2020 12:06:34 +0000</pubDate>
      <link>https://dev.to/vonagedev/adding-2fa-to-a-react-app-using-firebase-functions-m9i</link>
      <guid>https://dev.to/vonagedev/adding-2fa-to-a-react-app-using-firebase-functions-m9i</guid>
      <description>&lt;p&gt;If you’re like me, you probably have a few “smart” devices around your home. There are multiple ways to interact and control these devices, but I wanted to be able to control them with text messages and eventually voice as well.&lt;/p&gt;

&lt;p&gt;So I set out to build some tooling in Firebase to get me going. The first step I wanted to take, however, was securing the phone numbers that have access, and I thought it would be a perfect time to try out the Verify API. It’s admittedly a bit over-the-top since this isn’t a distributed app, but for safety, a phone number must go through the verification process to access my devices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify API
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://developer.nexmo.com/verify/overview" rel="noopener noreferrer"&gt;Verify API&lt;/a&gt; is a way to confirm that the phone belongs to the user. Performing the verification helps protect against spam and suspicious activity, as well as validating ownership.&lt;/p&gt;

&lt;p&gt;The API itself has quite a lot packed into it. Its &lt;a href="https://developer.nexmo.com/verify/guides/changing-default-timings" rel="noopener noreferrer"&gt;configuration options&lt;/a&gt; let you build the &lt;a href="https://developer.nexmo.com/verify/guides/workflows-and-events" rel="noopener noreferrer"&gt;exact workflow&lt;/a&gt; that works for your system. As an example, the default workflow sends an SMS with a PIN code, waits 125 seconds, then calls with a Text-to-Speech event, waits 3 additional minutes, then calls again and waits 5 minutes before expiring the request altogether.&lt;/p&gt;

&lt;p&gt;I like having this level control over something like this as it allows me to be very specific about how I can interact with my users. In my particular instance, I kept it very simple and did just one SMS message that expired in two minutes, since I wanted this mostly for my own purposes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;opts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;phoneNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;brand&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Total Home Control&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;workflow_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;pin_expiry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to get started with the Verify API, you can sign up for a &lt;a href="https://dashboard.nexmo.com/sign-up" rel="noopener noreferrer"&gt;Vonage&lt;/a&gt; account today to get going.&lt;/p&gt;

&lt;h2&gt;
  
  
  Firebase Functions
&lt;/h2&gt;

&lt;p&gt;Since I decided on using &lt;a href="https://firebase.google.com/" rel="noopener noreferrer"&gt;Firebase&lt;/a&gt; and &lt;a href="https://firebase.google.com/products/firestore" rel="noopener noreferrer"&gt;Firestore&lt;/a&gt;, setting up some &lt;a href="https://firebase.google.com/products/functions" rel="noopener noreferrer"&gt;Cloud Functions&lt;/a&gt; to interact with the data and the Verify API was my next step. Each time a new phone number was created, I wanted to send it a verification code and then have a function to check the code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Promises, Promises
&lt;/h3&gt;

&lt;p&gt;When you first learn Cloud Functions, you may try some &lt;a href="https://firebase.google.com/docs/functions/get-started" rel="noopener noreferrer"&gt;simple operations&lt;/a&gt; and build your confidence, which is what I did. After going through some of the simple functions first, I figured I’d be able to build this out fairly quickly.&lt;/p&gt;

&lt;p&gt;And I was wrong. One detail I completely overlooked is that callback methods do not evaluate in the Cloud Function environment the way they do in other environments. Once there is a returned value or promise, the CPU stops. Since the Nexmo JavaScript SDK is running on callback methods, it stops processing.&lt;/p&gt;

&lt;p&gt;Not knowing this had to be one of the more frustrating problems I’ve run into in a long time. The timing of everything was weird because the call back would run when I tried again, causing me to think I wasn’t waiting long enough or the latency was terrible.&lt;/p&gt;

&lt;p&gt;Once I sorted that out, I realized I needed to &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises" rel="noopener noreferrer"&gt;create Promise wrappers&lt;/a&gt; for the SDK methods, and everything worked perfectly. If you want some useful tips &amp;amp; tricks, I recommend reading &lt;a href="https://firebase.google.com/docs/functions/tips" rel="noopener noreferrer"&gt;this Firebase documentation guide.&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Requesting the Verify Code
&lt;/h3&gt;

&lt;p&gt;The Verify request method in the &lt;a href="https://developer.nexmo.com/sdk/stitch/javascript/" rel="noopener noreferrer"&gt;Nexmo JavaScript SDK&lt;/a&gt; is quite minimal code, as the framework there makes it simple to do most everything. The first thing I had to do was wrap it in a promise.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;verifyRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;nexmo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creating this wrapper allows the callback method to run and return as a Promise resolution, instead of being ignored.&lt;/p&gt;

&lt;p&gt;With this method, I could now create a Firebase function to run when the app added a new number to Firestore.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;requestVerify&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firestore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;document&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/phoneNumbers/{phoneNumber}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;opts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;phoneNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;brand&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Total Home Control&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;workflow_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;pin_expiry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;verifyRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;firestore&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/phoneNumbers/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;phoneNumber&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;req_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request_id&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the Verify API, we need to keep track of the &lt;code&gt;request_id&lt;/code&gt; to use in the check process. I use this to indicate that the verification process started but not yet completed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Checking the Verify Code
&lt;/h3&gt;

&lt;p&gt;Same as the previous example, the SDK method needs to first be wrapped as a Promise.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;verifyCheck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;nexmo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the user receives it, the React application asks for the code and then calls the function directly from the application, passing the &lt;code&gt;request_id&lt;/code&gt;, and the &lt;code&gt;code&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checkVerify&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCall&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;opts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;request_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;req_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;verifyCheck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;firestore&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/phoneNumbers/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;phoneNumber&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;req_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;verified&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As long as the code checks out, the document updates to include a &lt;code&gt;verified&lt;/code&gt; flag, and the process is over. There are error status responses to check for and respond to accordingly—for example, if the code has timed out. My app currently assumes it passes.&lt;/p&gt;

&lt;h3&gt;
  
  
  React App
&lt;/h3&gt;

&lt;p&gt;I won’t spend too much time explaining all the code I wrote for my app, but the highlights are adding the data, and then calling the Firebase function from the frontend.&lt;/p&gt;

&lt;p&gt;In my app, I have a form to add a new number, consisting of just the phone number field. On submission, it merely adds it to the database. I’ve also set up a Firebase context file that sets the connections between my app and Firebase, so I can easily import everything I need.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fb&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../context/firebase&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;//-----//&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;_handleSubmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;verified&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;phoneNumbers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;phoneNumber&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;//-----//&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The verification is nearly the same form with a similar submit method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../context/firebase&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;//-----//&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;_handleSubmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;checkVerify&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;httpsCallable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;checkVerify&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;checkVerify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;req_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]?.&lt;/span&gt;&lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;req_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;phoneNumber&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]?.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//close the form&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;//-----//&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Firebase SDK provides a &lt;code&gt;functions&lt;/code&gt; export to let you use &lt;code&gt;httpsCallable()&lt;/code&gt; and name the function. Instead of needing to write any HTTP requests and waiting on those, this simplifies the process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap Up
&lt;/h2&gt;

&lt;p&gt;The Verify API is simple to use, and with Firebase and React you can quickly write the code needed to validate your users and their phone numbers. Feel free to try it out. You can sign up for a &lt;a href="https://dashboard.nexmo.com/sign-up" rel="noopener noreferrer"&gt;Vonage&lt;/a&gt; account, and if you need some credits to get you started send us an email at &lt;a href="mailto:devrel@vonage.com"&gt;devrel@vonage.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can find my &lt;a href="https://dev.tosample%20application%20code%20here"&gt;https://github.com/kellyjandrews/smart-home-app&lt;/a&gt;. The app I built is more of a personal app for me, but feel free to have a look and use anything you might find useful. Over the next month or so, I’ll be adding some additional functionality to the app as well—first is opening and closing my garage door.&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://www.nexmo.com/blog/2020/04/01/adding-2fa-to-a-react-app-using-firebase-function" rel="noopener noreferrer"&gt;Adding 2FA to a React App Using Firebase Function&lt;/a&gt; appeared first on &lt;a href="https://www.nexmo.com" rel="noopener noreferrer"&gt;Vonage Developer Blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>react</category>
      <category>firebase</category>
      <category>javascript</category>
      <category>2fa</category>
    </item>
    <item>
      <title>Real-time SMS Demo with React, Node, and Google Translate</title>
      <dc:creator>Kelly Andrews</dc:creator>
      <pubDate>Wed, 11 Mar 2020 13:02:01 +0000</pubDate>
      <link>https://dev.to/vonagedev/real-time-sms-demo-with-react-node-and-google-translate-24c8</link>
      <guid>https://dev.to/vonagedev/real-time-sms-demo-with-react-node-and-google-translate-24c8</guid>
      <description>&lt;p&gt;Last year I worked with the &lt;a href="https://www.nexmo.com/blog/2019/10/24/extending-nexmo-google-cloud-translation-api-dr"&gt;Google Translate API&lt;/a&gt; to translate SMS messages. After showing the rest of the team, they wanted a demo they could show off to other developers at conferences we attended. Based on that, I set out to create a frontend with React that could display the translations in real-time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the WebSocket
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What's a WebSocket?
&lt;/h3&gt;

&lt;p&gt;For this demo, I decided that using a WebSocket would be a great solution. If you haven't used a WebSocket before, it's a protocol that allows a client and server to communicate in real-time. WebSockets are bi-directional, meaning the client and server can both send and receive messages. When you first connect to a WebSocket, the connection is made by upgrading an HTTP protocol to the WebSocket protocol and is kept alive as long as it goes uninterrupted. Once established, it provides a continuous stream of content. Exactly what we need to receive incoming, translated SMS messages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create the WebSocket Server in Node
&lt;/h3&gt;

&lt;p&gt;As an initial step to creating the WebSockets, the server requires a path to allow for client connections. Starting with the original server file from my &lt;a href="https://github.com/nexmo-community/sms-google-translate-js"&gt;previous post&lt;/a&gt;, we can make a few minor changes to create the WebSocket server and the events and listeners required by the client.&lt;/p&gt;

&lt;p&gt;Using the &lt;a href="https://github.com/websockets/ws"&gt;&lt;code&gt;ws&lt;/code&gt;&lt;/a&gt; package on NPM, we can quickly create what we need to get this working.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;ws
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once installed, include the package in your server file, and create the WebSocket server. &lt;code&gt;WS&lt;/code&gt; allows a &lt;code&gt;path&lt;/code&gt; option to set the route the client uses to connect.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;WebSocket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ws&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/socket&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With this bit of code, the client now has a place to connect to the WebSocket route &lt;code&gt;/socket&lt;/code&gt;. With the server ready to go, you need to now listen for a &lt;code&gt;connection&lt;/code&gt; event. When the client connects, the server uses the following to set up the other listeners we need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;wss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connection&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isAlive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;translateTo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pong&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isAlive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;translateTo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;There are two main points to call out:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;On connection, we set the property &lt;code&gt;isAlive&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt;, and listen for the &lt;code&gt;pong&lt;/code&gt; event. This event is for the server to check and maintain a connection with the client. The server sends a &lt;code&gt;ping&lt;/code&gt; and responds with &lt;code&gt;pong&lt;/code&gt; to verify it's still a live connection.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Here I set up &lt;code&gt;translateTo&lt;/code&gt; as a property to store. &lt;code&gt;translateTo&lt;/code&gt; is set through each client using a dropdown. When someone using our booth demo app selects a different language, that action sets this to translate the SMS texts into the requested language.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Keeping the Connection Alive
&lt;/h3&gt;

&lt;p&gt;One essential item to be concerned with is checking for clients that disconnect. It's possible that during the disconnection process, the server may not be aware, and problems may occur. With a good friend &lt;code&gt;setInterval()&lt;/code&gt;, we can check if our clients are still there and reconnect them if needed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;wss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clients&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isAlive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;terminate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isAlive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Sending Messages to the Client
&lt;/h3&gt;

&lt;p&gt;Now that the WebSocket is connected and monitored, we can handle the inbound messages from Nexmo, the translation, and the response to the client. The method &lt;code&gt;handleRoute&lt;/code&gt; needs to be updated from its original state to add the response for each client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleRoute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;msisdn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;This is not a valid inbound SMS message!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;wss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clients&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;translation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;translateText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;translateTo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;obfuscateNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;msisdn&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;translation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;translation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;translatedText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;originalLanguage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;translation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;detectedSourceLanguage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;originalMessage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;translatedTo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;translateTo&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;wss.clients.forEach&lt;/code&gt; method iterates through each connection, and sends off the SMS parameters from Nexmo to the Google Translate API. Once the translation comes back, we can decide what data the front-end should have, and pass it back as a string as I've done here with &lt;code&gt;client.send(JSON.stringify(response))&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To recap what has happened here: Each client connects to the WebSocket server by calling the &lt;code&gt;/socket&lt;/code&gt; route and establishing a connection. An SMS message goes from the sender's phone to Nexmo, which then calls the &lt;code&gt;/inboundSMS&lt;/code&gt; route. The app passes the text message to Google Translate API for each connected client, and then finally sends it back to the client UI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---7ag-Tuq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.nexmo.com/wp-content/uploads/2020/03/flow-diagram.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---7ag-Tuq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.nexmo.com/wp-content/uploads/2020/03/flow-diagram.png" alt="Diagram of WebSocket Flow" title="Diagram of WebSocket Flow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, let's build the UI parts to display it on the screen.&lt;/p&gt;

&lt;h2&gt;
  
  
  WebSockets with React
&lt;/h2&gt;

&lt;p&gt;With the WebSocket server running, we can move on to the display of the messages on screen. Since I enjoy using &lt;a href="https://reactjs.org/"&gt;React&lt;/a&gt;, and more importantly, &lt;a href="https://reactjs.org/docs/hooks-intro.html"&gt;React Hooks&lt;/a&gt;, I set out to locate something to help with connecting to WebSockets. Sure enough, I found one that fit my exact need.&lt;/p&gt;

&lt;p&gt;The demo app UI is built with &lt;a href="https://github.com/facebook/create-react-app"&gt;&lt;code&gt;create-react-app&lt;/code&gt;&lt;/a&gt;, and I used the &lt;a href="https://v2.grommet.io/"&gt;Grommet&lt;/a&gt; framework. These topics are out of scope for this post, but you can grab my &lt;a href="https://github.com/nexmo-community/sms-translation-demo-app"&gt;source code&lt;/a&gt; and follow along.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connecting to the WebSocket
&lt;/h3&gt;

&lt;p&gt;The first step here is to establish a connection and begin two-way communication. The module I found is &lt;a href="https://github.com/robtaussig/react-use-websocket"&gt;&lt;code&gt;react-use-websocket&lt;/code&gt;&lt;/a&gt;, and it made setting this up super simple.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;react-use-websocket
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;There are tons of these React hook libraries out there that help you create some impressive functionality in a short amount of time. In this instance, importing the module and setting up a couple of items for the configuration is all it took to get a connection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;useWebSocket&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-use-websocket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;STATIC_OPTIONS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;shouldReconnect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;closeEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;protocolPrefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;protocol&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wss:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ws:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;host&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lastMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;readyState&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useWebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;protocolPrefix&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;//&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/socket`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;STATIC_OPTIONS&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the component, we import the &lt;code&gt;useWebSocket&lt;/code&gt; method to pass the WebSocket URL and the object &lt;code&gt;STATIC_OPTIONS&lt;/code&gt; as the second argument. The &lt;code&gt;useWebSocket&lt;/code&gt; method is a custom hook that returns the &lt;code&gt;sendMessage&lt;/code&gt; method, &lt;code&gt;lastMessage&lt;/code&gt; object from the server (which is our translated messages), and the &lt;code&gt;readyState&lt;/code&gt; which is an integer to give us the status of the connection.&lt;/p&gt;

&lt;h3&gt;
  
  
  Receiving Incoming Messages
&lt;/h3&gt;

&lt;p&gt;Once &lt;code&gt;react-use-websocket&lt;/code&gt; makes the connection to the server, we can now start listening for messages from the &lt;code&gt;lastMessage&lt;/code&gt; property. When receiving incoming messages from the server, they populate here and update the component. If your server has multiple message types, you discern that information here. Since we only have one, it's an easier implementation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;messageHistory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setMessageHistory&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;

&lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lastMessage&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;setMessageHistory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lastMessage&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;lastMessage&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Main&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;messageHistory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;From&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Text&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Heading&lt;/span&gt; &lt;span class="nx"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;translation&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Heading&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Box&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})}&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Main&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The built-in hook &lt;code&gt;useEffect&lt;/code&gt; runs every time the state is updated. When &lt;code&gt;lastMessage&lt;/code&gt; is not null, it adds the new message to the end of the previous message state array, and the UI updates using the &lt;code&gt;map&lt;/code&gt; function to render all of the messages. It is in the &lt;code&gt;messageHistory&lt;/code&gt; where all of the JSON strings we passed from the server are stored. The main functionality of our WebSocket is complete, but I still want to add a few more items.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sending Messages to the Server
&lt;/h3&gt;

&lt;p&gt;Since this is a translation demo, having more than one language is an excellent way to show the power of the Google Translate API in conjunction with Nexmo SMS messages. I created a dropdown with languages to pick. This dropdown is where bi-directional communication happens with the server, and the app sends the selected language from the client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;languages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;English&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;French&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fr&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;German&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;de&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Spanish&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;es&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Select&lt;/span&gt;
  &lt;span class="nx"&gt;labelKey&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;label&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{({&lt;/span&gt; &lt;span class="nx"&gt;option&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;option&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;setTranslateValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;option&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}}&lt;/span&gt;
  &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;languages&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;translateValue&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;valueKey&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;value&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here, the &lt;code&gt;sendMessage&lt;/code&gt; function from &lt;code&gt;react-use-websocket&lt;/code&gt; is how we can send information back to our server and consume it. This process is where the event handler we set up comes in handy from earlier. It is this dropdown that determines what language the Google Translate API translates the message into and displays on the screen.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connection Status Display
&lt;/h3&gt;

&lt;p&gt;Since this is a demo in a conference environment, I thought having a connectivity indicator would be a good idea. As long as the front-end remains connected to the WebSocket, the light displays green.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CONNECTION_STATUS_CONNECTING&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CONNECTION_STATUS_OPEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CONNECTION_STATUS_CLOSING&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;CONNECTION_STATUS_OPEN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Connected&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;led green&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;CONNECTION_STATUS_CONNECTING&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Connecting&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;led yellow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;CONNECTION_STATUS_CLOSING&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Closing&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;led yellow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Disconnected&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;led grey&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;//....&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Status&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;readyState&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;Status&lt;/code&gt; component uses the &lt;code&gt;readyState&lt;/code&gt; to switch between the various statuses and indicates that to the user. If it turns red, you know something is wrong with the WebSocket server, and you should check into it.  &lt;/p&gt;

&lt;p&gt;Once everything is up and running, it looks something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aBJ2DSML--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.nexmo.com/wp-content/uploads/2020/03/using_translation_app.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aBJ2DSML--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.nexmo.com/wp-content/uploads/2020/03/using_translation_app.gif" alt="Animation of Working Demo App" title="Animation of Working Demo App"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It Out
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/nexmo-community/sms-translation-demo-app"&gt;demo application code&lt;/a&gt; is on our community GitHub organization, and you can try it out for yourself as well. I've created a README that should help you get through the setup and run it locally on your server or deploy it to Heroku. I've also provided a Dockerfile, if you'd prefer to go that route. Let me know what you think of it, and if you have any trouble, feel free to reach out and submit an issue on the repo.&lt;/p&gt;

</description>
      <category>googletranslate</category>
      <category>javascript</category>
      <category>react</category>
      <category>websockets</category>
    </item>
    <item>
      <title>Send and Receive SMS Messages with Node, Nexmo, and Firebase Functions</title>
      <dc:creator>Kelly Andrews</dc:creator>
      <pubDate>Tue, 18 Feb 2020 10:18:00 +0000</pubDate>
      <link>https://dev.to/vonagedev/send-and-receive-sms-messages-with-node-nexmo-and-firebase-functions-k30</link>
      <guid>https://dev.to/vonagedev/send-and-receive-sms-messages-with-node-nexmo-and-firebase-functions-k30</guid>
      <description>&lt;p&gt;The Firebase platform allows developers to build an application backend rapidly. It's also enjoyable to use as well. For this tutorial, I wanted to start using it for some SMS messaging with &lt;a href="https://www.nexmo.com/" rel="noopener noreferrer"&gt;Nexmo&lt;/a&gt;. After this walk-through, you will be able to create an SMS message log, and a response to the sender using &lt;a href="https://firebase.google.com/docs/functions/get-started" rel="noopener noreferrer"&gt;Firebase Functions&lt;/a&gt; and Firestore alongside the Nexmo SMS API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before You Get Started
&lt;/h2&gt;

&lt;p&gt;You will need a few items to get going - so take a moment and make sure you have both of these ready to go. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://firebase.google.com/" rel="noopener noreferrer"&gt;Firebase&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dashboard.nexmo.com/sign-in" rel="noopener noreferrer"&gt;Nexmo&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Setting up Firebase
&lt;/h2&gt;

&lt;p&gt;The first step is to set up a Firebase project. The following will walk you through setting up a new project using the Firebase console.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create the Firebase Project
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://console.firebase.google.com/" rel="noopener noreferrer"&gt;Firebase console&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;Click add project
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2020%2F01%2Fcreate-project.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2020%2F01%2Fcreate-project.png" alt="Click Add Project" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add a name and click continue&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2020%2F01%2Fname-project.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2020%2F01%2Fname-project.png" alt="Name Project" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Leave Google Analytics on and click continue (not required)&lt;/li&gt;
&lt;li&gt;Select a Google Analytics account and then click Create Project (if added)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2020%2F01%2Fadd-analytics.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2020%2F01%2Fadd-analytics.png" alt="Add analytics" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Wait a bit for the project to be created - takes less than a minute&lt;/li&gt;
&lt;li&gt;Set the Billing type under &lt;em&gt;⚙️ -&amp;gt; Usage and Billing -&amp;gt; Details &amp;amp; Settings&lt;/em&gt; to Blaze. The Pay-as-you-go plan is required to use a third-party API. For more details regarding billing with Google, go &lt;a href="https://cloud.google.com/billing/docs/how-to/payment-methods" rel="noopener noreferrer"&gt;here&lt;/a&gt;.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2020%2F01%2Fupdate-billing.png" alt="Change Billing" width="800" height="400"&gt;
&lt;/li&gt;
&lt;li&gt;Set the &lt;code&gt;Google Cloud Platform (GCP) resource location&lt;/code&gt; in &lt;code&gt;⚙️ -&amp;gt; Project Settings&lt;/code&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2020%2F01%2Fupdate-location.png" alt="Update Location" width="800" height="400"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Install Firebase Tools
&lt;/h3&gt;

&lt;p&gt;Most everything you will need to do with Firebase can be done directly from the command line with the toolset they provide.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install the Firebase tools with npm
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; npm install -g firebase-tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Log in to Firebase using &lt;code&gt;firebase login&lt;/code&gt;. The login process will open your browser for authentication.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Setup Local Environment
&lt;/h3&gt;

&lt;p&gt;Writing Firebase functions requires some initialization work to get started, but it's mostly done for you using Firebase Tools commands.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create a project folder &lt;code&gt;mkdir nexmo-project &amp;amp;&amp;amp; cd nexmo-project&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Initialize Firebase Functions &lt;code&gt;firebase init functions&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;     ######## #### ########  ######## ########     ###     ######  ########
     ##        ##  ##     ## ##       ##     ##  ##   ##  ##       ##
     ######    ##  ########  ######   ########  #########  ######  ######
     ##        ##  ##    ##  ##       ##     ## ##     ##       ## ##
     ##       #### ##     ## ######## ########  ##     ##  ######  ########

You're about to initialize a Firebase project in this directory:

 /your_folders/your-project-name


=== Project Setup

First, let's associate this project directory with a Firebase project.
You can create multiple project aliases by running firebase use --add,
but for now, we'll just set up a default project.

? Please select an option: (Use arrow keys)
❯ Use an existing project
 Create a new project
 Add Firebase to an existing Google Cloud Platform project
 Don't set up a default project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since you already created a project in the dashboard, you can select &lt;code&gt;Use an existing project&lt;/code&gt; which will prompt you to choose the desired project. If you haven't done this, use &lt;code&gt;Create a new project&lt;/code&gt; and give it a unique name to create one. You would still need to go to the console to update the location and billing, but it is another option to create Firebase projects. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select the project name you created&lt;/li&gt;
&lt;li&gt;Select JavaScript&lt;/li&gt;
&lt;li&gt;Choose Y for ESLint if you desire (I recommend it)&lt;/li&gt;
&lt;li&gt;Install all dependencies now&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These steps will create the folders and files required to build Firebase Functions and installs all dependencies. Once NPM completes, switch to the &lt;code&gt;functions&lt;/code&gt; directory and open &lt;code&gt;index.js&lt;/code&gt; in your favorite editor to start adding code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create Your First Function
&lt;/h3&gt;

&lt;p&gt;The first function you create will act as a webhook to capture and log incoming SMS messages from Nexmo.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;index.js&lt;/code&gt; file has some example code provided you won't need. Delete everything and start at the top to add the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase-functions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase-admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 

&lt;span class="c1"&gt;// Initialize Firebase app for database access&lt;/span&gt;
&lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Calling &lt;code&gt;admin.initializeApp();&lt;/code&gt; allows the functions to read and write to the Firebase Real-Time database. Next, use the following method to create your function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// This function will serve as the webhook for incoming SMS messages,&lt;/span&gt;
&lt;span class="c1"&gt;// and will log the message into the Firebase Realtime Database&lt;/span&gt;
&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inboundSMS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;database&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/msgq&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;inboundSMS&lt;/code&gt; method listens for HTTPS requests - which is precisely what Nexmo webhook needs. The Firebase Function will capture the &lt;code&gt;req.body&lt;/code&gt; and send it to the &lt;code&gt;/msgq&lt;/code&gt; object in the Real-Time Database as a log. &lt;/p&gt;

&lt;p&gt;Since we are using &lt;code&gt;req.body&lt;/code&gt;, the webhook will need to be a &lt;code&gt;POST Method&lt;/code&gt;. If you'd prefer to (or you have to) use the &lt;code&gt;GET&lt;/code&gt; method for Nexmo webhooks, just replace it with &lt;code&gt;req.query&lt;/code&gt;, and the GET method will work the same way.&lt;/p&gt;

&lt;p&gt;Now that you have some code written be sure to save your file an deploy the function to Firebase:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;firebase deploy --only functions

=== Deploying to 'nexmo-project'...

i deploying functions
Running command: npm --prefix "$RESOURCE_DIR" run lint

&amp;gt; functions@ lint /Users/kellyjandrews/Google Drive/Apps/nexmo-project/functions
&amp;gt; eslint .

✔ functions: Finished running predeploy script.
i functions: ensuring necessary APIs are enabled...
✔ functions: all necessary APIs are enabled
i functions: preparing functions directory for uploading...
i functions: packaged functions (38.78 KB) for uploading
✔ functions: functions folder uploaded successfully
i functions: creating Node.js 8 function inboundSMS(us-central1)...
✔ functions[inboundSMS(us-central1)]: Successful create operation.
Function URL (inboundSMS): https://us-central1-nexmo-project.cloudfunctions.net/inboundSMS

✔ Deploy complete!

Project Console: https://console.firebase.google.com/project/nexmo-project/overview
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The vital piece from the output is &lt;code&gt;Function URL (inboundSMS)&lt;/code&gt;. This URL is required to set up the webhook in Nexmo, which you will do next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up Nexmo
&lt;/h2&gt;

&lt;p&gt;There are a few quick steps to setting up Nexmo - all done from the command line.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install the CLI
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; npm install -g nexmo-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Setup the CLI with your API key and secret from the dashboard &lt;a href="https://dashboard.nexmo.com/getting-started-guide" rel="noopener noreferrer"&gt;https://dashboard.nexmo.com/getting-started-guide&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Purchase a new phone number
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; nexmo number:buy --country_code US
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;This command retrieves the first available phone number in the US. For more info on Nexmo numbers, you can view the [numbers documentation](&lt;a href="https://developer.nexmo.com/numbers/overview" rel="noopener noreferrer"&gt;https://developer.nexmo.com/numbers/overview&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Type confirm, then copy the number

&lt;ol&gt;
&lt;li&gt;Link the phone number to the webhook using this command
&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; nexmo link:sms YOUR_NUMBER YOUR_FUNCTION_URL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Give the process a few seconds to completely provision, then test out the new function to make sure the message is getting logged. &lt;/p&gt;

&lt;p&gt;Grab your phone and send a message to the phone number. Open up the Firebase console and navigate to &lt;code&gt;database&lt;/code&gt; page, and you should see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2020%2F01%2Fdatabase-nexmo-object.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2020%2F01%2Fdatabase-nexmo-object.png" alt="Real-time Database Nexmo Message Entry" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that there is a way to log incoming messages, you can write a function to do something with the incoming message.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the Send Function
&lt;/h2&gt;

&lt;p&gt;So far, you have created a Firebase Function linked to a Nexmo phone number for capturing inbound SMS messages. Firebase Functions can also react to database updates. Upon a new entry, the code sends an echo of the original text.&lt;/p&gt;

&lt;p&gt;Start by adding Nexmo to the dependency list - make sure you do this in the &lt;code&gt;functions&lt;/code&gt; directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i nexmo --save
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following environment variables to the Firebase config&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;firebase functions:config:set nexmo.api_key="YOUR_KEY" nexmo.api_secret="YOUR_SECRET"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, open &lt;code&gt;index.js&lt;/code&gt; add &lt;code&gt;nexmo&lt;/code&gt; to the requirements at the top, and import the environment variables to initialize Nexmo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase-functions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase-admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Nexmo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nexmo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Initialize Firebase app for database access&lt;/span&gt;
&lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// get Firebase environment variables for Nexmo&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;api_secret&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;nexmo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Initialize Nexmo with application credentials&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nexmo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Nexmo&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;apiSecret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;api_secret&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can create the new function for Firebase to send the response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// This function listens for updates to the Firebase Realtime Database&lt;/span&gt;
&lt;span class="c1"&gt;// and sends a message back to the original sender&lt;/span&gt;
&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sendSMS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/msgq/{pushId}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;msisdn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;val&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// the incoming object - 'msisdn' is the your phone number, and 'to' is the Nexmo number&lt;/span&gt;
    &lt;span class="c1"&gt;// nexmo.message.sendSms(to, msisdn, text);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;nexmo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendSms&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;msisdn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`You sent the following text: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;status&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Message sent successfully.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Message failed with error: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error-text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The new function will watch for new messages added to the &lt;code&gt;/msgq&lt;/code&gt; database object. When triggered, the full Nexmo object gets passed as &lt;code&gt;message&lt;/code&gt; .  This object includes &lt;code&gt;msisdn&lt;/code&gt;,  which is the originating phone number - yours in this case, and the &lt;code&gt;to&lt;/code&gt; number, which is the Nexmo virtual number you purchased. &lt;/p&gt;

&lt;p&gt;With the phone numbers in hand, as well as the text message, you can now do any number of things. You can create a lookup table to respond with specific data based on the keyword, forward to another system, or in our case, send the original message.&lt;/p&gt;

&lt;p&gt;Deploy the Firebase Functions again from the command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;firebase deploy --only functions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Grab your phone, send another message, and then you should get a response back that looks something like &lt;code&gt;You sent the following text: Test message&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap Up
&lt;/h2&gt;

&lt;p&gt;You have now completed all the steps for this tutorial. You can see the full code on &lt;a href="https://github.com/nexmo-community/firebase-functions-sms-example" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now that the initial steps to send and receive messages are complete, my next few posts will take this concept and expand it into controlling some of my home automation via text messages. I would love to hear what you plan to do as well so send me a message on &lt;a href="https://twitter.com/kellyjandrews" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and let me know.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Check out the Developer Documentation at &lt;a href="https://developer.nexmo.com" rel="noopener noreferrer"&gt;https://developer.nexmo.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Details about Nexmo SMS Functionality &lt;a href="https://developer.nexmo.com/messaging/sms/overview" rel="noopener noreferrer"&gt;https://developer.nexmo.com/messaging/sms/overview&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Getting started with Firebase Functions &lt;a href="https://firebase.google.com/docs/functions/get-started" rel="noopener noreferrer"&gt;https://firebase.google.com/docs/functions/get-started&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The post &lt;a href="https://www.nexmo.com/blog/2020/01/24/send-and-receive-sms-messages-with-firebase-functions-dr" rel="noopener noreferrer"&gt;Send and Receive SMS Messages with Firebase Functions&lt;/a&gt; appeared first on &lt;a href="https://www.nexmo.com" rel="noopener noreferrer"&gt;Nexmo Developer Blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>sms</category>
      <category>firebase</category>
      <category>nexmo</category>
      <category>node</category>
    </item>
    <item>
      <title>Translating SMS Messages With Azure Translator Text</title>
      <dc:creator>Kelly Andrews</dc:creator>
      <pubDate>Mon, 25 Nov 2019 17:37:06 +0000</pubDate>
      <link>https://dev.to/vonagedev/translating-sms-messages-with-azure-translator-text-4n9e</link>
      <guid>https://dev.to/vonagedev/translating-sms-messages-with-azure-translator-text-4n9e</guid>
      <description>&lt;p&gt;In my previous posts, I showed how you can translate text messages with the &lt;a href="https://dev.to/nexmo/translating-sms-messages-using-google-cloud-s-translation-api-g35"&gt;Google Translation API&lt;/a&gt;, &lt;a href="https://dev.to/kellyjandrews/translate-sms-messages-using-amazon-translate-5ca1-temp-slug-8260259"&gt;AWS Translate&lt;/a&gt;. and &lt;a href="https://dev.to/kellyjandrews/translate-sms-messages-with-ibm-watson-3i89-temp-slug-9890178"&gt;IBM Watson Language Translator&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;In this post, I show you how to create an &lt;a href="https://developer.nexmo.com/messaging/sms/guides/inbound-sms" rel="noopener noreferrer"&gt;inbound Nexmo SMS&lt;/a&gt; webhook and translate the message into English using the &lt;a href="https://azure.microsoft.com/en-us/services/cognitive-services/translator-text-api/" rel="noopener noreferrer"&gt;Azure Translator Text&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In order to get started, you will need the following items set up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://azure.microsoft.com/en-us/" rel="noopener noreferrer"&gt;Azure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dashboard.nexmo.com/sign-up" rel="noopener noreferrer"&gt;Nexmo Account&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Nexmo/nexmo-cli#installation" rel="noopener noreferrer"&gt;Nexmo CLI installed&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Create Your Project
&lt;/h2&gt;

&lt;p&gt;You will only need a couple of packages to get things going.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/@azure/ms-rest-js" rel="noopener noreferrer"&gt;&lt;code&gt;@azure/ms-rest-js&lt;/code&gt;&lt;/a&gt;—this is the Azure SDK and will assist with the credentials&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/@azure/cognitiveservices-translatortext" rel="noopener noreferrer"&gt;&lt;code&gt;@azure/cognitiveservices-translatortext&lt;/code&gt;&lt;/a&gt;—this is the Azure Translator Text SDK&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/express" rel="noopener noreferrer"&gt;&lt;code&gt;express&lt;/code&gt;&lt;/a&gt;—web framework to serve the webhook&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/dotenv" rel="noopener noreferrer"&gt;&lt;code&gt;dotenv&lt;/code&gt;&lt;/a&gt;—a package to load environment variables&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/body-parser" rel="noopener noreferrer"&gt;&lt;code&gt;body-parser&lt;/code&gt;&lt;/a&gt;—middleware for Express to handle the incoming webhook object&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Initialize the project and then install the above requirements using &lt;code&gt;npm&lt;/code&gt; or &lt;code&gt;yarn&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm init &amp;amp;&amp;amp; npm install @azure/ms-rest-js @azure/cognitiveservices-translatortext express dotenv body-parser
# or
yarn init &amp;amp;&amp;amp; yarn add @azure/ms-rest-js @azure/cognitiveservices-translatortext express dotenv body-parser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once installed, create an &lt;code&gt;index.js&lt;/code&gt; and &lt;code&gt;.env&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch index.js .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, open the &lt;code&gt;index.js&lt;/code&gt; file and put the following code inside:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use strict&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bodyParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;body-parser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CognitiveServicesCredentials&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@azure/ms-rest-js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;TranslatorTextClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@azure/cognitiveservices-translatortext&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bodyParser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bodyParser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlencoded&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;extended&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Express server listening on port &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;address&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; in &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; mode`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will set up the server to run the example.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing ngrok
&lt;/h3&gt;

&lt;p&gt;Publicly available webhooks are required so that Nexmo can communicate with the application to receive incoming SMS messages. You could push your code up to a publicly available server, or you can use &lt;a href="https://ngrok.com" rel="noopener noreferrer"&gt;&lt;code&gt;ngrok&lt;/code&gt;&lt;/a&gt; to allow for public traffic to reach your local application.&lt;/p&gt;

&lt;p&gt;You can learn more about installing &lt;code&gt;ngrok&lt;/code&gt; with &lt;a href="https://www.nexmo.com/blog/2017/07/04/local-development-nexmo-ngrok-tunnel-dr" rel="noopener noreferrer"&gt;this post&lt;/a&gt;. After you have everything ready to go you can start ngrok using the following command to create your tunnel.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ngrok http 3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make a note of the &lt;code&gt;ngrok&lt;/code&gt; address, as you will need that in a later step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Azure Translator Text
&lt;/h2&gt;

&lt;p&gt;Next you can set up the Azure Translator Text service in the Azure portal. Start by opening the portal and clicking &lt;code&gt;Create New Resource&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2019%2F11%2Fhome_page_add_resource.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2019%2F11%2Fhome_page_add_resource.png" title="Azure Portal Home Page" alt="Azure Portal Home Page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the next screen do a search for &lt;code&gt;Translator Text&lt;/code&gt; and click on the result to be taken to the Translator Text info page. Click &lt;code&gt;Create&lt;/code&gt; to start the process.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2019%2F11%2Fcreate_translator_text.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2019%2F11%2Fcreate_translator_text.png" title="Translator Text Create Resource Screen" alt="Translator Text Create Resource Screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fill out the name, select &lt;code&gt;Pay As You Go&lt;/code&gt; and the resource group, and then click &lt;code&gt;Create&lt;/code&gt; at the bottom of the page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2019%2F11%2Ftranslator_text_details.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2019%2F11%2Ftranslator_text_details.png" title="Translator Text Create Resource Details" alt="Translator Text Create Resource Details"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The creation process take a few moments, so relax for a bit until that completes.&lt;/p&gt;

&lt;p&gt;Open up the &lt;code&gt;.env&lt;/code&gt; file first, and copy and paste the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TEXT\_TRANSLATION\_SUBSCRIPTION\_KEY=TEXT\_TRANSLATION\_ENDPOINT=https://api.cognitive.microsofttranslator.com/translate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Grab the key and endpoint from the quick start page and update the &lt;code&gt;.env&lt;/code&gt; file with that information.&lt;/p&gt;

&lt;p&gt;During my trials, I attempted to use the services endpoint presented in the dashboard, but didn’t have any luck getting it to work correctly. The URL above is the global endpoint that will work if you run into the same troubles.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2019%2F11%2Ftranslate_quickstart.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2019%2F11%2Ftranslate_quickstart.png" title="Translator Text Resource Quickstart" alt="Translator Text Resource Quickstart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Nexmo Inbound SMS Messages
&lt;/h2&gt;

&lt;p&gt;This example requires a phone number from Nexmo to receive inbound messages. We can do this by using the &lt;a href="https://github.com/Nexmo/nexmo-cli#installation" rel="noopener noreferrer"&gt;Nexmo CLI&lt;/a&gt; right from a terminal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Purchase a Virtual Phone Number
&lt;/h3&gt;

&lt;p&gt;First, purchase a number directly from Nexmo (feel free to use a different &lt;a href="https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes" rel="noopener noreferrer"&gt;ISO 3166 alpha-2&lt;/a&gt; country code as needed).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nexmo number:buy --country\_code US
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You haven’t created the route as of yet, however you will name it &lt;code&gt;/message&lt;/code&gt;. The phone number needs to be linked to this route so inbound messages know where to go. Get the &lt;code&gt;ngrok&lt;/code&gt; host name from the previous setup and use it here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nexmo link:sms phone\_number https://my-ngrok-hostname/message
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the Nexmo webhook is set up to route inbound SMS messages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finish the Application
&lt;/h2&gt;

&lt;p&gt;The only step now is to create the Express route and functions to handle the incoming SMS message and the translations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Build the Webhook
&lt;/h3&gt;

&lt;p&gt;We can set up the route handler first. Nexmo allows the setting of a default SMS webhook behavior. &lt;a href="https://dashboard.nexmo.com/settings" rel="noopener noreferrer"&gt;In the settings panel&lt;/a&gt; you can change the default &lt;code&gt;HTTP&lt;/code&gt; method used. Mine is set to &lt;code&gt;POST-JSON&lt;/code&gt;, and I recommend using this setting. If you are unable to modify your setting, the code used here will handle all three options.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2019%2F10%2Fdefault-sms-settings.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2019%2F10%2Fdefault-sms-settings.png" title="Default Nexmo SMS HTTP Method" alt="Default Nexmo SMS HTTP Method"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open up the &lt;code&gt;index.js&lt;/code&gt; file, and at the bottom, paste the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Reading the inbound SMS messages&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleRoute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;msisdn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;This is not a valid inbound SMS message!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;translateText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This handler will be passed directly to the &lt;code&gt;/message&lt;/code&gt; route. If the incoming message HTTP method is &lt;code&gt;POST&lt;/code&gt;, the handler uses &lt;code&gt;req.body&lt;/code&gt;, and uses &lt;code&gt;req.query&lt;/code&gt; for the &lt;code&gt;GET&lt;/code&gt; option. It then checks the inbound payload ensuring it has the correct info, then sends the object to the &lt;code&gt;translateText&lt;/code&gt; method to display the translation.&lt;/p&gt;

&lt;p&gt;Now you can add the route and proper &lt;code&gt;HTTP&lt;/code&gt; methods to the application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handleRoute&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handleRoute&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;405&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code will create the &lt;code&gt;GET&lt;/code&gt; and &lt;code&gt;POST&lt;/code&gt; methods to handle either from the inbound SMS webhook message. If any other method is used, a &lt;code&gt;405 - Method Not Allowed&lt;/code&gt; response will be returned.&lt;/p&gt;

&lt;p&gt;The webhook is ready to go and the final piece is the actual translations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Translation Method
&lt;/h3&gt;

&lt;p&gt;In the previous step we call &lt;code&gt;translateText&lt;/code&gt;. This step will create that method.&lt;/p&gt;

&lt;p&gt;You will initially get your credentials by using &lt;code&gt;CognitiveServicesCredentials.ApiKeyCredentials&lt;/code&gt;. This will need to be passed as the first parameter to the &lt;code&gt;TranslatorTextClient&lt;/code&gt; constructor.&lt;/p&gt;

&lt;p&gt;After create the &lt;code&gt;client&lt;/code&gt;, use the &lt;code&gt;translate&lt;/code&gt; method to translate the text. The first argument is an array of languages you wish to translate the text into—allowing you to translate into multiple languages. The service will automatically detect the incoming language if it can. The second argument is an array of objects for the text you want to translate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;translateText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;creds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;CognitiveServicesCredentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ApiKeyCredentials&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;inHeader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Ocp-Apim-Subscription-Key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TEXT_TRANSLATION_SUBSCRIPTION_KEY&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TranslatorTextClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;creds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TEXT_TRANSLATION_ENDPOINT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;translator&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;translate&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}])&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Original Text: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Translation: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;translations&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can test out the functionality by starting the server and sending a text message to the number you purchased earlier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node index.js
# Text "Hola" to your phone number

# expected response
Original Text: Hola
Translation: Hello
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Azure Translator Text full response object has a lot of details as well, so you can change the response to include &lt;code&gt;console.dir(translationResult, {depth: null})&lt;/code&gt; to see the full payload.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;p&gt;Azure Translator Text is a great tool to translate your inbound messages from Nexmo. This example only scratches the surface, but should be a good start. You can venture off in several directions from here using this as a jumping point. Let me know what ideas you have for using these two services together.&lt;/p&gt;

&lt;p&gt;You can find a completed version of this tutorial at &lt;a href="https://github.com/nexmo-community/sms-azure-translate-js" rel="noopener noreferrer"&gt;https://github.com/nexmo-community/sms-azure-translate-js&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want to learn more about the Extend projects we have, you can visit &lt;a href="https://developer.nexmo.com/extend" rel="noopener noreferrer"&gt;https://developer.nexmo.com/extend&lt;/a&gt; to learn more.&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://www.nexmo.com/blog/2019/11/25/translating-sms-messages-with-azure-translator-text-dr" rel="noopener noreferrer"&gt;Translating SMS Messages With Azure Translator Text&lt;/a&gt; appeared first on &lt;a href="https://www.nexmo.com" rel="noopener noreferrer"&gt;Nexmo Developer Blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>developer</category>
      <category>tutorial</category>
      <category>extendingnexmo</category>
      <category>microsoftazure</category>
    </item>
    <item>
      <title>Translating SMS Messages Using Google Cloud’s Translation API</title>
      <dc:creator>Kelly Andrews</dc:creator>
      <pubDate>Thu, 24 Oct 2019 12:12:44 +0000</pubDate>
      <link>https://dev.to/vonagedev/translating-sms-messages-using-google-cloud-s-translation-api-g35</link>
      <guid>https://dev.to/vonagedev/translating-sms-messages-using-google-cloud-s-translation-api-g35</guid>
      <description>&lt;p&gt;Text messaging has become a part of our daily lives. We integrate it into multiple aspects like banking, alerts, marketing, and support. It has become simple to implement, and Nexmo is no different.&lt;/p&gt;

&lt;p&gt;As a part of the Extend team here, integrating text messages with translation API’s makes perfect sense. Translating incoming text messages can help break down communication barriers and help you reach a broader audience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;In this post, I show you how to create an &lt;a href="https://developer.nexmo.com/messaging/sms/guides/inbound-sms" rel="noopener noreferrer"&gt;inbound Nexmo SMS&lt;/a&gt; webhook and translate the message into English using the Google Cloud Translation API.&lt;/p&gt;

&lt;p&gt;In order to get started, you will need the following items setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://console.cloud.google.com" rel="noopener noreferrer"&gt;Google Cloud Account&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dashboard.nexmo.com/sign-up" rel="noopener noreferrer"&gt;Nexmo Account&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Nexmo/nexmo-cli#installation" rel="noopener noreferrer"&gt;Nexmo CLI installed&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Create Your Project
&lt;/h2&gt;

&lt;p&gt;The setup for this example is minimal, and you only need a couple of packages to get going.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/@google-cloud/translate" rel="noopener noreferrer"&gt;&lt;code&gt;@google-cloud/translate&lt;/code&gt;&lt;/a&gt; – this is the official Cloud Translation SDK&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/express" rel="noopener noreferrer"&gt;&lt;code&gt;express&lt;/code&gt;&lt;/a&gt; – web framework to serve the webhook&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/dotenv" rel="noopener noreferrer"&gt;&lt;code&gt;dotenv&lt;/code&gt;&lt;/a&gt; – a package to load environment variables&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/body-parser" rel="noopener noreferrer"&gt;&lt;code&gt;body-parser&lt;/code&gt;&lt;/a&gt; – middleware for Express to handle the incoming webhook object&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Initialize the project and then install the above requirements using &lt;code&gt;npm&lt;/code&gt; or &lt;code&gt;yarn&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm init &amp;amp;&amp;amp; npm install @google-cloud/translate express dotenv body-parser
# or
yarn init &amp;amp;&amp;amp; yarn add @google-cloud/translate express dotenv body-parser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once installed, create an &lt;code&gt;index.js&lt;/code&gt; and &lt;code&gt;.env&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch index.js .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open up the &lt;code&gt;.env&lt;/code&gt; file first, adn copy and paste the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GOOGLE_APPLICATION_CREDENTIALS=./google_creds.json
TARGET_LANGUAGE='en'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, open the &lt;code&gt;index.js&lt;/code&gt; file and put the following code inside:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use strict&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bodyParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;body-parser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Translate&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@google-cloud/translate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bodyParser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bodyParser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlencoded&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;extended&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Express server listening on port &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;address&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; in &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; mode`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will set up the server to run the example.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing Ngrok
&lt;/h3&gt;

&lt;p&gt;Webhooks need to be publicly available so that the Nexmo service can reach the application when incoming SMS messages are received. You could push your code up to a publicly available server, or you can use &lt;a href="https://ngrok.com" rel="noopener noreferrer"&gt;&lt;code&gt;ngrok&lt;/code&gt;&lt;/a&gt; to allow for public traffic to reach your local application.&lt;/p&gt;

&lt;p&gt;You can learn more about installing &lt;code&gt;ngrok&lt;/code&gt; with &lt;a href="https://www.nexmo.com/blog/2017/07/04/local-development-nexmo-ngrok-tunnel-dr" rel="noopener noreferrer"&gt;this post&lt;/a&gt;. After you have everything ready to go you can start ngrok using the following command to create your tunnel.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ngrok http 3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make a note of the &lt;code&gt;ngrok&lt;/code&gt; address, as you will need that in a later step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Google Cloud Translation API
&lt;/h2&gt;

&lt;p&gt;Once you have the initial items set up, you can now add Google Cloud Translation API to your account. Follow &lt;a href="https://console.cloud.google.com/apis/library/translate.googleapis.com" rel="noopener noreferrer"&gt;this link&lt;/a&gt; to enable the Translation API. Select a project, and then click the &lt;code&gt;Enable&lt;/code&gt; button to activate the API on that project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2019%2F10%2Fenable-translate-api.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2019%2F10%2Fenable-translate-api.png" title="Enable Google Cloud Translation API" alt="Enable Google Cloud Translation API"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is recommended to create a &lt;a href="https://console.cloud.google.com/iam-admin/serviceaccounts" rel="noopener noreferrer"&gt;&lt;code&gt;service user&lt;/code&gt;&lt;/a&gt; that has access to the Translation API. &lt;a href="https://console.cloud.google.com/iam-admin/serviceaccounts" rel="noopener noreferrer"&gt;Click here&lt;/a&gt; and click &lt;code&gt;+ Create Service Account&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2019%2F10%2Fadd-service-account.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2019%2F10%2Fadd-service-account.png" title="Add New Service Account" alt="Add New Service Account"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Give the account any name you’d like, and press the &lt;code&gt;Create&lt;/code&gt; button. After the account is created, add the &lt;code&gt;Cloud Translation API User&lt;/code&gt; role, and click &lt;code&gt;Continue&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2019%2F10%2Fservice-account-role.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2019%2F10%2Fservice-account-role.png" title="Add Cloud Translation API User Role" alt="Add Cloud Translation API User Role"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will need to create keys for this user. Go ahead and click the &lt;code&gt;+ Create Key&lt;/code&gt; button, and then select &lt;code&gt;JSON&lt;/code&gt; and click create. This will download a &lt;code&gt;JSON&lt;/code&gt; file to your machine that you will need to use the account. When that is completed, click &lt;code&gt;Done&lt;/code&gt; to complete the creation process.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2019%2F10%2Fcreate-account-key.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2019%2F10%2Fcreate-account-key.png" title="Create Service Account Key" alt="Create Service Account Key"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2019%2F10%2Fcreate-account-key-type.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2019%2F10%2Fcreate-account-key-type.png" title="Create Service Account Key - Select Type" alt="Create Service Account Key - Select Type"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy the credentials file into your project folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cp /path/to/file/project-name-id.json ./google\_creds.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Google Cloud Translation API is now set up and ready to use.&lt;/p&gt;

&lt;p&gt;Next, we can set up the phone number.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Nexmo Inbound SMS Messages
&lt;/h2&gt;

&lt;p&gt;This example requires a phone number from Nexmo to receive inbound messages. We can do this by using the &lt;a href="https://github.com/Nexmo/nexmo-cli#installation" rel="noopener noreferrer"&gt;Nexmo CLI&lt;/a&gt; right from a terminal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Purchase a Virtual Phone Number
&lt;/h3&gt;

&lt;p&gt;The first step will be to purchase a number (feel free to use a different &lt;a href="https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes" rel="noopener noreferrer"&gt;ISO 3166 alpha-2&lt;/a&gt; country code as needed).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nexmo number:buy --country\_code US
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although the actual route to use in the application isn’t set up, you will name it &lt;code&gt;/message&lt;/code&gt;. The phone number needs to be linked to this route so inbound messages know where to go. Get the &lt;code&gt;ngrok&lt;/code&gt; host name from the previous setup and use it here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nexmo link:sms phone\_number https://my-ngrok-hostname/message
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have the Nexmo webhook set up as a place for inbound SMS messages to be routed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finish the Application
&lt;/h2&gt;

&lt;p&gt;All that is left for this tutorial is creating the Express route to handle the incoming data and a couple of small functions to actually perform the translation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Build the Webhook
&lt;/h3&gt;

&lt;p&gt;First, we need to build the webhook code. Nexmo has a built in feature for setting default SMS behaviour. &lt;a href="https://dashboard.nexmo.com/settings" rel="noopener noreferrer"&gt;In the settings panel&lt;/a&gt; you can change the default &lt;code&gt;HTTP&lt;/code&gt; method used. Mine is set to &lt;code&gt;POST-JSON&lt;/code&gt;. I would recommend using this setting if possible, however the code used in this example will handle all three options in case you are unable to modify this setting.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2019%2F10%2Fdefault-sms-settings.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.nexmo.com%2Fwp-content%2Fuploads%2F2019%2F10%2Fdefault-sms-settings.png" title="Default Nexmo SMS HTTP Method" alt="Default Nexmo SMS HTTP Method"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open up the &lt;code&gt;index.js&lt;/code&gt; file, and at the bottom, paste the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Reading the inbound SMS messages&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleRoute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;msisdn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;This is not a valid inbound SMS message!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;translateText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above snippet is the method we will pass into the routes. If the incoming message is using &lt;code&gt;POST&lt;/code&gt; it will use &lt;code&gt;req.body&lt;/code&gt;, and it will use &lt;code&gt;req.query&lt;/code&gt; for the &lt;code&gt;GET&lt;/code&gt; option. As long as the inbound payload is properly set up, the object will be sent along to the &lt;code&gt;translateText&lt;/code&gt; method to display the translation.&lt;/p&gt;

&lt;p&gt;Now you can add the route and proper &lt;code&gt;HTTP&lt;/code&gt; methods to the application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handleRoute&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handleRoute&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;405&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code will create the &lt;code&gt;GET&lt;/code&gt; and &lt;code&gt;POST&lt;/code&gt; methods to handle either from the inbound SMS webhook message. If any other method is used, a &lt;code&gt;405 - Method Not Allowed&lt;/code&gt; response will be returned.&lt;/p&gt;

&lt;p&gt;The webhook is ready to go and the final piece is the actual translations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Translation Method
&lt;/h3&gt;

&lt;p&gt;In the previous step we call &lt;code&gt;translateText&lt;/code&gt;. This step will create that method.&lt;/p&gt;

&lt;p&gt;Using the &lt;code&gt;@google-cloud/translate&lt;/code&gt; package is really straight forward. We first instantiate the &lt;code&gt;Translate&lt;/code&gt; class, which will give us the &lt;code&gt;translate&lt;/code&gt; method. This is called within the &lt;code&gt;translateText&lt;/code&gt; method and uses the &lt;code&gt;text&lt;/code&gt; field from the inbound SMS message object. The &lt;code&gt;target&lt;/code&gt; input is any two-letter code for the &lt;a href="https://cloud.google.com/translate/docs/languages" rel="noopener noreferrer"&gt;language to translate into&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;translationApi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Translate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;translateText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TARGET_LANGUAGE&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;translationApi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;translate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Original Text: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
           &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Translation: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
         &lt;span class="p"&gt;})&lt;/span&gt;
         &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
         &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can test out the functionality by starting the server, and sending a text message to the number you purchased earlier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node index.js
# Text "Hola" to your phone number

# expected response
Original Text: Hola
Translation: Hello
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Google Cloud Translation API does an amazing job at detecting the incoming language and processing the translation quickly. Have fun and try it out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;p&gt;The example above is just a small introduction to translation, but should be a good start to get you going. From here you can translate the inbound message, and then translate the outbound message into the correct language as well (future blog post, for sure).&lt;/p&gt;

&lt;p&gt;For a completed version of this tutorial you can find it at &lt;a href="https://github.com/nexmo-community/sms-translate-google-js" rel="noopener noreferrer"&gt;https://github.com/nexmo-community/sms-translate-google-js&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want to learn more about the Extend projects we have, you can visit &lt;a href="https://developer.nexmo.com/extend" rel="noopener noreferrer"&gt;https://developer.nexmo.com/extend&lt;/a&gt; to learn more.&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://www.nexmo.com/blog/2019/10/24/extending-nexmo-google-cloud-translation-api-dr" rel="noopener noreferrer"&gt;Translating SMS Messages Using Google Cloud’s Translation API&lt;/a&gt; appeared first on &lt;a href="https://www.nexmo.com" rel="noopener noreferrer"&gt;Nexmo Developer Blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>developer</category>
      <category>api</category>
      <category>nexmoextend</category>
      <category>node</category>
    </item>
    <item>
      <title>Extending Nexmo – Streaming Transcription Comparison</title>
      <dc:creator>Kelly Andrews</dc:creator>
      <pubDate>Tue, 10 Sep 2019 11:00:12 +0000</pubDate>
      <link>https://dev.to/vonagedev/extending-nexmo-streaming-transcription-comparison-hb1</link>
      <guid>https://dev.to/vonagedev/extending-nexmo-streaming-transcription-comparison-hb1</guid>
      <description>&lt;p&gt;In the world of communication, words are vital, and getting the right ones is incredibly important. Transcriptions of voice calls can help businesses understand emerging trends in content from sales and support phone calls.&lt;/p&gt;

&lt;p&gt;Transcription is the process of taking audio conversations and turning them into written words. In the past, this was handled by humans listening to a recording and typing out the words manually. This practice still exists today. There are now automated services that have emerged, allowing software developers to send audio files to services for a more immediate result.&lt;/p&gt;

&lt;p&gt;This work alone can provide incredible insights, but I’m focused specifically on streaming transcriptions where real-time information can provide another level of detail to your sales and support team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;This post is a comparison and overview of the four leading cloud provider’s streaming transcription services: &lt;a href="https://aws.amazon.com/transcribe/"&gt;Amazon Transcribe&lt;/a&gt;, &lt;a href="https://azure.microsoft.com/en-us/services/cognitive-services/speech-to-text/"&gt;Azure Cognitive Speech Service&lt;/a&gt;, &lt;a href="https://cloud.google.com/speech-to-text/"&gt;Google Cloud Speech-to-Text&lt;/a&gt;, and &lt;a href="https://www.ibm.com/watson/services/speech-to-text/"&gt;IBM Watson Speech-to-Text&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Using the &lt;a href="https://developer.nexmo.com/voice/voice-api/guides/websockets"&gt;Nexmo Voice API and WebSockets&lt;/a&gt;, I connected a voice call from my cell phone and streamed the audio to test the service. During the process, I took a few notes regarding things like features, ease of use, accuracy, and costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accuracy
&lt;/h2&gt;

&lt;p&gt;One of the more critical factors when selecting a transcription service is its accuracy. Having incorrect information would cause any data to be untrusted.&lt;/p&gt;

&lt;p&gt;I tested each service using an &lt;code&gt;8kHz&lt;/code&gt; sample rate using my cell phone. You can also use &lt;code&gt;16kHz&lt;/code&gt;, but in some cases, it’s actually less accurate. Using various phrases, I spoke at a relatively average rate of speech at a moderate volume. The room was also quiet enough to remove background noises.&lt;/p&gt;

&lt;p&gt;Every service transcribed the phrases I used with no issues, but some of it depended on how well I spoke. Unfortunately, any service struggles with lack of enunciation.&lt;/p&gt;

&lt;p&gt;Otherwise, you can feel reasonably confident with any one of these services to handle your transcriptions.&lt;/p&gt;

&lt;h3&gt;
  
  
  “Stand clear of the doors.”
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;IBM Watson Speech-to-Text – 90% (It couldn’t get “stand” no matter how clear I spoke)&lt;/li&gt;
&lt;li&gt;Azure Cognitive Speech Service – 100%&lt;/li&gt;
&lt;li&gt;Google Cloud Speech-to-Text – 100%&lt;/li&gt;
&lt;li&gt;Amazon Transcribe – 100%&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  “Shake well before serving”
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;IBM Watson Speech-to-Text – 100%&lt;/li&gt;
&lt;li&gt;Azure Cognitive Speech Service – 100%&lt;/li&gt;
&lt;li&gt;Google Cloud Speech-to-Text – 100%&lt;/li&gt;
&lt;li&gt;Amazon Transcribe – 100%&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  “Peter Piper picked a peck of pickled peppers.”
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;IBM Watson Speech-to-Text – 100%&lt;/li&gt;
&lt;li&gt;Azure Cognitive Speech Service – 100%&lt;/li&gt;
&lt;li&gt;Google Cloud Speech-to-Text – 100%&lt;/li&gt;
&lt;li&gt;Amazon Transcribe – 100%&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;p&gt;The feature sets for most of the services are very similar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uses Machine Learning for Accuracy&lt;/li&gt;
&lt;li&gt;Custom models for optimization&lt;/li&gt;
&lt;li&gt;Audio files and streaming&lt;/li&gt;
&lt;li&gt;Contextual formatting for proper nouns&lt;/li&gt;
&lt;li&gt;Punctuation support&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Language Support
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://cloud.google.com/speech-to-text/docs/languages"&gt;Google Cloud Speech-to-Text&lt;/a&gt; has far-and-away the highest number of supported languages at 120 and can auto-detect the language in most cases. The next closest language support is &lt;a href="https://docs.microsoft.com/en-us/azure/cognitive-services/speech-service/language-support"&gt;Azure Cognitive Speech Service&lt;/a&gt; with 30 and &lt;a href="https://cloud.ibm.com/docs/services/speech-to-text?topic=speech-to-text-models#modelsList"&gt;IBM Watson Speech-to-Text&lt;/a&gt; with 15. &lt;a href="https://docs.aws.amazon.com/transcribe/latest/dg/what-is-transcribe.html"&gt;Amazon Transcribe&lt;/a&gt; is most restrictive with only 5 languages available for streaming transcription (more available for audio files).&lt;/p&gt;

&lt;h2&gt;
  
  
  Ease of Use
&lt;/h2&gt;

&lt;p&gt;Each provider has their unique path to success. All of them provide getting started guides in various formats. However, they tend to either be for sending an audio file or capturing microphone input. While microphone input is the streaming method we need to use with the Nexmo WebSocket, it comes with some additional front end code that was unnecessary.&lt;/p&gt;

&lt;h3&gt;
  
  
  Google Cloud Speech-to-Text
&lt;/h3&gt;

&lt;p&gt;The Google SDK was simple to implement by creating a &lt;code&gt;SpeechClient&lt;/code&gt; with the provided SDK and the Google credentials file provided during the service account user.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;SpeechClient&lt;/code&gt; provides a method called &lt;code&gt;streamingRecognize&lt;/code&gt; which provides events.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const client = new speech.SpeechClient(); let request ={ config: { encoding: 'LINEAR16', sampleRateHertz: 8000, languageCode: 'en-US' }, interimResults: false }; const recognizeStream = client .streamingRecognize(request) .on('error', console.error) .on('data', data =&amp;gt; { console.dir(data, {depth: null}); });
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Google’s simplicity gets an advantage over other competitors. You can get up and running with little effort, and for me, that’s a huge win.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://cloud.google.com/speech-to-text/docs/"&gt;Google Cloud Speech-to-Text Documentation&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Azure/IBM
&lt;/h3&gt;

&lt;p&gt;Both IBM and Azure provide language-specific SDKs and plenty of getting started documentation to get you going, but the API direct call is straightforward to implement. These services can both be used with just connecting to an API route with the &lt;code&gt;wss://&lt;/code&gt; protocol and providing a key.&lt;/p&gt;

&lt;h4&gt;
  
  
  Azure Cognitive Speech Service
&lt;/h4&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wss://region.stt.speech.microsoft.com/speech/recognition/interactive/cognitiveservices/v1?format=simple&amp;amp;language=LANG\_CODE
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  IBM Watson Speech-to-Text
&lt;/h4&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wss://stream.watsonplatform.net/speech-to-text/api/v1/recognize?model=langage\_model
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;There are some additional headers to be provided, but you can find the documentation for each service to be a beneficial resource.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://cloud.ibm.com/apidocs/speech-to-text"&gt;IBM Watson Speech-to-Text Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/cognitive-services/speech-service/"&gt;Azure Cognitive Speech Service Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Amazon Transcribe
&lt;/h4&gt;

&lt;p&gt;I have to admit, AWS was the hardest for me to implement. The documentation had very few examples, and the SDK didn’t seem to support streaming services at all. When I first set out to build the Amazon Transcribe integration, HTTP/2 was the only protocol available and required signing every request sent to the server. Being a bit of a novice with AWS in general, this proved to be quite tricky for me.&lt;/p&gt;

&lt;p&gt;Where this story makes a great turn around, is when Developer Relations lead, &lt;a href="https://twitter.com/bwest"&gt;Brandon West&lt;/a&gt; stepped in, and wrote some sample code using a WebSocket connection and saved me. The sample code made things much more accessible, but the general authorization process and call signing make Amazon Transcribe a bit harder to implement in general.&lt;/p&gt;

&lt;p&gt;Here I used the &lt;code&gt;WebSocket&lt;/code&gt; Node package and created a signed URL to create the connection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let url = v4.createPresignedURL( 'GET', `transcribestreaming.${process.env.AWS_REGION}.amazonaws.com:8443`, '/stream-transcription-websocket', 'transcribe', crypto.createHash('sha256').update('', 'utf8').digest('hex'), { 'key': process.env.AWS\_ACCESS\_KEY\_ID, 'secret': process.env.AWS\_SECRET\_ACCESS\_KEY, 'protocol': 'wss', 'expires': 15, 'region': process.env.AWS\_REGION, 'query': `language-code=${process.env.LANG_CODE}&amp;amp;media-encoding=pcm&amp;amp;sample-rate=${process.env.SAMPLE_RATE}` } ); let socket = new WebSocket(url);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Amazon Transcribe is an excellent service, but if it’s not something you are accustomed to, the learning curve can be a challenge.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/transcribe/latest/dg/what-is-transcribe.html"&gt;Amazon Transcribe Documentation&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost
&lt;/h2&gt;

&lt;p&gt;All of the service providers offer a lite or free tier to get you started. The base cost is on the amount of audio time transcribed. The providers use different increments of time, so I normalized them in the table below to help you understand precisely the difference in costs.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Provider&lt;/th&gt;
&lt;th&gt;Free Tier&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;th&gt;Normalized Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://aws.amazon.com/transcribe/pricing/"&gt;Amazon Transcribe&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;60 min/month for 12 months&lt;/td&gt;
&lt;td&gt;$0.006/~10 seconds&lt;/td&gt;
&lt;td&gt;$0.036/minute&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://azure.microsoft.com/en-us/pricing/details/cognitive-services/speech-services/"&gt;Azure Cognitive Speech Service&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;5 audio hours free per month&lt;/td&gt;
&lt;td&gt;$1/audio hour&lt;/td&gt;
&lt;td&gt;$0.016/minute&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://cloud.google.com/speech-to-text/pricing"&gt;Google Cloud Speech-to-Text&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;60 minutes free&lt;/td&gt;
&lt;td&gt;$0.006/15 seconds&lt;/td&gt;
&lt;td&gt;$0.024/minute&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://www.ibm.com/cloud/watson-speech-to-text/pricing"&gt;IBM Watson Speech-to-Text&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;500 Minutes per Month&lt;/td&gt;
&lt;td&gt;$0.02/minute&lt;/td&gt;
&lt;td&gt;$0.02/minute&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;p&gt;Streaming transcription is a great way to provide insight in real-time. Each of the four leading cloud providers has great offerings with reliable, accurate speech-to-text services. Using Nexmo as the audio stream is a great extension that allows for more in-depth communication experiences for your customers.&lt;/p&gt;

&lt;p&gt;I highly recommend Google Speech-to-text as a solid pick. The price is competitive, and the service is robust and reliable. It’s easy to get set up and start using it immediately, which is a bonus.&lt;/p&gt;

&lt;p&gt;If you would like to try out any or all of these services, the Nexmo Extend team has created example code to help you get started.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/nexmo-community/voice-aws-transcribe"&gt;Amazon Transcribe&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nexmo-community/voice-microsoft-speechtotext"&gt;Azure Cognitive Speech Service&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nexmo-community/voice-google-speechtotext"&gt;Google Cloud Speech-to-Text&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nexmo-community/voice-watson-speechtotext"&gt;IBM Watson Speech-to-Text&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The post &lt;a href="https://www.nexmo.com/blog/2019/09/10/extending-nexmo-streaming-transcription-dr"&gt;Extending Nexmo – Streaming Transcription Comparison&lt;/a&gt; appeared first on &lt;a href="https://www.nexmo.com"&gt;Nexmo Developer Blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>developer</category>
      <category>amazonwebservices</category>
      <category>extendingnexmo</category>
      <category>googlecloudplatfor</category>
    </item>
  </channel>
</rss>
