{"id":2072,"date":"2021-06-21T11:37:37","date_gmt":"2021-06-21T11:37:37","guid":{"rendered":"https:\/\/lvboard.infostore.in.ua\/?p=2072"},"modified":"2021-06-21T11:37:37","modified_gmt":"2021-06-21T11:37:37","slug":"deploying-a-full-stack-node-js-react-app-for-free-with-begin","status":"publish","type":"post","link":"https:\/\/lvboard.infostore.in.ua\/?p=2072","title":{"rendered":"Deploying a full-stack Node.js + React app for free with Begin"},"content":{"rendered":"\n<p>Separating the backend and frontend has become the norm in developing full-stack applications. But there aren\u2019t many options out there to host a full-stack app on a single provider.<\/p>\n\n\n\n<!--more-->\n\n\n\n<p>In this post, we will see step by step how to deploy a full-stack JavaScript application using Node.js and React on Begin with Begin Data. Let\u2019s get the ball rolling!<\/p>\n\n\n\n<h2>Free options for hosting a JavaScript application<\/h2>\n\n\n\n<p>A true full-stack application would not only cover the backend and the frontend, but also incorporate the data storage layer. There aren\u2019t many options that provide a managed solution for all three pieces.<\/p>\n\n\n\n<p>There\u2019s just a handful of options if you want to quickly try out your idea without paying a dime.&nbsp;<a href=\"https:\/\/vercel.com\/\">Vercel<\/a>&nbsp;and&nbsp;<a href=\"https:\/\/qovery.com\/\">Qovery<\/a>&nbsp;are two that come to mind for handling both the backend and frontend.<\/p>\n\n\n\n<p>If you identify yourself as a frontend developer who mainly knows one language \u2014 JavaScript \u2014 setting up a database and understanding all the backend and data layer aspects might become overwhelming pretty fast. This is the area where&nbsp;<a href=\"https:\/\/begin.com\/\">Begin.com<\/a>&nbsp;shines. Let\u2019s see why.<\/p>\n\n\n\n<h2>Begin features<\/h2>\n\n\n\n<p>As a frontend developer, you want to write the frontend parts, but if need be, you could probably dabble a bit in the backend if you feel it is familiar territory.<\/p>\n\n\n\n<p>Begin provides unparalleled, ultra-usable abstractions on top of&nbsp;<a href=\"https:\/\/blog.logrocket.com\/aws-services-cheat-sheet\/\">popular AWS services<\/a>&nbsp;many of us are scared to configure and glue together, including&nbsp;<a href=\"https:\/\/aws.amazon.com\/lambda\/\">AWS Lambda<\/a>&nbsp;and&nbsp;<a href=\"https:\/\/aws.amazon.com\/dynamodb\/\">DynamoDB<\/a>. You can get from code to a working URL in 30 seconds \u2014 for free, at that.<\/p>\n\n\n\n<p>All this makes Begin very frontend-friendly. As they say on their homepage, \u201cBegin makes serverless absurdly easy.\u201d They also add, \u201cNo servers. No config. No sweat.\u201d Let\u2019s test out these claims.<\/p>\n\n\n\n<h2>How Architect (arc.codes) is related to Begin<\/h2>\n\n\n\n<p>Begin may provide us with highly usable abstractions on top of AWS Lambda, but it comes with its own opinions on how to use it.<\/p>\n\n\n\n<p>Begin is like a SaaS version of&nbsp;<a href=\"https:\/\/arc.codes\/\">Architect<\/a>. It is a serverless framework that helps you build massively scalable serverless applications. It is open source, and its&nbsp;<a href=\"https:\/\/arc.codes\/docs\/en\/guides\/get-started\/why-architect\">features<\/a>&nbsp;include the ability to work locally.<\/p>\n\n\n\n<p>Architect has a defined&nbsp;<a href=\"https:\/\/arc.codes\/docs\/en\/guides\/get-started\/project-layout\">project layout<\/a>&nbsp;and prescriptions on how to&nbsp;<a href=\"https:\/\/arc.codes\/docs\/en\/guides\/developer-experience\/sharing-code\">share code<\/a>&nbsp;between Lambda functions. With these opinions, Architect does make deploying, logging, and monitoring a breeze.<\/p>\n\n\n\n<p>In the next step, we will see how to build a simple news app that fetches the latest US news from sources like CNN, ABC News, and The Guardian.<\/p>\n\n\n\n<h2>Prerequisites<\/h2>\n\n\n\n<p>Before we dive into the code, below are some things you should know:<\/p>\n\n\n\n<ol><li>You are familiar with JavaScript, Node.js, and React in general<\/li><li>You know how AWS Lambda and serverless functions more broadly work<\/li><li>You have Node.js running on your local machine and are able to run basic npm commands<\/li><li>You are familiar with Git and GitHub<\/li><\/ol>\n\n\n\n<p>Next, we will look at how to build the news app.<\/p>\n\n\n\n<h2>Example App: Latest US news<\/h2>\n\n\n\n<p>By now, you know that our goal is to build a small news application that will show the latest US news from a number of sources. It will look like the example below:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img src=\"https:\/\/blog.logrocket.com\/wp-content\/uploads\/2021\/05\/latest-news-app-preview.png\" alt=\"Preview of Our Latest News App\" class=\"wp-image-47630\"\/><\/figure><\/div>\n\n\n\n<p>This example app will have two main parts: the backend written in Node.js and the frontend in React. The data for this news app will be stored in&nbsp;<a href=\"https:\/\/docs.begin.com\/en\/data\/begin-data\">Begin Data<\/a>, which is a very useful abstraction on top of DynamoDB. Time to get our hands dirty with some code now.<\/p>\n\n\n\n<h2>Getting started with Begin<\/h2>\n\n\n\n<p>To start using Begin, please go to the homepage, click the&nbsp;<strong>Sign up with GitHub<\/strong>&nbsp;button, and authorize with your GitHub account. Begin has a generous free plan that accommodates five free apps, so please do sign up with them.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img src=\"https:\/\/blog.logrocket.com\/wp-content\/uploads\/2021\/05\/begin-pricing-tiers.png\" alt=\"Begin's Pricing Tiers\" class=\"wp-image-47631\"\/><\/figure><\/div>\n\n\n\n<h3>Create a Node + React app from a Begin example<\/h3>\n\n\n\n<p>We will use a Begin example of Node.js and React to start with. We will later modify it to become our US news app.<\/p>\n\n\n\n<p>Head over to the Begin&nbsp;<a href=\"https:\/\/github.com\/begin-examples\/node-create-react-app\">Node + React example<\/a>&nbsp;app and click the&nbsp;<strong>Deploy to Begin<\/strong>&nbsp;button, as seen below:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img src=\"https:\/\/blog.logrocket.com\/wp-content\/uploads\/2021\/05\/begin-node-react-example.png\" alt=\"Begin's Node and React Starter Template on GitHub\" class=\"wp-image-47633\"\/><\/figure><\/div>\n\n\n\n<p>Since we are already logged in, it will take us to the following screen:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img src=\"https:\/\/blog.logrocket.com\/wp-content\/uploads\/2021\/05\/creating-app-github-repo.png\" alt=\"Creating Our Begin App as a GitHub Repo\" class=\"wp-image-47636\"\/><\/figure><\/div>\n\n\n\n<p>You will need to allow Begin to access your GitHub. When you click the&nbsp;<strong>Create app<\/strong>&nbsp;button, it will create the Begin app as a new repository on your GitHub account. In my case, it created&nbsp;<a href=\"https:\/\/github.com\/geshan\/us-news\">this open source GitHub repo<\/a>&nbsp;on my account.<\/p>\n\n\n\n<p>It will start the CI\/CD process and deploy the app on a unique Begin URL, as seen below:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img src=\"https:\/\/blog.logrocket.com\/wp-content\/uploads\/2021\/05\/ci-cd-process-begin.png\" alt=\"The CI\/CD Process Running in Begin\" class=\"wp-image-47638\"\/><\/figure><\/div>\n\n\n\n<p>You will need to wait 2\u20133 minutes for the build and deployment process to complete, then you can visit the staging environment of your new Begin app. It has a very simple API, which React calls to show its content.<\/p>\n\n\n\n<p>After some time, the build and deploy processes are done:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img src=\"https:\/\/blog.logrocket.com\/wp-content\/uploads\/2021\/05\/build-deploy-processes-complete-staging.png\" alt=\"Our Build and Deploy Processes Complete on Staging\" class=\"wp-image-47647\"\/><\/figure><\/div>\n\n\n\n<p>If we hit our staging URL, which, in my case, was&nbsp;<code><a href=\"https:\/\/whale-ls5-staging.begin.app\/\">https:\/\/whale-ls5-staging.begin.app\/<\/a><\/code>, we will see a basic React app:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img src=\"https:\/\/blog.logrocket.com\/wp-content\/uploads\/2021\/05\/basic-react-app-staging.png\" alt=\"Our Basic react App in Staging\" class=\"wp-image-47642\"\/><\/figure><\/div>\n\n\n\n<p>Hooray! Our basic React app with a super-simple Node.js backend is up and running on Begin.com.<\/p>\n\n\n\n<p>It will only deploy to production when we push a new tag on GitHub. Begin asks us to use&nbsp;<a href=\"https:\/\/semver.org\/\">SemVer<\/a>&nbsp;for releases with Git&nbsp;<a href=\"https:\/\/git-scm.com\/book\/en\/v2\/Git-Basics-Tagging\">tags<\/a>.<\/p>\n\n\n\n<p>Now we will move on to actually building our news API that will be consumed by React.<\/p>\n\n\n\n<h2>Replacing the dummy API with the news API<\/h2>\n\n\n\n<p>We currently have a dummy API for our example application available at&nbsp;<code>\/api<\/code>. It simply responds with a message&nbsp;<code>Hello&nbsp;from&nbsp;your&nbsp;Begin&nbsp;API!<\/code>. We will delete this API and add two new&nbsp;<code>GET<\/code>&nbsp;APIs.<\/p>\n\n\n\n<p>The first will be accessible at&nbsp;<code>\/api\/news<\/code>&nbsp;to get the latest news saved in Begin Data. The second can be reached at&nbsp;<code>\/api\/fetch-news<\/code>&nbsp;to fetch the news from sources\u2019 RSS feeds and save it in the Begin data table. Let\u2019s take a look at the code to do all this.<\/p>\n\n\n\n<p>First, clone the repository somewhere on your machine so you can edit it, then run&nbsp;<code>npm install<\/code>&nbsp;to get all the dependencies. To build these two new APIs, we will first remove the&nbsp;<code>http<\/code>&nbsp;section from the&nbsp;<code>package.json<\/code>&nbsp;file\u2019s&nbsp;<code>arc<\/code>&nbsp;section and make it look like the below:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">\"arc\": {\n    \"app\": \"react-hello\",\n    \"static\": {\n      \"folder\": \"build\",\n      \"spa\": true\n    }\n},<\/pre>\n\n\n\n<p>As the next step, we will delete the&nbsp;<code>api<\/code>&nbsp;folder present on the root:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">rm -rf api<\/pre>\n\n\n\n<p>If you want to delete it with a GUI, I leave that decision up to you.<\/p>\n\n\n\n<h3>Add the&nbsp;<code>app.arc<\/code>&nbsp;file<\/h3>\n\n\n\n<p>Subsequently, we will add an&nbsp;<code>app.arc<\/code>&nbsp;file that defines the routes and Begin data table we will use to store news. The&nbsp;<code>app.arc<\/code>&nbsp;file looks like this:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">@app\nreact-hello\n\n@static\nfolder build\n\n# json api\n@http\nget \/api\/news\nget \/api\/fetch-news\n\n@tables\ndata\n  scopeID *String\n  dataID **String\n  ttl TTL<\/pre>\n\n\n\n<p>A couple of important things to note here are:<\/p>\n\n\n\n<ol><li>We are defining two&nbsp;<code>GET<\/code>&nbsp;API endpoints,&nbsp;<code>\/api\/news<\/code>&nbsp;and&nbsp;<code>\/api\/fetch-news<\/code>, which will show the news and fetch the news from our defined sources and save it on Begin Data<\/li><li>We define a directive&nbsp;<code><a href=\"https:\/\/arc.codes\/docs\/en\/reference\/app.arc\/tables\">@tables<\/a><\/code>&nbsp;that tells Begin we want to add a table called&nbsp;<code>news<\/code>&nbsp;with a time to live (TTL) field. We will find out the use of the TTL field later on.<\/li><\/ol>\n\n\n\n<h3>Add the API routes and related files<\/h3>\n\n\n\n<p>For the API routes to function properly, we\u2019ll need the&nbsp;<code>rss-parser<\/code>&nbsp;module because we\u2019re fetching the news from the sources\u2019 RSS feeds. Install it with:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">npm i --save rss-parser<\/pre>\n\n\n\n<p>Then we will add the two files to serve the two API endpoints in the&nbsp;<code>http<\/code>&nbsp;folder, as below:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img src=\"https:\/\/blog.logrocket.com\/wp-content\/uploads\/2021\/05\/app-file-structure.png\" alt=\"Our App File Structure Highlighting Two New Files in the HTTP Folder\" class=\"wp-image-47644\"\/><\/figure><\/div>\n\n\n\n<p>The first file is&nbsp;<code>index.js<\/code>&nbsp;in the&nbsp;<code>get-api-fetch_news<\/code>&nbsp;folder. This is where most of the interesting things happen:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">const data = require('@begin\/data');\nconst Parser = require('rss-parser');\nconst parser = new Parser();\nconst table = 'news';\n\nfunction formatFeedStories(stories, source) {\n  const MAX_STORIES = 10;\n  let formattedStories = [];\n  let count = 0;\n  for (story of stories) {\n    formattedStories.push({ \n      headline: story.title.trim(), \n      url: story.link,\n      published_date: story.pubDate,\n      source });\n    if (count === MAX_STORIES - 1) {\n      break;\n    }\n    count++;\n  }\n\n  console.log(`Formatted ${formattedStories.length} storied from ${source}`, formattedStories);\n  return formattedStories;\n}\n\nasync function getStories(feedUrl, source) {\n  try {\n    const feed = await parser.parseURL(feedUrl);\n    return formatFeedStories(feed.items, source);\n  } catch (err) {\n    const errMessage = `Error while parsing feed from news stories for ${source}`;\n    console.log(errMessage, err);\n\n    return [];\n  }\n}\n\nasync function saveNewsFromSources() {\n  const newsSources = [\n    {\n      feedUrl: 'http:\/\/rss.cnn.com\/rss\/edition.rss',\n      source: 'CNN'\n    },\n    {\n      feedUrl: 'https:\/\/abcnews.go.com\/abcnews\/topstories',\n      source: 'ABC News'\n    },\n    {\n      feedUrl: 'https:\/\/www.theguardian.com\/us-news\/rss',\n      source: 'The Guardian'\n    }\n  ]\n  let totalStoriesSaved = 0;\n\n  for (newsSource of newsSources) {\n    const stories = await getStories(newsSource.feedUrl, newsSource.source);\n    const savedCount = await saveNews(stories);\n    console.log(`Saved ${savedCount} stories from ${newsSource.source}`);\n    totalStoriesSaved += savedCount;\n  }\n\n  return totalStoriesSaved;\n}\n\nasync function saveNews(stories) {\n  const storiesToInsert = [];\n  const ttl = (Date.now() \/ 1000) + (60 * 60 * 6); \/\/ 6 hours from now in seconds\n\n  for(story of stories) {\n    const key = story.url.slice(-50);\n    const newsExists = await data.get({table, key});\n    if (!newsExists) {\n      storiesToInsert.push({table, key, ttl, ...story});\n    }\n  }\n\n  if (storiesToInsert.length) {\n    await data.set(storiesToInsert);\n  }\n\n  return storiesToInsert.length;\n}\n\nexports.handler = async function http(req) {\n  try {\n    const noOfStoriesSaved = await saveNewsFromSources();\n    return {\n      statusCode: 200,\n      headers: {\n        'content-type': 'application\/json; charset=utf8'\n      },\n      body: JSON.stringify({message: `${noOfStoriesSaved} News stories fetched and saved!`})\n    }\n  } catch(e) {\n    console.log(`e: ${e.message}`, e);\n    return {\n      statusCode: 500,\n      headers: {\n        'content-type': 'application\/json; charset=utf8',\n      },\n      body: JSON.stringify({'message': `some error occured while fetching news, ${e.message}`})\n    }\n  }\n}<\/pre>\n\n\n\n<p>The main heavy lifting of the application is in this 100-line file. Let\u2019s run through the main points.<\/p>\n\n\n\n<p>The news sources\u2019 RSS feed URLs are defined in&nbsp;<code>saveNewsFromSources<\/code>. In our case, we\u2019re pulling from CNN, ABC News, and The Guardian. For each of these news sources, it gets the 10 latest stories in the&nbsp;<code>getStories<\/code>&nbsp;function.<\/p>\n\n\n\n<p>After that, it saves the stories in the&nbsp;<code>saveNews<\/code>&nbsp;function. This saves the stories in the&nbsp;<code>news<\/code>&nbsp;table with a time to live (TTL) of 6h only if it doesn\u2019t already exist. So the stories stay in the database for a maximum of 6h, and they are auto-deleted after their TTL expires.<\/p>\n\n\n\n<p>Another point to notice here is that we generate a unique key from the last 50 characters from the URL (N.B.,&nbsp;<a href=\"https:\/\/docs.begin.com\/en\/data\/begin-data#tables--keys\">keys<\/a>&nbsp;in Begin Data need to be a maximum of 50 characters). We use this same key to check whether the news already exists; if it exists, we don\u2019t save it again.<\/p>\n\n\n\n<p>We log things like the stories and the number of news stories saved for our own reference. We also log errors should any occur.<\/p>\n\n\n\n<p>Consequently, we will add the other&nbsp;<code>index.js<\/code>&nbsp;file in&nbsp;<code>http\/get-news-api<\/code>&nbsp;folder to fetch the news from the data store and serve it up as JSON.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">const data = require('@begin\/data');\n\nfunction pick(obj, attributes = []) {\n  return Object.entries(obj)\n    .filter(([key]) =&gt; attributes.includes(key))\n    .reduce((obj, [key, val]) =&gt; Object.assign(obj, { [key]: val }), {});\n}\n\nexports.handler = async function http (req) {\n  const newsStories = await data.get({table:'news', limit: 20});\n  let storiesToShow = [];\n\n  for (newsStory of newsStories) {\n    const pickedStory = pick(newsStory, ['headline', 'url', 'published_date', 'source']);\n    if (pickedStory.headline) {\n      storiesToShow.push(pickedStory);\n    }\n  }\n\n  const sortedStories = storiesToShow.sort((a, b) =&gt; new Date(b.published_date) - new Date(a.published_date));\n  return {\n    headers: {\n      'content-type': 'application\/json; charset=utf8',\n      'cache-control': 'no-cache, no-store, must-revalidate, max-age=0, s-maxage=0'\n    },\n    statusCode: 200,\n    body: JSON.stringify(sortedStories)\n  }\n}<\/pre>\n\n\n\n<p>This small 30-line file is pretty straightforward. It queries Begin Data to get 20 news stories. It only picks up the four fields from the response&nbsp;<code>headline<\/code>,&nbsp;<code>url<\/code>,&nbsp;<code>published_date<\/code>, and&nbsp;<code>source<\/code>. It does a quick sort based on the date to put the latest news first, then the sorted stores are sent out as JSON. Pretty easy!<\/p>\n\n\n\n<p>In the next section, we will see how the React code and CSS are changed to show the latest 20 news stories we pull from the Begin data table.<\/p>\n\n\n\n<h2>Call the news API from React<\/h2>\n\n\n\n<p>The example application already calls the&nbsp;<code>\/api<\/code>&nbsp;endpoint to render the dummy text, but we deleted the old API and added the new news APIs. As such, we need to change the code to call our APIs and show the latest news on the React app. We will change the&nbsp;<code>App.js<\/code>&nbsp;in&nbsp;<code>src<\/code>&nbsp;as follows:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">import React, { useState, useEffect } from 'react';\nimport logo from '.\/logo.svg';\nimport '.\/App.css';\n\nconst App = () =&gt; {\n  const [stories, setStories] = useState([]);\n  const [message, setMessage] = useState('loading...');\n  useEffect(() =&gt; {\n    async function fetchNewsStories () {\n      try {\n        await (await fetch('\/api\/fetch-news')).json();\n        const data = await (await fetch('\/api\/news')).json();\n        setStories(data)\n        const message = data.length ? '' : 'No stories found';\n        setMessage(message);\n      } catch (err) {\n        console.log(`err: ${err.message}`, err);\n        setMessage('could not fetch stories');\n      }\n    }\n    fetchNewsStories()\n  }, []);\n\n  return (\n    &lt;div className=\"App\"&gt;\n      &lt;header className=\"App-header\"&gt;\n        &lt;img src={logo} className=\"App-logo\" alt=\"logo\" \/&gt;\n        &lt;h2&gt;Latest News&lt;\/h2&gt;\n        {message}\n        &lt;div className=\"stories\"&gt;\n          {Array.isArray(stories) &amp;&amp; stories.map(story =&gt; &lt;h3&gt;&lt;a href={story.url} target=\"_blank\" rel=\"noreferrer\"&gt;{story.headline}&lt;\/a&gt; - {story.source}&lt;\/h3&gt;)}\n        &lt;\/div&gt;\n      &lt;\/header&gt;\n    &lt;\/div&gt;\n  );\n}\n\nexport default App;<\/pre>\n\n\n\n<p>Let\u2019s do a quick rundown of what the React app is doing. We\u2019re doing two things in the&nbsp;<code>fetchNewsStories<\/code>&nbsp;function inside the&nbsp;<code>useEffect<\/code>. The first is to call the API to fetch the news and write it to the datastore.<\/p>\n\n\n\n<p>Next, we call the get news API and set it as&nbsp;<code>stories<\/code>. The fetch news call is idempotent as it will add news that is not in the database with the unique key.<\/p>\n\n\n\n<p>The&nbsp;<code>stories<\/code>&nbsp;array variable is later looped with a&nbsp;<code>Map<\/code>&nbsp;and we show the headline and source as&nbsp;<code>H3<\/code>&nbsp;with a link to the news story. We show a loading message while the stories are loading, and if there\u2019s an error, we show a&nbsp;<code>could&nbsp;not&nbsp;fetch stories<\/code>&nbsp;message to the users.<\/p>\n\n\n\n<p>In addition, we will also remove&nbsp;<code>background-color:&nbsp;#282c34;<\/code>&nbsp;on line 12 and&nbsp;<code>color:&nbsp;white<\/code>&nbsp;on line 18 of&nbsp;<code>App.css<\/code>&nbsp;to make the news more readable.<\/p>\n\n\n\n<p>We can quickly test our app locally with&nbsp;<code>npm start<\/code>&nbsp;to see something like the below:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img src=\"https:\/\/blog.logrocket.com\/wp-content\/uploads\/2021\/05\/latest-news-app-preview.png\" alt=\"Preview of Our Latest News App\" class=\"wp-image-47630\"\/><\/figure><\/div>\n\n\n\n<p>Congratulations! Your latest news app is working. If you want to try out what the API looks like in your local, you can hit&nbsp;<code><a href=\"http:\/\/localhost:3333\/api\/news\">http:\/\/localhost:3333\/api\/news<\/a><\/code>&nbsp;to see the get news API\u2019s JSON response. If it\u2019s empty, first hit the fetch news API at&nbsp;<code><a href=\"http:\/\/localhost:3333\/api\/fetch-news\">http:\/\/localhost:3333\/api\/fetch-news<\/a><\/code>&nbsp;to get the latest news from all three sources.<\/p>\n\n\n\n<p>We\u2019ll need to fix the tests written with&nbsp;<code><a href=\"https:\/\/github.com\/substack\/tape\">tape<\/a><\/code>&nbsp;so that the test step in the deployment passes. To do so, in the&nbsp;<code>\/test<\/code>&nbsp;folder, we\u2019ll change lines 17\u201326 of the&nbsp;<code>api-test.js<\/code>&nbsp;file to look like this:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">test('get \/api\/news', async t =&gt; {\n  t.plan(1)\n  try {\n    let result = await tiny.get({url: `${base}\/api\/news`})\n    t.ok(result, 'Got API response', result.body);\n  } catch (err) {\n    t.fail(err)\n  }\n\n})<\/pre>\n\n\n\n<p>We changed the API path in the test and simply assert that we get a response back from the API. It\u2019s not a great test, but it lets us reach our goal of deploying the API.<\/p>\n\n\n\n<p>Now we will deploy it to Begin. To deploy the changes, we will commit and push them to GitHub. Main code changes are available as a&nbsp;<a href=\"https:\/\/github.com\/geshan\/us-news\/pull\/1\/files\">pull request<\/a>&nbsp;for your reference; test code changes are in a different pull request.<\/p>\n\n\n\n<h2>Deploy the news app on Begin<\/h2>\n\n\n\n<p>We will open a pull request for the news app. After the pull request is merged, it will auto-deploy these changes on the staging environment as seen below:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img src=\"https:\/\/blog.logrocket.com\/wp-content\/uploads\/2021\/05\/merging-deploying-pull-request.png\" alt=\"Merging and Deploying the Pull Request\" class=\"wp-image-47648\"\/><\/figure><\/div>\n\n\n\n<p>After that, if we check the staging URL, we can see the app working similar to our local. We can visit staging by clicking the&nbsp;<strong>Staging<\/strong>&nbsp;link in the top left of the above page.<\/p>\n\n\n\n<p>If we check the&nbsp;<strong>Data<\/strong>&nbsp;page, we can see that our news stories data is written on Begin Data as well:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img src=\"https:\/\/blog.logrocket.com\/wp-content\/uploads\/2021\/05\/data-table-begin-data.png\" alt=\"Our Data Table in Begin Data\" class=\"wp-image-47649\"\/><\/figure><\/div>\n\n\n\n<p>Finally, we will deploy a production release. Click the&nbsp;<strong>Deploy to Production<\/strong>&nbsp;button and select a version \u2014 I will go with&nbsp;<code>0.0.1<\/code>, with a release note of&nbsp;<code>0.0.1&nbsp;first release<\/code>&nbsp;\u2014 and click the&nbsp;<strong>Ship It!<\/strong>&nbsp;button:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img src=\"https:\/\/blog.logrocket.com\/wp-content\/uploads\/2021\/05\/indicating-release-version.png\" alt=\"Indicating Our Release Version\" class=\"wp-image-47655\"\/><\/figure><\/div>\n\n\n\n<p>Similar to staging, it will take its time to build, and it deploys by provisioning the resources for us:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img src=\"https:\/\/blog.logrocket.com\/wp-content\/uploads\/2021\/05\/build-deploy-processes-production.png\" alt=\"Building and Deploying Our App to Production\" class=\"wp-image-47656\"\/><\/figure><\/div>\n\n\n\n<p>All of these updates are available via the&nbsp;<strong>Activity<\/strong>&nbsp;link. After that, we can check how the app looks in production:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img src=\"https:\/\/blog.logrocket.com\/wp-content\/uploads\/2021\/05\/finished-app-production.png\" alt=\"Finished App in Production\" class=\"wp-image-47657\"\/><\/figure><\/div>\n\n\n\n<p>You can check my app\u2019s&nbsp;<a href=\"https:\/\/whale-ls5.begin.app\/\">production<\/a>&nbsp;version to see how it works.<\/p>\n\n\n\n<h2>Next steps<\/h2>\n\n\n\n<p>Begin provides other features, too, like scheduled functions. We could have used a scheduled function in place of the&nbsp;<code>fetch news<\/code>&nbsp;API that runs every 6h and fills up our news table. That is one of the reasons I used a TTL of 6h.<\/p>\n\n\n\n<p>You can also check out&nbsp;<a href=\"https:\/\/docs.begin.com\/en\/event-functions\/provisioning\">event functions<\/a>, which can replace a queue for any functionality that needs one. The example depicts an account verification email, which is a great candidate to use a queue, but it is solved very well by an event-based kind of approach.<\/p>\n\n\n\n<p>You might also want to explore more of Begin \u2014 for instance, mapping&nbsp;<a href=\"https:\/\/docs.begin.com\/en\/getting-started\/domains\/\">custom domains<\/a>&nbsp;is another great feature. All in all, Begin provides solid abstractions on top of AWS services without locking you in.<\/p>\n\n\n\n<h2>Conclusion<\/h2>\n\n\n\n<p>We saw how we can deploy a full-stack JavaScript app on Begin.com using Begin Data to store our data, too. Rather than using two or three services for data, backend, and frontend, we can utilize Begin to host a full application and its data on the same service. I hope you explore more Begin features like scheduled function and customs domains to easily deploy your idea and have it working with less effort.<\/p>\n\n\n\n<h2>Full visibility into production React apps<\/h2>\n\n\n\n<p>Debugging React applications can be difficult, especially when users experience issues that are difficult to reproduce. If you\u2019re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time,&nbsp;<a href=\"https:\/\/www2.logrocket.com\/react-performance-monitoring\" target=\"_blank\" rel=\"noreferrer noopener\">try LogRocket<\/a>.&nbsp;<a href=\"https:\/\/www2.logrocket.com\/react-performance-monitoring\" target=\"_blank\" rel=\"noreferrer noopener\"><\/a><a href=\"https:\/\/www2.logrocket.com\/react-performance-monitoring\" target=\"_blank\" rel=\"noreferrer noopener\"><\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/www2.logrocket.com\/react-performance-monitoring\" target=\"_blank\" rel=\"noreferrer noopener\">LogRocket<\/a>&nbsp;is like a DVR for web apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app&#8217;s performance, reporting with metrics like client CPU load, client memory usage, and more.<\/p>\n\n\n\n<p>The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.<\/p>\n\n\n\n<p>Modernize how you debug your React apps \u2014&nbsp;<a href=\"https:\/\/www2.logrocket.com\/react-performance-monitoring\" target=\"_blank\" rel=\"noreferrer noopener\">start monitoring for free<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Separating the backend and frontend has become the norm in developing full-stack applications. But there aren\u2019t many options out there to host a full-stack app on a single provider.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[30],"tags":[94,65],"_links":{"self":[{"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=\/wp\/v2\/posts\/2072"}],"collection":[{"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2072"}],"version-history":[{"count":1,"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=\/wp\/v2\/posts\/2072\/revisions"}],"predecessor-version":[{"id":2073,"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=\/wp\/v2\/posts\/2072\/revisions\/2073"}],"wp:attachment":[{"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2072"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2072"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2072"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}