Use the Notion API to Create a Quiz with JavaScript — SitePoint

Notion is a multi-featured app for organizing every kind of content material materials, from notes to calendars and reminders. In our remaining article, “Getting Started with the Notion API and Its JavaScript SDK”, we delved into learn how to make use of Notion’s API and created a small interface to work along with it. This textual content now will uncover one different use case for the Notion API: making a JavaScript quiz.

Whereas no earlier data is required to watch along with this textual content (I’ll current all the required steps), we’ll be dealing with front-end and back-end code, as there’s slightly little bit of Node.js and Categorical setup involved, so some JavaScript experience are assumed.

Key Takeaways

  • Profit from the Notion API to creatively adapt a Desk database for creating a JavaScript quiz, no matter Notion not being inherently designed for quiz databases.
  • Implement a JavaScript and Node.js setting, incorporating Categorical and dotenv for server administration and setting variable security.
  • Securely mix with Notion by producing and using an Inside Integration Token, making sure API interactions are authenticated.
  • Retrieve quiz data from Notion using a structured query that maps database entries to a usable format inside the JavaScript software program.
  • Enhance shopper interaction by dynamically rendering quiz questions and options inside the browser, and coping with shopper responses with seen options.
  • Leverage the flexibleness of the Notion API to customize and automate the quiz setup, making it a scalable reply for quite a few functions.

JavaScript Quiz Mission Setup

We’re going to separate our setup into two sections. Throughout the first one, we’ll stroll through the required setup on the Notion side, and one the second half we’ll work with our code.

To look at alongside, you’ll need a Notion account (further on that beneath), along with a modern copy of Node put in in your machine. As ever, the remaining code for the tutorial is likely to be found on GitHub.

The Notion Setup

In case you don’t already have a Notion account, please create one by following this hyperlink. After creating your account and logging in, create a model new internet web page by deciding on Add an online web page and gives it a fame. For this tutorial, we’ll use a Desk database. Although it’s not the proper database to assemble a quiz, it’s the closest we’ll acquire with Notion!

Inserting information into the desk

Now that we now have our empty Desk, we’ve to work out learn how to accurately insert our information into it.
Our meant schema for our quiz is the subsequent:

{
  "1": {
    "Question": "Which is the purpose of JavaScript?",
    "Options": {
      "1": "To sort HTML Pages",
      "2": "In order so as to add interactivity to HTML pages",
      "3": "To hold out server side scripting operations"
    },
    "Acceptable": "In order so as to add interactivy to HTML pages"
  },
  "2": {
    "Question": "To insert a JavaScript into an HTML internet web page, which tag is used?",
    "Options": {
      "1": ",
      "2": "",
      "3": "
    },
    "Acceptable": "
  },
  "3": {
    "Question": "Which of the subsequent is acceptable to jot down “Hello there World” on the web internet web page?",
    "Options": {
      "1": "print('Hello there World')",
      "2": "doc.write('Hello there World')",
      "3": "response.write('Hello there World')"
    },
    "Acceptable": "doc.write('Hello there World')"
  }
}

Notion isn’t truly constructed for such a database, so we’ve to get creative with it! 💡 So our Question column will in all probability be solely a Title (which works good) and our Acceptable column will in all probability be of kind Textual content material (which moreover works as meant). For our numerous decisions, though, we’ve to do one factor completely completely different! My technique to it is to utilize the Multi-select topic kind so I can write numerous outcomes into the similar cell (we’ll see down the path what the information retrieved from this seems like). So our Desk must look like the subsequent image because the tip finish outcome.

Use the Notion API to Create a Quiz with JavaScript — SitePoint

Creating our Notion API integration

Now we’ve to go to the Notion API site to create our integration. Press the My Integrations button on the very best correct nook after which click on on on Create new integration. Now we have to fill in our title and make certain you choose our Associated workspace (will in all probability be chosen by default nonetheless make certain that of this). If we press Submit, we’ll be directed to a model new internet web page with an Inside Integration Token (we’ll use this in our code) and with two selection containers for the place we have to use our integration. We don’t must do one thing on this internet web page aside from copy our token and press Save changes.

Now we return to our Notion workspace. In our newly created Notion database, we have to press Share, then Invite. We’ll then have the power to pick out our newly created integration. If we choose it and press Invite, our Notion setup is completed. Properly carried out! 🙌

The Code Setup

For our code setup, we’ll use a Notion template repository (which we’ll then use on any of our Notion API duties!) that already has the preliminary code required to work with Notion’s API. This repo is likely to be found proper right here, so make certain you fork it and clone it to accompany our mission! In case you’re taken with what all the bits of code do, please talk about with “Getting Started with the Notion API and Its JavaScript SDK”, since we go into quite a few component for every little little bit of code (the repo moreover has a README that must make clear what it does!).

Placing in dependencies

After forking and cloning our Notion template repo, our first step is to place in our dependencies, so make certain that to run yarn or npm arrange on our terminal contained within the folder. On this mission we now have three dependencies: the @notionhq/shopper, dotenv and Categorical. We’ll use dotenv to deal with our variables and preserve them protected (such as a result of the one we observed on our integration) and Categorical to create our once more end and server for our software program.

To deal with our variables with dotenv, create a .env file on the foundation of our mission and paste the subsequent there:

NOTION_API_KEY = YOUR_TOKEN_HERE
NOTION_API_DATABASE = YOUR_DATABASE_ID_HERE

Our NOTION_API_KEY is the essential factor that we are going to uncover in our Integrations, and our NOTION_API_DATABASE is likely to be found by going to the created Notion internet web page and looking on the browser’s URL bar. It comes after your workspace title (if we now have one) and the slash (myworkspace/) and sooner than the question mark (?). The ID is 32 characters prolonged, containing numbers and letters:

https://www.notion.so/myworkspace/a8aec43384f447ed84390e8e42c2e089?v=...
                                  |--------- Database ID --------|

If we’re fearful about having Notion’s API keys on a file inside our repo, uncover that on our .gitignore we now have the .env file there; the .gitignore permits us to position completely completely different file/folder names inside, and that signifies that these recordsdata/folders obtained’t be added to our repo as soon as we push our code.

Now that we now have our preliminary repository and we now have the required credentials from Notion, we’ll start engaged on our quiz!

Grabbing the JavaScript Quiz Data

We should all the time first confirm if we’re effectively associated to our Notion database, so we’ll navigate to our .index.js file and log our reponse variable (see how we’re grabbing our databaseId from our .env file and using it on our database query?).

If we then run yarn start, we should all the time see one factor like the subsequent screenshot on our terminal.

What logging the response query retrieves

Seeing this on our terminal signifies that we’re accurately associated to our Notion database and that we are going to now get our required data. Our getDatabase function will look like this:

exports.getDatabase = async function () {
  const response = await notion.databases.query({ database_id: databaseId });

  const responseResults = response.outcomes.map((internet web page) => {
    return {
      id: internet web page.id,
      question: internet web page.properties.Question.title[0].plain_text,
      options: internet web page.properties.Options.multi_select,
      acceptable: internet web page.properties.Acceptable.rich_text[0].plain_text,
    };
  });

  return responseResults;
};

With responseResults, we’re mapping over our outcomes (matching the entries in our database) and we’re mapping the paths for numerous properties to names that we’re deciding on (on this case, id, question, options and acceptable). Uncover how explicit the merchandise path is. That’s by design, which signifies that, when rising and coping with your private database, it is best to continually look at the returned properties until you uncover the information you’re looking for (it’s truly a matter of trial and error).

With this new code, we’re nearly making a reputation to our API and deciding on the properties that we have to use in our code, which signifies that we’re capable of work with them on our interface!

Displaying Our Data inside the Browser

Let’s start by dealing with our HTML and CSS, since they’re pretty direct! We obtained’t do any changes on our HTML from the template, and on our sort.css we’ll paste the subsequent code beneath the current one:

.questionContainer {
  padding: 30px;

  present: flex;
  flex-direction: column;
  justify-content: coronary heart;
  align-items: coronary heart;

  box-shadow: rgba(149, 157, 165, 0.2) 0px 8px 24px;
  border-radius: 10px;
}

.numberElement {
  margin: 0px auto 10px;

  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
}

.question {
  margin: 0px auto 40px;
}

.answersDiv {
  width: 100%;

  present: flex;
  flex-direction: column;
  gap: 20px;
}

.answerOption {
  padding: 20px;
  margin: 0px;

  font-size: 18px;
  text-align: coronary heart;

  cursor: pointer;

  border: 1px secure rgb(42, 43, 44);
  border-radius: 40px;
}

We obtained’t see these styling changes however, nonetheless we’ll now give consideration to the efficiency, which is the additional important part of this tutorial.

If we now go to the main.js file contained within the public folder, we’ll see that we’re already grabbing our data from our once more end with the getDataFromBackend function. In case you’re confused by this, “Getting Started with the Notion API and Its JavaScript SDK” has a lengthier rationalization for it, nonetheless primarily on our server.js we created a route that can get our database, and proper right here on getDataFromBackend we’re making a fetch to that exact same route, which might seize our data for us.

Uncover how inside addData we already have const data = await getDataFromBackend();. Due to this we’re ready to start working with our data, and we’ll actually confirm this! log this data variable and we should all the time see, on our console, an array of our database entries.

Logging our data

Displaying our data on the show display screen

Now that everyone knows what our returned data seems like, we’ve to think about how we actually have to current it on the show display screen. My idea for it is to have a card for each question, with the completely completely different options inside, and when the buyer presses the correct reply, the reply’s background must flip inexperienced; if it’s fallacious, it must flip pink.

Let’s start by making a

for each question. We'll try this by iterating over our array with a forEach loop, allowing us to create the

and add some programs to it.

So inside our addData function we'll try this:

const addData = async () => {
  const data = await getDataFromBackend();

  data.forEach((price, index) => {
    const div = doc.createElement('div');
    div.classList.add('questionContainer');

    container.append(div);
  });
};

But it surely absolutely nonetheless feels a bit empty, so let’s append a header for each card like this:

const addData = async () => {
  const data = await getDataFromBackend();

  data.forEach((price, index) => {
    const div = doc.createElement('div');
    div.classList.add('questionContainer');

    const numberElement = doc.createElement('p');
    numberElement.classList.add('numberElement');
    numberElement.innerHTML = `Question ${index + 1}`;

    div.appendChild(numberElement);

    container.append(div);
  });
};

Proper right here we’re making a and giving it a class, and we’re working with index + 1, on account of arrays in JavaScript are zero-based and we don’t have to see Question 0, since that doesn’t make sense! If we now start our app, we should all the time see one factor like what’s pictured beneath.

We're now rendering a card for each question and displaying a header for it that reads Question ${index + 1}

The satisfying half: new capabilities for rendering questions and options

Now for the satisfying half! We might do all of our logic inside addData, nonetheless that will get too messy, so we’re going to create new capabilities to render our question and options.

Let’s start with the question, and let’s do some work on our addData function that obtained’t nonetheless translate into quite a bit:

const addData = async () => {
  const data = await getDataFromBackend();

  data.forEach((price, index) => {
    const div = doc.createElement('div');
    div.classList.add('questionContainer');

    const numberElement = doc.createElement('p');
    numberElement.classList.add('numberElement');
    numberElement.innerHTML = `Question ${index + 1}`;

    div.appendChild(numberElement);

    
    const question = createQuestion(price.question);

    div.appendChild(question);
    

    container.append(div);
  });
};

The code we merely added is much like that for the numberElement, nonetheless proper right here we’re assigning a function to a variable and appending that variable. Uncover moreover that we’re passing price.question into our createQuestion, on account of we have to work with and render the question, in any case. It may all make sense in a short time — don’t worry!

Now, outdoor and above addData, let’s create this new createQuestion function. Inside it, we nearly want the similar logic that we added for our numberElement: create a part, give it a class, and add some content material materials to it. Proper right here we’ll be using not innerHTML nonetheless createTextNode: since our questions are related to code, if we've been to utilize innerHTML in a single factor like textual content material, it is going to actually render the phrase textual content material nonetheless with daring instead of the entire syntax (you'll see an occasion proper right here). Our remaining createQuestion will look like this:

const createQuestion = (question) => {
  const questionElement = doc.createElement('h3');
  questionElement.classList.add('question');
  const questionNode = doc.createTextNode(question);

  questionElement.appendChild(questionNode);

  return questionElement;
};

If we now run yarn start, our browser ought to appear as confirmed beneath.

We should now see the question card with the question header and the newly added question

Now our setup for our options is simply in regards to the similar. Let’s first do the similar issue that we did with createQuestion inside addData:

const addData = async () => {
  const data = await getDataFromBackend();

  data.forEach((price, index) => {
    const div = doc.createElement('div');
    div.classList.add('questionContainer');

    const numberElement = doc.createElement('p');
    numberElement.classList.add('numberElement');
    numberElement.innerHTML = `Question ${index + 1}`;

    div.appendChild(numberElement);

    const question = createQuestion(price.question);

    div.appendChild(question);

    
    const options = createAnswers(price);

    div.appendChild(options);
    

    container.append(div);
  });
};

And now our preliminary seek for createAnswers will look like this:

const createAnswers = (price) => {
  const answersDiv = doc.createElement('div');
  answersDiv.classList.add('answersDiv');

  return answersDiv;
};

Uncover how we’re doing const options = createAnswers(price);. We'll’t merely cross price.options to our function, on account of we moreover need the price.acceptable. We might instead of this cross two arguments to our function: one for the array of options and the other one may be the acceptable one.

Rendering an array of options

We now have an array of options, and we've to render all of them, so we would like a loop to endure all of them. The tactic inside this loop will nearly be the similar as for all the other elements, so we must be professionals at this degree at rendering elements on the DOM:

const createAnswers = (price) => {
  const answersDiv = doc.createElement('div');
  answersDiv.classList.add('answersDiv');

  for (let i = 0; i  price.options.measurement; i++) {
    const answerElement = doc.createElement('p');
    answerElement.classList.add('answerOption');
    const answerNode = doc.createTextNode(price.options[i].title);

    answerElement.appendChild(answerNode);

    answersDiv.appendChild(answerElement);
  }

  return answersDiv;
};

With this code, we’re looping over our array, making a part, giving it a class and using createTextNode to render our options. (Funnily adequate, if we had used innerHTML proper right here, the options with

By admin

Leave a Reply

Your email address will not be published. Required fields are marked *