{"id":14768,"date":"2023-08-28T18:20:02","date_gmt":"2023-08-29T01:20:02","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=14768"},"modified":"2023-08-31T11:21:04","modified_gmt":"2023-08-31T18:21:04","slug":"building-a-survey-app-with-netlify-and-couchbase","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/building-a-survey-app-with-netlify-and-couchbase\/","title":{"rendered":"Build a Survey App with Netlify and Couchbase"},"content":{"rendered":"<p><span style=\"font-weight: 400;\">The Couchbase DevRel team has been working with the <\/span><a href=\"https:\/\/badwebsite.club\/\"><span style=\"font-weight: 400;\">Bad Website Club<\/span><\/a><span style=\"font-weight: 400;\"> on <\/span><a href=\"https:\/\/www.freecodecamp.org\/\"><span style=\"font-weight: 400;\">freeCodeCamp <\/span><\/a><span style=\"font-weight: 400;\">materials.\u00a0<\/span><\/p>\n<p><i><span style=\"font-weight: 400;\">freeCodeCamp is a non-profit organization that consists of an interactive learning web platform, an online community forum, chat rooms, online publications and local organizations that intend to make learning software development accessible to anyone.<\/span><\/i><\/p>\n<p><i><span style=\"font-weight: 400;\">The Bad Website Club is an online community helping new learners in their programming journey.<\/span><\/i><\/p>\n<p><span style=\"font-weight: 400;\">We have been streaming to show fCC learners what could happen to their project in more &#8216;real-life\u2019 conditions. We started with the Responsive Web Design course, took some examples like the Survey form, completed them and pushed them to production. The whole series is streamed on YouTube, LinkedIn, Twitter and Twitch, and the recordings are available on this youtube playlist if you want to check it out: <\/span><a href=\"https:\/\/www.youtube.com\/watch?v=OkO1ZHH1N54&amp;list=PLcspbWiU9RutKoHwXID713a_GcTgeT6j6\"><span style=\"font-weight: 400;\" data-rich-links=\"{&quot;fple-t&quot;:&quot;New Couchbase Streams: Starting July 31st!&quot;,&quot;fple-u&quot;:&quot;https:\/\/www.youtube.com\/watch?v=OkO1ZHH1N54&amp;list=PLcspbWiU9RutKoHwXID713a_GcTgeT6j6&quot;,&quot;fple-mt&quot;:null,&quot;type&quot;:&quot;first-party-link&quot;}\">New Couchbase Streams: Starting July 31st!<\/span><\/a><\/p>\n<p><iframe loading=\"lazy\" title=\"New Couchbase Streams: Starting July 31st!\" width=\"900\" height=\"506\" src=\"https:\/\/www.youtube.com\/embed\/OkO1ZHH1N54?list=PLcspbWiU9RutKoHwXID713a_GcTgeT6j6\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe><\/p>\n<p><span style=\"font-weight: 400;\">I was personally streaming on the <\/span><a href=\"https:\/\/www.freecodecamp.org\/learn\/2022\/responsive-web-design\/build-a-survey-form-project\/build-a-survey-form\"><span style=\"font-weight: 400;\">Survey project<\/span><\/a><span style=\"font-weight: 400;\">. In this blog post series, I will show you all the additional steps you can do publish the code on GitHub, deploy the Survey online with Netlify, and storing its content on Couchbase Capella.<\/span><\/p>\n<h2>Step 1 &#8211; Create an HTML Form<\/h2>\n<p><span style=\"font-weight: 400;\">Getting a lot of inspiration from the FreeCodeCamp survey example (copy, paste, and trim), I get the following HTML form. It&#8217;s a bit simpler than the original one.<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true\">&lt;!DOCTYPE html&gt;\r\n&lt;html&gt;\r\n\u00a0\u00a0&lt;head&gt;\r\n\u00a0\u00a0\u00a0\u00a0&lt;link rel=\"stylesheet\" href=\".\/styles.css\" \/&gt;\r\n\u00a0\u00a0&lt;\/head&gt;\r\n\u00a0\u00a0&lt;body&gt;\r\n\u00a0\u00a0\u00a0\u00a0&lt;div class=\"container\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;header class=\"header\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;h1 id=\"title\" class=\"text-center\"&gt;Survey Form&lt;\/h1&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;p id=\"description\" class=\"description text-center\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Thank you for taking the time to help us improve the platform\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/p&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/header&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;form id=\"survey-form\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;div class=\"form-group\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;label id=\"name-label\" for=\"name\"&gt;Name&lt;\/label&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;input\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0type=\"text\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0name=\"name\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0id=\"name\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0class=\"form-control\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0placeholder=\"Enter your name\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0required\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/div&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;div class=\"form-group\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;label id=\"number-label\" for=\"number\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&gt;Age&lt;span class=\"clue\"&gt;(optional)&lt;\/span&gt;&lt;\/label\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;input\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0type=\"number\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0name=\"age\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0id=\"number\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0min=\"10\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0max=\"99\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0class=\"form-control\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0placeholder=\"Age\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/div&gt;\r\n\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;div class=\"form-group\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;p&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Would you recommend this awesome survey to a Friend ?\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/p&gt;\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;label\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&gt;&lt;input\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0name=\"recommend\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0value=\"recommend\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0type=\"checkbox\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0class=\"input-checkbox\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/&gt;yes&lt;\/label\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/div&gt;\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;div class=\"form-group\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;button type=\"submit\" id=\"submit\" class=\"submit-button\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Submit\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/button&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/div&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/form&gt;\r\n\u00a0\u00a0\u00a0\u00a0&lt;\/div&gt;\r\n\u00a0\u00a0&lt;\/body&gt;\r\n&lt;\/html&gt;<\/pre>\n<p><span style=\"font-weight: 400;\">The <em>styles.css<\/em> file is exactly the same than the original. <a href=\"https:\/\/survey-form.freecodecamp.rocks\/\">Open here<\/a> to see the survey form in action. You can open<\/span><span style=\"font-weight: 400;\"> in your browser, right click on the page and you should see something like <strong>view page source<\/strong> or <strong>inspect<\/strong>. Click on that and this will open a panel which shows the code of the page. While you are in this view you can click on link like <\/span><em><span style=\"font-weight: 400;\">style.css<\/span><\/em><span style=\"font-weight: 400;\"> or click on the <strong>styles<\/strong>\u00a0tab to view the CSS applied to certain elements as well.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">To test this code sample you can first clone this repository to your local computer using the terminal or you can download it as a zip file).<\/span><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/user-images.githubusercontent.com\/60084237\/260500053-9b4fb80b-f98e-4a0a-9ff0-09e76bede954.png\" alt=\"Screenshot of button in github where you can clone or download code\" \/><\/p>\n<p><span style=\"font-weight: 400;\">Go to your browser and on the top bar select <\/span><strong>file<\/strong><span style=\"font-weight: 400;\">, <\/span><strong>open<\/strong><span style=\"font-weight: 400;\">, than select the <em>index.html<\/em> file from the folder (or zip folder) that was downloaded. Take a look at your browser URL, it shows a path to a local file. And you should see something like this, that does not do anything when you click on submit.<\/span><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/github.com\/ldoguin\/freecodecamp-survey\/raw\/main\/images\/htmlform.png\" alt=\"The screenshot of the survey from created during the freecode camp Survery lesson\" \/><\/p>\n<p><span style=\"font-weight: 400;\">The question then is, how do we deploy it to the Internet, how do we make it do something? We need some backend code to be executed after the click. And then make that code store the form content in the database.<\/span><\/p>\n<h2>Step 2 &#8211; Git, Github, Netlify<\/h2>\n<p><span style=\"font-weight: 400;\">Let&#8217;s start by deploying this form live on the Internet. To that end we are going to use Netlify. First thing first, making sure that we have the <\/span><a href=\"https:\/\/docs.netlify.com\/cli\/get-started\/\"><span style=\"font-weight: 400;\">Netlify CLI<\/span><\/a><span style=\"font-weight: 400;\"> available, and that we are logged in. If it&#8217;s not installed, the fastest route is to type in your terminal:<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true\">npm install netlify-cli -g<\/pre>\n<p><span style=\"font-weight: 400;\">You wil find more details in the <a href=\"https:\/\/docs.netlify.com\/cli\/get-started\/\">Netlify get started docs<\/a>.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Typing <\/span><em><span style=\"font-weight: 400;\">netlify version<\/span><\/em><span style=\"font-weight: 400;\"> in my terminal currently gives me <\/span><em><span style=\"font-weight: 400;\">netlify-cli\/15.6.0 win32-x64 node-v18.5.0<\/span><\/em><span style=\"font-weight: 400;\">. So I know it&#8217;s installed and ready.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Then the next thing to do is type <\/span><em><span style=\"font-weight: 400;\">netlify login<\/span><\/em><span style=\"font-weight: 400;\"> in your terminal. It will take you through the Netflify sign in form.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Now everything should be ready to move to the deployment phase. But just to make sure we are going to test things locally. Because that&#8217;s what most developers do. To that end, type <\/span><span style=\"font-weight: 400;\">netlify dev<\/span><span style=\"font-weight: 400;\"> in your terminal.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">It should output the following in your terminal and open your form in your browser.<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true\">\u25c8 Netlify Dev \u25c8\r\n\u25c8 Ignored general context env var: LANG (defined in process)\r\n\u25c8 No app server detected. Using simple static server\r\n\u25c8 Unable to determine public folder to serve files from. Using current working directory\r\n\u25c8 Setup a netlify.toml file with a [dev] section to specify your dev server settings.\r\n\u25c8 See docs at: https:\/\/cli.netlify.com\/netlify-dev#project-detection\r\n\u25c8 Running static server from \"freecodecamp-survey\"\r\n\u25c8 Setting up local development server\r\n\r\n\u25c8 Static server listening to 3999\r\n\r\nAdding local .netlify folder to .gitignore file...\r\n\r\n\u00a0\u00a0\u00a0\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\r\n\u00a0\u00a0\u00a0\u2502 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u2502\r\n\u00a0\u00a0\u00a0\u2502 \u00a0 \u25c8 Server now ready on https:\/\/localhost:8888 \u00a0 \u2502\r\n\u00a0\u00a0\u00a0\u2502 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u2502\r\n\u00a0\u00a0\u00a0\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518<\/pre>\n<p><span style=\"font-weight: 400;\">If you take a look at the browser URL bar again, you will see that it is different. It looks like a webite address, not a local file. Congratulations, you just run your first local server, serving your HTML and CSS file, using N<\/span><span style=\"font-weight: 400;\">etlify dev<\/span><span style=\"font-weight: 400;\">! You have a website running on your machine. Now let&#8217;s make this accessible to everyone on Internet, both the source code and the site itself.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Go to GitHub (or GitLab, or Heptapod, or any other code source hosting solutions, there are others out there!) and create a new Repository. Visit<\/span><a href=\"https:\/\/github.com\/new\"> <span style=\"font-weight: 400;\">https:\/\/github.com\/new<\/span><\/a><span style=\"font-weight: 400;\"> for Github. You are now in the repo wizard creation. I have only setup my organization, my repo name and a description than clicked on the <\/span><i><span style=\"font-weight: 400;\">Create Repository<\/span><\/i><span style=\"font-weight: 400;\"> button.<\/span><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/github.com\/ldoguin\/freecodecamp-survey\/raw\/main\/images\/githubRepoCreation.png\" alt=\"A screenshot of Github's repository creation wizard\" \/><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/github.com\/ldoguin\/freecodecamp-survey\/raw\/main\/images\/intialGithubRepo.png\" alt=\"A screenshot of a newly intitialized Github repo\" \/><\/p>\n<p><span style=\"font-weight: 400;\">It will give you all the instructions needed to convert your working folder in a <em>git<\/em> repo, and link it to your GitHub project. This is what I typed in my terminal (you can either copy and paste the below into your terminal or press enter after each line of the below to have it execute. Note, you will have to change line 6 to be your project repository URL):<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true\">echo \"# myproject\" &gt;&gt; README.md\r\ngit init\r\ngit add README.md\r\ngit commit -m \"first commit\"\r\ngit branch -M main\r\ngit remote add origin https:\/\/github.com\/ldoguin\/myproject.git\r\ngit push -u origin main<\/pre>\n<p><span style=\"font-weight: 400;\">This is the resulting terminal output:<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true \">[C:\\Code\\Couchbase\\myproject] $ echo \"# myproject\" &gt;&gt; README.md\r\n[C:\\Code\\Couchbase\\myproject] $ ls\r\n\r\n\u00a0\u00a0\u00a0\u00a0Directory: C:\\Code\\Couchbase\\myproject\r\n\r\nMode \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 LastWriteTime \u00a0 \u00a0 \u00a0 \u00a0 Length Name\r\n---- \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ------------- \u00a0 \u00a0 \u00a0 \u00a0 ------ ----\r\n-a----\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 8\/4\/2023\u00a0 12:11 PM \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 28 README.md\r\n\r\n[C:\\Code\\Couchbase\\myproject] $ git init\r\nhint: Using 'master' as the name for the initial branch. This default branch name\r\nhint: is subject to change. To configure the initial branch name to use in all\r\nhint: of your new repositories, which will suppress this warning, call:\r\nhint:\r\nhint: \u00a0 git config --global init.defaultBranch &lt;name&gt;\r\nhint:\r\nhint: Names commonly chosen instead of 'master' are 'main', 'trunk' and\r\nhint: 'development'. The just-created branch can be renamed via this command:\r\nhint:\r\nhint: \u00a0 git branch -m &lt;name&gt;\r\nInitialized empty Git repository in C:\/Users\/Laurent Doguin\/Documents\/Couchbase\/myproject\/.git\/\r\n[C:\\Code\\Couchbase\\myproject] $ git config --global init.defaultBranch main\r\n[C:\\Code\\Couchbase\\myproject] $ git branch -m main\r\n[C:\\Code\\Couchbase\\myproject] $ git add .\\README.md .\\index.html .\\styles.css\r\n[C:\\Code\\Couchbase\\myproject] $ git commit -m \"first commit\"\r\n[main (root-commit) 356ece7] first commit\r\n\u00a03 files changed, 245 insertions(+)\r\n\u00a0create mode 100644 README.md\r\n\u00a0create mode 100644 index.html\r\n\u00a0create mode 100644 styles.css\r\n[C:\\Code\\Couchbase\\myproject] $ git remote add origin https:\/\/github.com\/ldoguin\/myproject.git\r\n[C:\\Code\\Couchbase\\myproject] $ git push -u origin main\r\nEnumerating objects: 5, done.\r\nCounting objects: 100% (5\/5), done.\r\nDelta compression using up to 8 threads\r\nCompressing objects: 100% (4\/4), done.\r\nWriting objects: 100% (5\/5), 1.95 KiB | 999.00 KiB\/s, done.\r\nTotal 5 (delta 0), reused 0 (delta 0), pack-reused 0\r\nTo https:\/\/github.com\/ldoguin\/myproject.git\r\n\u00a0* [new branch]\u00a0 \u00a0 \u00a0 main -&gt; main\r\nbranch 'main' set up to track 'origin\/main'.\r\n[C:\\Code\\Couchbase\\myproject] $<\/pre>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400;\">Now if I go back to the Github page and reload it, this what I see:<\/span><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/github.com\/ldoguin\/freecodecamp-survey\/raw\/main\/images\/firstCommitReo.png\" alt=\"A screenshot of the github repository after an intial commit was pushed\" \/><\/p>\n<p><span style=\"font-weight: 400;\">Congratulations, your code is now available on Github, for everyone to see, learn from, contribute to. It&#8217;s now time for Production! Let&#8217;s make that website live \ud83d\udcaa<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Go ahead and visit<\/span><a href=\"https:\/\/app.netlify.com\/start\/deploy\"> <span style=\"font-weight: 400;\">https:\/\/app.netlify.com\/start\/deploy<\/span><\/a><span style=\"font-weight: 400;\">. This will get you to Netify&#8217;s new project wizard. You will see various buttons to help you start, GitHub, GitLab, Bitbucket, AzureDevops. Let&#8217;s click on GitHub.<\/span><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/github.com\/ldoguin\/freecodecamp-survey\/raw\/main\/images\/netlifyWizard.png\" alt=\"A screenshot of the Netlify Wizard for new project creation\" \/><\/p>\n<p><span style=\"font-weight: 400;\">You will see a couple windows asking you to link your GitHub profile to Netlify. Go ahead and proceed, it will take you to the following page.<\/span><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/github.com\/ldoguin\/freecodecamp-survey\/raw\/main\/images\/netlifyWizard2.png\" alt=\"A screenshot of the second step of Netlify's project creation wizard after picking Github\" \/><\/p>\n<p><span style=\"font-weight: 400;\">Netlify is telling me I have no Netlify app installed on any GitHub org. Click on <\/span><strong>Configure Netlify on GitHub<\/strong><span style=\"font-weight: 400;\">, it will open a poup window asking you to select the GitHub org you want to install Netlify in, and which repo to give it access to.<\/span><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/github.com\/ldoguin\/freecodecamp-survey\/raw\/main\/images\/ghAuthz.png\" alt=\"A screenshot of Github's authorization matrix\" \/><\/p>\n<p><span style=\"font-weight: 400;\">I leave the default and proceed to the next step. From now on you should see every repo in your GitHub account.<\/span><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/github.com\/ldoguin\/freecodecamp-survey\/raw\/main\/images\/NetlifyProjectList.png\" alt=\"A screenshot of Netlify's project List showing linked Github project \" \/><\/p>\n<p><span style=\"font-weight: 400;\">I will leave the default and click on <\/span><span style=\"font-weight: 400;\"><strong>Deploy <\/strong><\/span><span style=\"font-weight: 400;\"><strong>myproject<\/strong><\/span><i><span style=\"font-weight: 400;\">:<\/span><\/i><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/github.com\/ldoguin\/freecodecamp-survey\/raw\/main\/images\/netlifyConfigureroject.png\" alt=\"A screenshot of the default Netlify project configuration\" \/><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400;\">You will see a link to your newly deployed on the internet website, for me it&#8217;s <\/span><em><span style=\"font-weight: 400;\">https:\/\/jolly-sfogliatella-3e6c07.netlify.app\/<\/span><\/em><span style=\"font-weight: 400;\">. Netlify provides sandboxes environment under the <\/span><em><span style=\"font-weight: 400;\">netlify.app<\/span><\/em><span style=\"font-weight: 400;\"> domain for you to deploy things without having your own domain name.<\/span><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/github.com\/ldoguin\/freecodecamp-survey\/raw\/main\/images\/netlifyProjectCreatedWiz.png\" alt=\"A screenshot of a newly created Project\" \/><\/p>\n<p><span style=\"font-weight: 400;\">Congratulations, your website is now live on the Internet. Take a minute to celebrate \ud83c\udf89.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Now we can link this Netlify project by entering <\/span><em><span style=\"font-weight: 400;\">netlify link<\/span><\/em><span style=\"font-weight: 400;\"> in the terminal. A list of options will be offered. Select the default one, which should be <\/span><em><span style=\"font-weight: 400;\">Use current git remote origin (https:\/\/github.com\/yourOrg\/yourProject)<\/span><\/em><span style=\"font-weight: 400;\">. Because you have deployed through GitHub, Netlify has the git information of your repo and can infer which project to use (and also at that point you probably have only one project). This is what the output looks for me:<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true\">[C:\\Code\\Couchbase\\myproject] $ netlify link\r\n\r\nnetlify link will connect this folder to a site on Netlify\r\n\r\n? How do you want to link this folder to a site? Use current git remote origin (https:\/\/github.com\/ldoguin\/myproject)\r\n\r\nLooking for sites connected to 'https:\/\/github.com\/ldoguin\/myproject'...\r\n\r\nDirectory Linked\r\n\r\nAdmin url: https:\/\/app.netlify.com\/sites\/jolly-sfogliatella-3e6c07\r\nSite url:\u00a0 https:\/\/jolly-sfogliatella-3e6c07.netlify.app\r\n\r\nYou can now run other `netlify` cli commands in this directory\r\n[C:\\Code\\Couchbase\\myproject] $<\/pre>\n<p>We can try a couple things now. I am going add a \ud83d\udc3c emoji to my form because why not. In <em>index.html<\/em>, I am modifying line 9 from this: <em>&lt;h1 id=&#8221;title&#8221; class=&#8221;text-center&#8221;&gt;Survey Form&lt;\/h1&gt;<\/em> to this <em>&lt;h1 id=&#8221;title&#8221; class=&#8221;text-center&#8221;&gt;Survey Form \ud83d\udc3c&lt;\/h1&gt;<\/em><\/p>\n<p><span style=\"font-weight: 400;\">I then save the file, and push this changes to Github. Then, in the terminal, I type <\/span><em><span style=\"font-weight: 400;\">netlify open:site<\/span><\/em><span style=\"font-weight: 400;\">:<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true\">[C:\\Code\\Couchbase\\myproject] $ git add .\\index.html\r\n[C:\\Code\\Couchbase\\myproject] $ git commit -m\"Panda\"\r\n[main caa6f87] Panda\u00a0\r\n\u00a01 file changed, 1 insertion(+), 1 deletion(-)\r\n[C:\\Code\\Couchbase\\myproject] $ git push\r\nEnumerating objects: 5, done.\r\nCounting objects: 100% (5\/5), done.\r\nDelta compression using up to 8 threads\r\nCompressing objects: 100% (3\/3), done.\r\nWriting objects: 100% (3\/3), 360 bytes | 180.00 KiB\/s, done.\r\nTotal 3 (delta 1), reused 0 (delta 0), pack-reused 0\r\nremote: Resolving deltas: 100% (1\/1), completed with 1 local object.\r\nTo https:\/\/github.com\/ldoguin\/myproject.git\r\n\u00a0\u00a0\u00a0356ece7..8a2ebe2\u00a0 main -&gt; main\r\n[C:\\Code\\Couchbase\\myproject] $ netlify open:site\u00a0\u00a0\r\nOpening \"jolly-sfogliatella-3e6c07\" site url:\r\n&gt; https:\/\/jolly-sfogliatella-3e6c07.netlify.app<\/pre>\n<p>Something very cool is happening. Because your GitHub repo is linked to Netlify, a new deployment will be automatically done by Netlify. So when opening the website, you will see the Panda &lt;3.<\/p>\n<p><span style=\"font-weight: 400;\">At that point we have a Github Repository that holds our code, that is integrated to Netlify, that will automatically create new deployment when you push new code. And we also have a configured <\/span><span style=\"font-weight: 400;\">netlify<\/span><span style=\"font-weight: 400;\"> CLI in our working folder. We are ready to write backend code!<\/span><\/p>\n<h2>Step 3 &#8211; Backend<\/h2>\n<p><span style=\"font-weight: 400;\">In this chapter we will answer the following question: What happens when someone fill the form and click on <strong>submit<\/strong> ?<\/span><\/p>\n<p><span style=\"font-weight: 400;\">The answer right now is: Nothing. Let&#8217;s change that. By writing some JavaScript. We are going to display a popup alert when someone enters valid information and click on <strong>Submit<\/strong>. In your <em>index.html<\/em> file you will put the following <em>&lt;script&gt;<\/em> code between the last closing div tag <\/span><em><span style=\"font-weight: 400;\">&lt;\/div&gt;<\/span><\/em><span style=\"font-weight: 400;\"> and before the closing body tag <\/span><em><span style=\"font-weight: 400;\">&lt;\/body&gt;<\/span><\/em><span style=\"font-weight: 400;\">.<\/span><span style=\"font-weight: 400;\">\u00a0<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true\">&lt;script&gt;\r\n\u00a0\u00a0const form = document.getElementById('survey-form'); &lt;1&gt;\r\n\u00a0\u00a0form.addEventListener('submit', handleForm); &lt;2&gt;\r\n\r\n\u00a0\u00a0async function handleForm(e) {\r\n\u00a0\u00a0\u00a0\u00a0e.preventDefault() &lt;3&gt;\r\n\u00a0\u00a0\u00a0\u00a0alert(\"Form Submission !\") &lt;4&gt;\r\n\u00a0\u00a0}\r\n\r\n\u00a0\u00a0&lt;\/script&gt;<\/pre>\n<p>&nbsp;<\/p>\n<pre class=\"nums:false lang:default decode:true\">&lt;1&gt; Get the Dom element representing the form by using its id\r\n&lt;2&gt; Each time the submit event occurs, run the handleForm function\r\n&lt;3&gt; The natural behavior of a form submission is to reload the page, we don't need that, hence we prevent the default behavior to happen\r\n&lt;4&gt; The alert function display a popup with a message<\/pre>\n<p>If you save your code and reload the page, fill the form, click on <strong>submit<\/strong>, you should see something like this:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/github.com\/ldoguin\/freecodecamp-survey\/raw\/main\/images\/formSubmission.png\" alt=\"A screenshot of a sucessfull form submission\" \/><\/p>\n<p><span style=\"font-weight: 400;\">Now that we have something happening when a user submits the form, let&#8217;s go a bit further. We want to look at the content of the form and make sure we can get the right data in JSON. We want a string for the name, and integer for the age and a boolean for the recommendation.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">And it turns out that the HTML checkbox is not playing nice. The value it gives by default is no value, and once checked it gives the content of the value field. We are going to add another input field, hidden, to make sure the default value will be False.<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true\"> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;label&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;input\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0id=\"hiddenRecommend\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0name=\"recommend\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0value=\"false\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0type=\"hidden\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;input\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0id=\"recommend\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0name=\"recommend\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0value=\"true\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0type=\"checkbox\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0class=\"input-checkbox\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/&gt;yes&lt;\/label&gt;<\/pre>\n<p><span style=\"font-weight: 400;\">Now about the JavaScript Code, the are some interesting new lines to look into.<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true\"> const form = document.getElementById('survey-form');\r\n\u00a0\u00a0form.addEventListener('submit', handleForm);\r\n\r\n\u00a0\u00a0async function handleForm(e) { &lt;1&gt;\r\n\u00a0\u00a0\u00a0\u00a0e.preventDefault()\r\n\u00a0\u00a0\u00a0\u00a0\r\n\u00a0\u00a0\u00a0\u00a0const data = new FormData(e.target); &lt;1&gt;\r\n\u00a0\u00a0\u00a0\u00a0const value = Object.fromEntries(data.entries()); &lt;2&gt;\r\n\u00a0\u00a0\u00a0\u00a0const details = `name: ${value.name}\\nage: ${value.age}\\nrecommend: ${value.recommend}`; &lt;3&gt;\r\n\u00a0\u00a0\u00a0\u00a0console.log(details); &lt;4&gt;\r\n\u00a0\u00a0}<\/pre>\n<pre class=\"nums:false lang:default decode:true\">&lt;1&gt; The parameter of the handleForm function is an object(e) with a field called target. This target can be transform into a FormData object.\r\n&lt;2&gt; The FormData object can be transformed into a JSON object.\r\n&lt;3&gt; Now that we have a JSON object we can print out the values we are interested in.\r\n&lt;4&gt; This time instead of displaying an alert box, we are logging the details string to the console. The console can be accessed through your browser's dev tools. It is great for debugging.<\/pre>\n<p>With that being sorted, let&#8217;s get serious and start creating a Netlify function. Enter <em>netlify function:create<\/em> in your terminal. You should see something like:<\/p>\n<pre class=\"nums:false lang:default decode:true\">[C:\\Code\\Couchbase\\myproject] $ netlify function:create\r\n? Select the type of function you'd like to create Serverless function (Node\/Go)\r\n\u25c8 functions directory not specified in netlify.toml or UI settings\r\n? Enter the path, relative to your site\u2019s base directory in your repository, where your functions should live: netlify\/functions\r\n\u25c8 updating site settings with netlify\/functions\r\n\u25c8 functions directory netlify\/functions updated in site settings\r\n\u25c8 functions directory netlify\/functions does not exist yet, creating it...\r\n\u25c8 functions directory netlify\/functions created\r\n? Select the language of your function JavaScript\r\n? Pick a template javascript-hello-world\r\n? Name your function: saveform\r\n\u25c8 Creating function saveform\r\n\u25c8 Created netlify\\functions\\saveform\\saveform.js\r\n[C:\\Code\\Couchbase\\myproject] $<\/pre>\n<p><span style=\"font-weight: 400;\">Select <strong>Serverless<\/strong> function, leaves the default for the next question about path, keep JavaScript as the language, keep the default <em>hello-world<\/em> template, than give a name to your function. Mine is called <\/span><em><span style=\"font-weight: 400;\">saveform<\/span><\/em><span style=\"font-weight: 400;\">. This will generate new files in the netlify folder. If you run <\/span><em><span style=\"font-weight: 400;\">netlify dev<\/span><\/em><span style=\"font-weight: 400;\"> now, you will see new lines in the logs:<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true\">Loaded function saveform https:\/\/localhost:8888\/.netlify\/functions\/saveform.\r\n\u25c8 Functions server is listening on 62431<\/pre>\n<p>This means that our netlify dev server is also serving our newly created function. Take a look at the newly generated file <em>.\/netlify\/functions\/saveform\/saveform.js<\/em>.<\/p>\n<pre class=\"nums:false lang:default decode:true\">\/\/ Docs on event and context https:\/\/docs.netlify.com\/functions\/build\/#code-your-function-2\r\nconst handler = async (event) =&gt; { &lt;1&gt;\r\n\u00a0\u00a0try {\r\n\u00a0\u00a0\u00a0\u00a0const subject = event.queryStringParameters.name || 'World' &lt;2&gt;\r\n\u00a0\u00a0\u00a0\u00a0return {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0statusCode: 200,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0body: JSON.stringify({ message: `Hello ${subject}` }), &lt;3&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ \/\/ more keys you can return:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ headers: { \"headerName\": \"headerValue\", ... },\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ isBase64Encoded: true,\r\n\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0} catch (error) {\r\n\u00a0\u00a0\u00a0\u00a0return { statusCode: 500, body: error.toString() } &lt;4&gt;\r\n\u00a0\u00a0}\r\n}\r\n\r\nmodule.exports = { handler }<\/pre>\n<pre class=\"nums:false lang:default decode:true\">&lt;1&gt; the signature of the function is aysynchronous (the async keyword),and has an event parameter. Asynchronous means some code inside the function can be asynchronous and we can wait for the code to be executed with the await keyword, instead of managing the JavaScript Promess object traditionally returned by async functions.\r\n&lt;2&gt; the `event` object has some properties and methods, like `queryStringParameters` that allows us to get the name query param\r\n&lt;3&gt; this function must return a JSON object with an HTTP status code and an Object body. If everything worked well, we return a JSON body containing a message field and the code 200. Code starting with 2 means things went well.\r\n&lt;4&gt; If things went wrong, we return the status code 500. Code starting with 5 means something went wrong on the server. And the body field will contain the error.<\/pre>\n<p>Let&#8217;s try it out by calling this function when the user clicks on <strong>submit<\/strong>. Just add the following code after the last <em>console.log<\/em> call:<\/p>\n<pre class=\"nums:false lang:default decode:true\">  \u00a0\u00a0console.log(details);\r\n\u00a0\r\n \u00a0\u00a0\u00a0const response = await fetch(\"\/.netlify\/functions\/saveform\", { &lt;1&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0method: 'GET', &lt;2&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0headers: { &lt;3&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0'Content-Type': 'application\/json',\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0},\r\n\u00a0\u00a0\u00a0\u00a0})\r\n\u00a0\u00a0\u00a0\u00a0if (response.status == 200) { &lt;4&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0console.log(await response.text());\r\n\u00a0\u00a0\u00a0\u00a0}<\/pre>\n<pre class=\"nums:false lang:default decode:true\">&lt;1&gt; fetch is the method you can call to send an HTTP request to a server. Here we are sending a request to `\/.netlify\/functions\/saveform`. Notice the await keyword that means this method usually returns a promess. Here we are just assign the result of the promess to the field response.\r\n&lt;2&gt; HTTP request have methods, sometime also known as HTTP verbs. Here we are not modifying anything on the server, we are retrieving information, so we are using the method GET\r\n&lt;3&gt; HTTP requests have [headers](https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Headers\/Content-Type). They provide additional metadata like the Content-type, here set to `application\/json`. What it means is that we are manipulating JSON. `application\/text` would mean we are manipulating any form of text. These are called [Mime types or Media type](https:\/\/developer.mozilla.org\/en-US\/docs\/Glossary\/MIME_type).\r\n&lt;4&gt; We are testing the status code returned by the server. If it's 200, it means everything went well. We have a message to display in the console.<\/pre>\n<p><span style=\"font-weight: 400;\">Add, commit and push. <\/span><em><span style=\"font-weight: 400;\">netlify open:admin<\/span><\/em><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/github.com\/ldoguin\/freecodecamp-survey\/raw\/main\/images\/netlifyDeployList.png\" alt=\"A screenshot showing the Netlify site administrator overview, with the list of all deployments already done\" \/><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/github.com\/ldoguin\/freecodecamp-survey\/raw\/main\/images\/netlifyFunctionReturnCall.png\" alt=\"A screenshot of the form page and the developer tools opened, showing the message returned by the Netlify function\" \/><\/p>\n<p><span style=\"font-weight: 400;\">At this point, you have a frontend and a backend deployed, on the Internet. But all we are doing is calling the default function created by Netlify&#8217;s wizard. The next step is to send the content of the form to that function, and store it in a database.<\/span><\/p>\n<h2>Step 4 &#8211; Database<\/h2>\n<p><span style=\"font-weight: 400;\">First thing to do is figure out how to send the form details to the function. This requires us to change our GET method to a POST method. These things are called HTTP request methods, sometimes reffered to as HTTP verbs. You can take a look at the full list on<\/span><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Methods\"> <span style=\"font-weight: 400;\">MDN<\/span><\/a><span style=\"font-weight: 400;\">. A Get method request is used to only retrieve data. A post method request is used to create or change data. This is exactly what we want. We want to create a new entry in our Dababase when someone submits a form. An HTTP request has a method, some headers(Metadata about your requests, here we are saying the request will be JSON content with the Content-Typ header), and a body. The body of our request will be JSON text.<\/span><\/p>\n<pre class=\"nums:false lang:js decode:true\"> \u00a0\u00a0const response = await fetch(\"\/.netlify\/functions\/saveform\", {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0method: 'POST', &lt;1&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0headers: {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0'Content-Type': 'application\/json',\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0},\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0body: JSON.stringify(value), &lt;2&gt;\r\n\u00a0\u00a0\u00a0\u00a0})<\/pre>\n<pre class=\"nums:false lang:default decode:true\">&lt;1&gt; We change the HTTP method to POST because we want to change something instead of just retrieving information. \r\n&lt;2&gt; A request can also have a body. Here we are sending a text version of our JSON object.<\/pre>\n<p><span style=\"font-weight: 400;\">Our frontend HTTP request to our backend is changed, now we need to adapt the backend code.<\/span><\/p>\n<pre class=\"nums:false lang:js decode:true\">const handler = async (event) =&gt; {\r\n\u00a0\u00a0try {\r\n\u00a0\u00a0\u00a0\u00a0var data = JSON.parse(event.body); &lt;1&gt;\r\n\u00a0\u00a0\u00a0\u00a0return {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0statusCode: 200,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0body: JSON.stringify({ name: data.name }) &lt;2&gt;\r\n\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0} catch (error) {\r\n\u00a0\u00a0\u00a0\u00a0return { statusCode: 500, body: error.toString() }\r\n\u00a0\u00a0}\r\n}\r\n\r\nmodule.exports = { handler }<\/pre>\n<p>&nbsp;<\/p>\n<pre class=\"nums:false lang:default decode:true\">&lt;1&gt; The event object allows us to get the body of the request. It's text, we can parse this text into a JSON object and assign it to the field called `data`.\r\n&lt;2&gt; To make sure we did receive our JSON object, we change the returned message and use the field `data.name`.<\/pre>\n<p>You should see a different message in the web dev console, you should see <em>{&#8220;name&#8221;:&#8221;yourName&#8221;}<\/em>.<\/p>\n<p><span style=\"font-weight: 400;\">We have sent the form data to the backend and made sure of it. Now on to the database side of things. Working at Couchbase, this is the database I am going to use. A simple way to try, go to<\/span><a href=\"https:\/\/cloud.couchbase.com\/sign-up\"> <span style=\"font-weight: 400;\">https:\/\/cloud.couchbase.com\/sign-up<\/span><\/a><span style=\"font-weight: 400;\">, create an account, you get a 30 day trial, no credit card required.<\/span><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/github.com\/ldoguin\/freecodecamp-survey\/raw\/main\/images\/capellaGetStarted.png\" alt=\"A screenshot of the first Couchbase Capella Get started wizard step \" \/><\/p>\n<p><span style=\"font-weight: 400;\">You can leave the default on, or choose your favorite cloud provider and closest region. Click on <\/span><strong><i>Deploy now<\/i><\/strong><span style=\"font-weight: 400;\"> and wait for the deployment of your database.<\/span><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/github.com\/ldoguin\/freecodecamp-survey\/raw\/main\/images\/capellaTrialHome.png\" alt=\"A screenshot of the Couchbase Capella trial home\" \/><\/p>\n<p><span style=\"font-weight: 400;\">Two things we want to do from there. Make sure we can connect to that database from our backend code, and make sure we can write the data somewhere. Go ahead and click the <strong>Connect<\/strong> tab.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">In Couchbase we store data in Buckets. By default the trial comes with a travel-sample bucket preimported. We are not going to use it. Instead we are going to create our own bucket. Click on <\/span><strong>Settings<\/strong><span style=\"font-weight: 400;\"> on the top level menu, than on <\/span><strong>Buckets<\/strong><span style=\"font-weight: 400;\"> on the left menu.<\/span><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/github.com\/ldoguin\/freecodecamp-survey\/raw\/main\/images\/bucketHome.png\" alt=\"A screenshot of the Bucket settings in Couchbase Capella\" \/><\/p>\n<p><span style=\"font-weight: 400;\">Now click on <\/span><strong>+ Create Bucket<\/strong><span style=\"font-weight: 400;\">, give it a name and leave the rest to default settings.Than Click on <\/span><strong>Create Bucket<\/strong><span style=\"font-weight: 400;\">.<\/span><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/github.com\/ldoguin\/freecodecamp-survey\/raw\/main\/images\/surveyFormBucketCreated.png\" alt=\"A screenshot of the Buckets settings home, with the newly created bucket visible\" \/><\/p>\n<p><span style=\"font-weight: 400;\">We have a new Bucket, now we need to create associated credentials. Click the <\/span><strong>Database Access<\/strong><span style=\"font-weight: 400;\"> button, than <\/span><strong>Create Database Access<\/strong><span style=\"font-weight: 400;\"> button.<\/span><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/github.com\/ldoguin\/freecodecamp-survey\/raw\/main\/images\/emptyCredentials.png\" alt=\"A screenshot of the empty Credentials settings\" \/><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/github.com\/ldoguin\/freecodecamp-survey\/raw\/main\/images\/credentialCreation.png\" alt=\"A screenshot fo the credentials creation detail\" \/><\/p>\n<p><span style=\"font-weight: 400;\">Make sure you remember both username and passaord and click on <\/span><strong>Create Database<\/strong><span style=\"font-weight: 400;\">. One last thing to do is to allow this database to be reachable publicly. Right now it&#8217;s hidden. Click on <\/span><strong>Allowed IP Addresses<\/strong><span style=\"font-weight: 400;\">, than <\/span><strong>Add Allowed IP<\/strong><span style=\"font-weight: 400;\">. Click on <\/span><span style=\"font-weight: 400;\"><strong>Allow Access<\/strong> <\/span><strong>from Anywhere<\/strong><span style=\"font-weight: 400;\">, follow the instructions. This should prefill the form, than click on the <\/span><strong>Add Allowed IP<\/strong><span style=\"font-weight: 400;\"> button. You might think this is a bit cumbersome. Why isn&#8217;t it the default?<\/span><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/github.com\/ldoguin\/freecodecamp-survey\/raw\/main\/images\/addAllowedIp.png\" alt=\"A screenshot of the Allow Access from Anywhere popup\" \/><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/github.com\/ldoguin\/freecodecamp-survey\/raw\/main\/images\/addedIp.png\" alt=\"A screenshot of the resuting operation with the newly added IP range\" \/><\/p>\n<p><span style=\"font-weight: 400;\">Now click on the <\/span><strong>Connect<\/strong><span style=\"font-weight: 400;\"> tab. You will see the <em>Connection String<\/em>, select your database credentials, switch the language to Node, and it will give us the right instructions to connect to the database from our backend code.<\/span><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/github.com\/ldoguin\/freecodecamp-survey\/raw\/main\/images\/connectInstructions.png\" alt=\"A screenshot of the SDK connection instructions, with doc and code\" \/><\/p>\n<p><span style=\"font-weight: 400;\">We can copy and paste this to our function code, and add a couple more things:<\/span><\/p>\n<pre class=\"nums:false lang:js decode:true\">const crypto = require(\"crypto\"); &lt;1&gt;\u00a0\r\nconst couchbase = require(\"couchbase\"); &lt;2&gt;\r\n\r\nconst handler = async (event) =&gt; {\r\n\u00a0\u00a0try {\r\n         const clusterConnStr = \"couchbases:\/\/cb.ar0qqwli6cczm1u.cloud.couchbase.com\"; \/\/ Replace this with Connection String &lt;3&gt;\r\n         const username = \"Adminstrator\"; \/\/ Replace this with username from database access credentials &lt;3&gt;\r\n         const password = \"Couch#123\"; \/\/ Replace this with password from database access credentials &lt;3&gt;\r\n         \/\/ Get a reference to the cluster\r\n         const cluster = await couchbase.connect(clusterConnStr, { &lt;4&gt;\r\n         \u00a0 username: username,\r\n         \u00a0 password: password,\r\n         \u00a0 \/\/ Use the pre-configured profile below to avoid latency issues with your connection.\r\n         \u00a0 configProfile: \"wanDevelopment\",\r\n         });\r\n\r\n\u00a0\u00a0\u00a0\u00a0const bucket = cluster.bucket(\"surveyform\"); &lt;5&gt;\r\n\u00a0\u00a0\u00a0\u00a0const collection = bucket.defaultCollection(); &lt;6&gt;\r\n\r\n\u00a0\u00a0\u00a0\u00a0var data = JSON.parse(event.body);\r\n\u00a0\u00a0\u00a0\u00a0let result = await collection.insert(crypto.randomUUID(), data); &lt;7&gt;\r\n\r\n\u00a0\u00a0\u00a0\u00a0return {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0statusCode: 200,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0body: JSON.stringify({ name: data.name })\r\n\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0} catch (error) {\r\n\u00a0\u00a0\u00a0\u00a0console.log(error);\r\n\u00a0\u00a0\u00a0\u00a0return { statusCode: 500, body: error.toString() }\r\n\u00a0\u00a0}\r\n}\r\n\r\nmodule.exports = { handler }<\/pre>\n<pre class=\"nums:false lang:default decode:true\">&lt;1&gt; You can see we have two new dependencies to our project. The 'crypto' package is provided by node. It allows us to generate a random identifier for our document\r\n&lt;2&gt; The 'couchbase' package is the Couchbase NodeJS SDK. It's every bit of code you need to connect to a Couchbase database. This projects are also often called drivers for other databases, or clients.<\/pre>\n<p>For Couchbase you need to install it. Running <em>npm i couchbase@4.2.4<\/em> will do the trick. Right now Netlify\/Couchbase compatibilty is assured for Couchbase version 4.2.4 or below. This is due to the nature of our SDK. It&#8217;s a JavaScript interface on top our our C SDK. And C dependencies expect to find their system dependencies in the right version. Right now Couchbase 4.2.5 is expecting to find <em>GLIBC_29<\/em> but it&#8217;s not available on the Ubuntu system running our Netlify backend code.<\/p>\n<p><span style=\"font-weight: 400;\">Now that we have dependencies, let&#8217;s be explicit in how build them. You can add a <\/span><em><span style=\"font-weight: 400;\">netlify.toml<\/span><\/em><span style=\"font-weight: 400;\"> file at the root of the repository with the following content:<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true \">[build]\r\n\u00a0\u00a0command = \"npm install &amp;&amp; strip --strip-debug .\/node_modules\/couchbase\/build\/Release\/couchbase_impl.node\"\r\n\u00a0\u00a0publish = \".\"<\/pre>\n<p><span style=\"font-weight: 400;\">It&#8217;s doing a couple things. Installing the dependencies and removing the debug symbol table from <\/span><em><span style=\"font-weight: 400;\">couchbase_impl.node<\/span><\/em><span style=\"font-weight: 400;\">. This file is the C library used by our Node SDK. And it&#8217;s too big for Netlify right now. So we are removing unnecessary clutter coming from the build process.<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true\">&lt;3&gt; This variables are the informations needed for the SDK to connect to the cluster. A connections string, a username and a password.\r\n&lt;4&gt; `couchbase.connect` takes the connection string as first parameter, than a JSON object with username, password and other options. Here we also give the `wanDevelopment` config profiles. It will increase the default timeout values of all Couchbase operations. Basically if your connection is slow it won't scream at you.\r\n&lt;5&gt; From the Cluster object we get a Bucket. A bucket is where we store Scopes and Collections. Here we get the `surveyform` bucket. It already has a default scope and a default collection.\r\n&lt;6&gt; From the bucket we can get the default Collection. A Collection is where we store Document, or key\/value pairs. Think of the key as the identifier of the document, and the value as your JSON data. But it could be anything else.\r\n&lt;7&gt; From the collection object, we call the insert method. It takes two parameters, the key and the value. So we call the randomUUID() method from the crypto package, to generate a random identifier. And we pass the data object as value. It contains our JSON. This function is asynchronous, it's making a request to the Couchbase Capella cluster. We await for the cluster's response.<\/pre>\n<p><span style=\"font-weight: 400;\">Now you could add the new files, commit and push to GitHub. But that would push your password to GitHub. We don&#8217;t want that. Instead you can test it by running <\/span><em><span style=\"font-weight: 400;\">netlify dev<\/span><\/em><span style=\"font-weight: 400;\">. Go ahead and resubmit the form.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">If everything went well, you have written data to your Database! You can check this out easily by going to the Couchbase Capella UI. Cick on <\/span><strong>Data Tools<\/strong><span style=\"font-weight: 400;\">, select your Bucket, Scope and collection, and you should see your survey from document.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">This is great, you just wrote code to connect your database!<\/span><\/p>\n<h2>Step 5 &#8211; Configuration Management<\/h2>\n<p><span style=\"font-weight: 400;\">To avoid pushing our credentials on GitHub, we are going to use environment variables. Environment variables are common to every Operating Systems and is the best way to manage configuration across different environments (different OSs, clouds, test, staging, preproduction, production, whatever fits your workflow).<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true\">....\r\nconst ENDPOINT = process.env.COUCHBASE_ENDPOINT || \"couchbase:\/\/localhost\"; &lt;1&gt;\r\nconst USERNAME = process.env.COUCHBASE_USERNAME || \"Administrator\";&lt;1&gt;\r\nconst PASSWORD = process.env.COUCHBASE_PASSWORD || \"password\";&lt;1&gt;\r\nconst BUCKET = process.env.COUCHBASE_BUCKET || \"surveyform\"&lt;1&gt;\r\nconst handler = async (event) =&gt; {\r\n\u00a0\u00a0try {\r\n        const clusterConnStr = ENDPOINT; \/\/ Replace this with Connection String\r\n        const username = USERNAME; \/\/ Replace this with username from database access credentials\r\n        const password = PASSWORD; \/\/ Replace this with password from database access credentials\r\n        \/\/ Get a reference to the cluster\r\n        const cluster = await couchbase.connect(clusterConnStr, {\r\n          usernme: username,\r\n          password: password,\r\n       \u00a0  \/\/ Use the pre-configured profile below to avoid latency issues with your connection.\r\n       \u00a0  configProfile: \"wanDevelopment\",\r\n        });\r\n\u00a0\u00a0\u00a0\u00a0const bucket = cluster.bucket(BUCKET);\r\n...<\/pre>\n<pre class=\"nums:false lang:default decode:true \">&lt;1&gt; The process object is always available with node so no need for a specific library import. Using || allows to provide a default value for each variable if they are not defined.<\/pre>\n<p><span style=\"font-weight: 400;\">On Mac or Linux, you can run <\/span><em><span style=\"font-weight: 400;\">export MYVARIABLE=&#8221;value&#8221;<\/span><\/em><span style=\"font-weight: 400;\"> in your terminal. On Windows you can run <\/span><em><span style=\"font-weight: 400;\">$Env:MYVARIABLE=&#8221;value&#8221;<\/span><\/em><\/p>\n<p><span style=\"font-weight: 400;\">To define them in Netlify&#8217;s context, you can go though the UI and do it manually, or use the CLI:<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true\">netlify env:set COUCHBASE_ENDPOINT couchbases:\/\/cb.ar0qqwli6cczm1u.cloud.couchbase.com\r\nnetlify env:set COUCHBASE_USERNAME Administrator\r\nnetlify env:set COUCHBASE_PASSWORD password\r\nnetlify env:set COUCHBASE_BUCKET surveyform<\/pre>\n<p><span style=\"font-weight: 400;\">Now you can add your files, commit and push your code. Congratulations, you went fullstack. Backend, Frontend and Database. And deployed everything live! But our work is not over. There are still a couple things we can do to make this more professional.<\/span><\/p>\n<h2>Step 6 &#8211; User feedback<\/h2>\n<p><span style=\"font-weight: 400;\">Right now we don&#8217;t have much happening when the user clicks on the <\/span><strong>Submit<\/strong><span style=\"font-weight: 400;\"> button of our form. We need to change this to let them know they have been successfully recored, or not. First step it check for an error on the dev side of things. HTTP status code are well made, anything equals or higher than 400 is usually an error, so we can do something like this:<\/span><\/p>\n<pre class=\"nums:false lang:js decode:true\"> \u00a0\u00a0\u00a0if (response.status &gt;= 400) { &lt;1&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0console.log(\"Something when wrong\"); &lt;2&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0console.log(await response.text()); &lt;3&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return false;\r\n\u00a0\u00a0\u00a0\u00a0}<\/pre>\n<pre class=\"nums:false lang:default decode:true\">&lt;1&gt; Status code that starts with 4 usually means something went wrong on the client side. The wrong data was sent, the client does not have the right permission, the page does not exist etc... Here we test if the code is equals or higher than 400.\r\n&lt;2&gt; If it is, we log a message in the console\r\n&lt;3&gt; We also log the error message returned by the server<\/pre>\n<p>To test it, just make a typo somewhere in your Connection String or Credentials to Couchbase. You should see errors in the webconsole once clicking on <i>Submit<\/i>. But the web console is just for us, we need to add a proper error or success message to our user.<\/p>\n<p><span style=\"font-weight: 400;\">I added a couple span HTML elements with error and success message right before the end of the form. Note the <em>hide<\/em> CSS class that makes them invisible for now.<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true\">...\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/div&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;span id=\"form-error\" class=\"error-message hide\"&gt;&lt;\/span&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;span id=\"thank-you-message\" class=\"hide\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Your participation has been recorded, thank you!.\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/span&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/form&gt;\r\n...<\/pre>\n<p><span style=\"font-weight: 400;\">And here is the corresponding CSS. Displaying the error in red, hiding or showing an element, and a nice fade-out animation because I am fancy like that.<\/span><\/p>\n<pre class=\"nums:false lang:css decode:true\">.container .error-message {\r\n\u00a0\u00a0color: red;\r\n}\r\n\r\n.hide {\r\n\u00a0\u00a0display: none;\r\n}\r\n\r\n.show {\r\n\u00a0\u00a0display: block;\r\n}\r\n\r\n.fade-out {\r\n\u00a0\u00a0animation: fadeOut ease 8s;\r\n\u00a0\u00a0-webkit-animation: fadeOut ease 8s;\r\n\u00a0\u00a0-moz-animation: fadeOut ease 8s;\r\n\u00a0\u00a0-o-animation: fadeOut ease 8s;\r\n\u00a0\u00a0-ms-animation: fadeOut ease 8s;\r\n}@keyframes fadeOut {\r\n\u00a0\u00a00% {\r\n\u00a0\u00a0\u00a0\u00a0opacity:1;\r\n\u00a0\u00a0}\r\n\u00a0\u00a0100% {\r\n\u00a0\u00a0\u00a0\u00a0opacity:0;\r\n\u00a0\u00a0}\r\n}\r\n\r\n@-moz-keyframes fadeOut {\r\n\u00a0\u00a00% {\r\n\u00a0\u00a0\u00a0\u00a0opacity:1;\r\n\u00a0\u00a0}\r\n\u00a0\u00a0100% {\r\n\u00a0\u00a0\u00a0\u00a0opacity:0;\r\n\u00a0\u00a0}\r\n}\r\n\r\n@-webkit-keyframes fadeOut {\r\n\u00a0\u00a00% {\r\n\u00a0\u00a0\u00a0\u00a0opacity:1;\r\n\u00a0\u00a0}\r\n\u00a0\u00a0100% {\r\n\u00a0\u00a0\u00a0\u00a0opacity:0;\r\n\u00a0\u00a0}\r\n}\r\n\r\n@-o-keyframes fadeOut {\r\n\u00a0\u00a00% {\r\n\u00a0\u00a0\u00a0\u00a0opacity:1;\r\n\u00a0\u00a0}\r\n\u00a0\u00a0100% {\r\n\u00a0\u00a0\u00a0\u00a0opacity:0;\r\n\u00a0\u00a0}\r\n}\r\n\r\n@-ms-keyframes fadeOut {\r\n\u00a0\u00a00% {\r\n\u00a0\u00a0\u00a0\u00a0opacity:1;\r\n\u00a0\u00a0}\r\n\u00a0\u00a0100% {\r\n\u00a0\u00a0\u00a0\u00a0opacity:0;\r\n\u00a0\u00a0\u00a0\u00a0display: none;\r\n}<\/pre>\n<p><span style=\"font-weight: 400;\">Now to put everything together. The first two lines get the new span elements just added. The call to <\/span><em><span style=\"font-weight: 400;\">form.reset()<\/span><\/em><span style=\"font-weight: 400;\"> is clearing all values from the form when the returned response status code is <em>200<\/em>. Than the rest is playing with CSS classes to make the message appear, than fading out with the addition of the fade-out class, than a 7000ms timeout function will remove every classes and hide the element again. It&#8217;s pretty much the same when there is an error.<\/span><\/p>\n<pre class=\"nums:false lang:js decode:true\"> \u00a0\u00a0\u00a0const thankYouMessage = document.getElementById('thank-you-message'); &lt;1&gt;\r\n\u00a0\u00a0\u00a0\u00a0const formError = document.getElementById(\"form-error\"); &lt;1&gt;\r\n\r\n\u00a0\u00a0\u00a0\u00a0if (response.status == 200) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0form.reset(); &lt;2&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0thankYouMessage.classList.add('show'); &lt;3&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0thankYouMessage.classList.add('fade-out'); &lt;3&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0setTimeout(function(){thankYouMessage.classList.remove('fade-out');thankYouMessage.classList.remove('show');}, 7000); &lt;3&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0console.log(await response.text());\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return false;\r\n\u00a0\u00a0\u00a0\u00a0}\r\n\r\n\u00a0\u00a0\u00a0\u00a0if (response.status &gt;= 400) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0console.log(\"Something when wrong\");\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0console.log(await response.text());\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0formError.textContent = \"Something went wrong while recording your contact.\"; &lt;4&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0formError.classList.toggle('show'); &lt;4&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0formError.classList.toggle('fade-out'); &lt;4&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0setTimeout(function(){formError.classList.toggle('fade-out');formError.classList.toggle('show');}, 7000); &lt;4&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return false;\r\n\u00a0\u00a0\u00a0\u00a0}<\/pre>\n<pre class=\"nums:false lang:default decode:true\">&lt;1&gt; We assign our new spans to variables\r\n&lt;2&gt; If things went well, we reset the form's data, it shows to the user that it worked.\r\n&lt;3&gt; We first add a CSS class that shows the error message, than apply the fade-out CSS class, than call the timeout function. In 7000 ms, the fade-out and show CSS class will be removed, hiding the success message again.\r\n&lt;4&gt; We do the same thing when there is an error, using the formError HTML element instead.<\/pre>\n<p>Now you can test submit a form again and see the different success or error message, depending on what you decided to do. When you are happy you can add, commit and push that code.<\/p>\n<p><span style=\"font-weight: 400;\">Congratulations, you made it to the end of this guide! You have used git, GitHub, Netlify and Couchbase Capella to deploy an HTML form on the web, and made sure that the content was stored in a database each time users submit the form.<\/span><\/p>\n<h2>Ready for more?<\/h2>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li>Check out <a href=\"https:\/\/www.couchbase.com\/developers\/\">Couchbase developer resources<\/a>: sample applications, code, and tutorials.<\/li>\n<li>Join our <a href=\"https:\/\/www.couchbase.com\/developers\/community\/\">Community Hub<\/a> to use Discord, Forums, and more.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><a href=\"https:\/\/www.couchbase.com\/developers\/community\/\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-14769 size-large\" style=\"border: 1px solid;\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/08\/image_2023-08-28_191205758-1024x865.png\" alt=\"\" width=\"900\" height=\"760\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/08\/image_2023-08-28_191205758-1024x865.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/08\/image_2023-08-28_191205758-300x253.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/08\/image_2023-08-28_191205758-768x649.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/08\/image_2023-08-28_191205758-1320x1115.png 1320w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/08\/image_2023-08-28_191205758.png 1536w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The Couchbase DevRel team has been working with the Bad Website Club on freeCodeCamp materials.\u00a0 freeCodeCamp is a non-profit organization that consists of an interactive learning web platform, an online community forum, chat rooms, online publications and local organizations that [&hellip;]<\/p>\n","protected":false},"author":49,"featured_media":14772,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1814,1815,2225,9327,2201],"tags":[9832,1500,1776],"ppma_author":[9023],"class_list":["post-14768","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-application-design","category-best-practices-and-tutorials","category-cloud","category-javascript","category-tools-sdks","tag-netlify","tag-tutorial","tag-web-application"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.8 (Yoast SEO v25.8) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Build a Survey App with Netlify and Couchbase - The Couchbase Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/building-a-survey-app-with-netlify-and-couchbase\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Build a Survey App with Netlify and Couchbase\" \/>\n<meta property=\"og:description\" content=\"The Couchbase DevRel team has been working with the Bad Website Club on freeCodeCamp materials.\u00a0 freeCodeCamp is a non-profit organization that consists of an interactive learning web platform, an online community forum, chat rooms, online publications and local organizations that [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/building-a-survey-app-with-netlify-and-couchbase\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2023-08-29T01:20:02+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-08-31T18:21:04+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/08\/image_2023-08-28_192155937-1024x513.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1024\" \/>\n\t<meta property=\"og:image:height\" content=\"513\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Laurent Doguin\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@ldoguin\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"unstructured.io\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"18 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/building-a-survey-app-with-netlify-and-couchbase\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/building-a-survey-app-with-netlify-and-couchbase\/\"},\"author\":{\"name\":\"Laurent Doguin\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/c0aa9b8f1ed51b7a9e2f7cb755994a5e\"},\"headline\":\"Build a Survey App with Netlify and Couchbase\",\"datePublished\":\"2023-08-29T01:20:02+00:00\",\"dateModified\":\"2023-08-31T18:21:04+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/building-a-survey-app-with-netlify-and-couchbase\/\"},\"wordCount\":2988,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/building-a-survey-app-with-netlify-and-couchbase\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/08\/image_2023-08-28_192155937.png\",\"keywords\":[\"netlify\",\"tutorial\",\"web application\"],\"articleSection\":[\"Application Design\",\"Best Practices and Tutorials\",\"Couchbase Capella\",\"JavaScript\",\"Tools &amp; SDKs\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/building-a-survey-app-with-netlify-and-couchbase\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/building-a-survey-app-with-netlify-and-couchbase\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/building-a-survey-app-with-netlify-and-couchbase\/\",\"name\":\"Build a Survey App with Netlify and Couchbase - The Couchbase Blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/building-a-survey-app-with-netlify-and-couchbase\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/building-a-survey-app-with-netlify-and-couchbase\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/08\/image_2023-08-28_192155937.png\",\"datePublished\":\"2023-08-29T01:20:02+00:00\",\"dateModified\":\"2023-08-31T18:21:04+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/building-a-survey-app-with-netlify-and-couchbase\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/building-a-survey-app-with-netlify-and-couchbase\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/building-a-survey-app-with-netlify-and-couchbase\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/08\/image_2023-08-28_192155937.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/08\/image_2023-08-28_192155937.png\",\"width\":3732,\"height\":1871},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/building-a-survey-app-with-netlify-and-couchbase\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Build a Survey App with Netlify and Couchbase\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/c0aa9b8f1ed51b7a9e2f7cb755994a5e\",\"name\":\"Laurent Doguin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/12929ce99397769f362b7a90d6b85071\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/b8c466908092b46634af916b6921f30187a051e4367ded7ac9b1a3f2c5692fd2?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/b8c466908092b46634af916b6921f30187a051e4367ded7ac9b1a3f2c5692fd2?s=96&d=mm&r=g\",\"caption\":\"Laurent Doguin\"},\"description\":\"Laurent is a nerdy metal head who lives in Paris. He mostly writes code in Java and structured text in AsciiDoc, and often talks about data, reactive programming and other buzzwordy stuff. He is also a former Developer Advocate for Clever Cloud and Nuxeo where he devoted his time and expertise to helping those communities grow bigger and stronger. He now runs Developer Relations at Couchbase.\",\"sameAs\":[\"https:\/\/x.com\/ldoguin\"],\"honorificPrefix\":\"Mr\",\"birthDate\":\"1985-06-07\",\"gender\":\"male\",\"award\":[\"Devoxx Champion\",\"Couchbase Legend\"],\"knowsAbout\":[\"Java\"],\"knowsLanguage\":[\"English\",\"French\"],\"jobTitle\":\"Director Developer Relation & Strategy\",\"worksFor\":\"Couchbase\",\"url\":\"https:\/\/www.couchbase.com\/blog\/author\/laurent-doguin\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Build a Survey App with Netlify and Couchbase - The Couchbase Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/building-a-survey-app-with-netlify-and-couchbase\/","og_locale":"en_US","og_type":"article","og_title":"Build a Survey App with Netlify and Couchbase","og_description":"The Couchbase DevRel team has been working with the Bad Website Club on freeCodeCamp materials.\u00a0 freeCodeCamp is a non-profit organization that consists of an interactive learning web platform, an online community forum, chat rooms, online publications and local organizations that [&hellip;]","og_url":"https:\/\/www.couchbase.com\/blog\/building-a-survey-app-with-netlify-and-couchbase\/","og_site_name":"The Couchbase Blog","article_published_time":"2023-08-29T01:20:02+00:00","article_modified_time":"2023-08-31T18:21:04+00:00","og_image":[{"width":1024,"height":513,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/08\/image_2023-08-28_192155937-1024x513.png","type":"image\/png"}],"author":"Laurent Doguin","twitter_card":"summary_large_image","twitter_creator":"@ldoguin","twitter_misc":{"Written by":"unstructured.io","Est. reading time":"18 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/building-a-survey-app-with-netlify-and-couchbase\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/building-a-survey-app-with-netlify-and-couchbase\/"},"author":{"name":"Laurent Doguin","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/c0aa9b8f1ed51b7a9e2f7cb755994a5e"},"headline":"Build a Survey App with Netlify and Couchbase","datePublished":"2023-08-29T01:20:02+00:00","dateModified":"2023-08-31T18:21:04+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/building-a-survey-app-with-netlify-and-couchbase\/"},"wordCount":2988,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/building-a-survey-app-with-netlify-and-couchbase\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/08\/image_2023-08-28_192155937.png","keywords":["netlify","tutorial","web application"],"articleSection":["Application Design","Best Practices and Tutorials","Couchbase Capella","JavaScript","Tools &amp; SDKs"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/building-a-survey-app-with-netlify-and-couchbase\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/building-a-survey-app-with-netlify-and-couchbase\/","url":"https:\/\/www.couchbase.com\/blog\/building-a-survey-app-with-netlify-and-couchbase\/","name":"Build a Survey App with Netlify and Couchbase - The Couchbase Blog","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/building-a-survey-app-with-netlify-and-couchbase\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/building-a-survey-app-with-netlify-and-couchbase\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/08\/image_2023-08-28_192155937.png","datePublished":"2023-08-29T01:20:02+00:00","dateModified":"2023-08-31T18:21:04+00:00","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/building-a-survey-app-with-netlify-and-couchbase\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/building-a-survey-app-with-netlify-and-couchbase\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/building-a-survey-app-with-netlify-and-couchbase\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/08\/image_2023-08-28_192155937.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2023\/08\/image_2023-08-28_192155937.png","width":3732,"height":1871},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/building-a-survey-app-with-netlify-and-couchbase\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Build a Survey App with Netlify and Couchbase"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"The Couchbase Blog","description":"Couchbase, the NoSQL Database","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"The Couchbase Blog","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/c0aa9b8f1ed51b7a9e2f7cb755994a5e","name":"Laurent Doguin","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/12929ce99397769f362b7a90d6b85071","url":"https:\/\/secure.gravatar.com\/avatar\/b8c466908092b46634af916b6921f30187a051e4367ded7ac9b1a3f2c5692fd2?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/b8c466908092b46634af916b6921f30187a051e4367ded7ac9b1a3f2c5692fd2?s=96&d=mm&r=g","caption":"Laurent Doguin"},"description":"Laurent is a nerdy metal head who lives in Paris. He mostly writes code in Java and structured text in AsciiDoc, and often talks about data, reactive programming and other buzzwordy stuff. He is also a former Developer Advocate for Clever Cloud and Nuxeo where he devoted his time and expertise to helping those communities grow bigger and stronger. He now runs Developer Relations at Couchbase.","sameAs":["https:\/\/x.com\/ldoguin"],"honorificPrefix":"Mr","birthDate":"1985-06-07","gender":"male","award":["Devoxx Champion","Couchbase Legend"],"knowsAbout":["Java"],"knowsLanguage":["English","French"],"jobTitle":"Director Developer Relation & Strategy","worksFor":"Couchbase","url":"https:\/\/www.couchbase.com\/blog\/author\/laurent-doguin\/"}]}},"authors":[{"term_id":9023,"user_id":49,"is_guest":0,"slug":"laurent-doguin","display_name":"Laurent Doguin","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/b8c466908092b46634af916b6921f30187a051e4367ded7ac9b1a3f2c5692fd2?s=96&d=mm&r=g","author_category":"","last_name":"Doguin","first_name":"Laurent","job_title":"","user_url":"","description":"Laurent is a nerdy metal head who lives in Paris. He mostly writes code in Java and structured text in AsciiDoc, and often talks about data, reactive programming and other buzzwordy stuff. He is also a former Developer Advocate for Clever Cloud and Nuxeo where he devoted his time and expertise to helping those communities grow bigger and stronger. He now runs Developer Relations at Couchbase."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/14768","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/users\/49"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/comments?post=14768"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/14768\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media\/14772"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media?parent=14768"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/categories?post=14768"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/tags?post=14768"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=14768"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}