Home ยป JavaScript fetch API: GET data from REST API and display in HTML/CSS

JavaScript fetch API: GET data from REST API and display in HTML/CSS

Share this post:

In this JavaScript example, we are going to fetch data from an external REST API using JavaScript fetch().

In addition to fetching posts from a third party API and list the post titles on the HTML page, we’re going to do a little HTML DOM manipulation by creating HTML elements on the fly.

Watch the lesson, or read the explanation of the codes below:


  • Basic knowlege of JavaScript
  • Basic knowlege of HTML and CSS

The expected result

The result will be a list of post titles with clickable links, created with JavaScript fetch() and DOM manipulation. You can see the finished project in the video.

HTML Codes


<!DOCTYPE html>
    <link rel="stylesheet" href="app.css" />
    <div id="post-section">
      <h2>LATEST POSTS</h2>
      <div id="post-items-container"></div>
    <script src="post.js"></script>

Explanation of the HTML code:

  • The line that include the CSS file is: <link rel=”stylesheet” href=”app.css” />
  • The div element with id=”post-items-container” wraps the post titles we’re going to insert using JavaScript DOM maniuplation.
  • The line that include the JavaScript file is <script src=”post.js”></script>
  • listPosts(‘post-items-container’); called in the next script tag calls a function from post.js file included before it, hence, it must come after the post.js file has been included!

CSS Codes


body {
  margin: 0;
#post-section {
  background-color: rgb(16, 15, 15);
  color: #bcbcbc;
  padding: 24px;
h3 {
  font-size: 24px;
#post-items-container h3 {
  margin: 6px;
  padding: 6px;
a {
  text-decoration: none;
  padding: 6px;
  color: #0492cee2;

Explanation of the CSS codes

The CSS codes are actually self-explanatory since only very basic CSS is used. Note that you can style the CSS anyhow you like.

  • body: we remove default marging added by the browser from the body.
  • #post-section: set a dark background color and light text color.
  • a: The a tag is given a special color that highlights it as a link in the dack background page.

JavaScript Code


const apiUrl = 'https://jsonplaceholder.typicode.com';

async function fetchPosts() {
  try {
    const response = await fetch(`${apiUrl}/posts`);
    if (!response.ok) {
      throw new Error(`HTTP error: ${response.status}`);

    return await response.json();
  } catch (e) {
    console.log('fetchPosts:', e);

function listPosts(postContainerElementId) {
  const postContainerElement = document.getElementById(

  if (!postContainerElement) {

  // because fetchPosts returns a promise, use then() to get content and
  // catch() in case of any error, e.g. if posts is not iterable
    .then((posts) => {
      if (!posts) {
        postContainerElement.innerText = 'Could not get posts';
      for (const post of posts) {
    .catch((e) => {
      console.log('listPosts:', e);

function postElement(post) {
  const anchorElement = document.createElement('a');
  anchorElement.setAttribute('href', `${apiUrl}/posts/${post.id}`);
  anchorElement.setAttribute('target', '_blank');
  anchorElement.innerText = capitalizeFirstLetter(post.title);

  const postTitleElement = document.createElement('h3');

  return postTitleElement;

function capitalizeFirstLetter(string) {
  return string.charAt(0).toUpperCase() + string.slice(1);

Let me walk you through the JavaScript codes we have in app.js

fetchPosts function

This is the function that fetches posts from third party posts API. The posts API is defined in the line const apiUrl = ‘https://jsonplaceholder.typicode.com’; Which is a URL pointing to {JSON} Placeholder, a free resource that provides free APIs you can use for learning purposes.

Notice that the function returns a promise. This is indicated by the async keyword in the function definition: async function fetchPosts(){…}

The reason this function needs to have async is that the call to fetch() returns a promise. This is why we use the await keyword before fetch().

Recall that a promise produces a result (success or failure) in the “future”. In programming, the future can be in milliseconds, so, “future” does not mean that it will take 1 hour or so for the posts to be fetched.

fetch(): The line of code that fetches posts from the JSON Placeholder API is const response = await fetch(${apiUrl}/posts);

try {} catch (e) {}: The try-catch is needed to catch any error that might occur in the process without crashing the app. This error can be the one we threw at the line if (!response.ok){…}.


  • fetch() works in browsers, not in node.js by default
  • the JavaScript file is included in the HTML file first before another script tag in the HTML that calls a function in the JavaScript file.

listPosts function

The listPosts function calls the fetchPosts function to get the list of posts and insert each post in the HTML page.

Calling fetchPosts()

Because fetchPosts returns a promise, we can’t just say const posts = fetchPosts() instead, we use .then().catch() syntax:

    .then((posts) => {...})
    .catch((e) => {...});
  • postContainerElementId: This id the ID of HTML element where the post items will be inserted.

postElement function

The function postElement created H3 and anchor elements and then set the post title as the inner text of the link.

Some attributes are also set for the HTML elements created in this function, such as href and target for the anchor tag.

The anchor tag is inserted into the H3 tag and the function returns the resulting HTML elements.

capitalizeFistLetter function

This is a helper function that basically capitalizes the first letter of a string passed to it. We called this function to capitalize the first letter of each post title.

Have a question? Let me hear it in the comment box below.

Happy coding!

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.