DEV Community

Isabella Otoo
Isabella Otoo

Posted on

Understanding APIs: A Beginner's Guide to Making Your First API Call

Table of Contents


Introduction

If you've ever wondered how apps communicate with each other, share data, or fetch information from the internet, the answer is APIs. In this tutorial, you'll learn what APIs are, how they work, and how to make your first API call.

What you'll learn:

  • What an API is and why it matters
  • Understanding HTTP methods and status codes
  • Making API calls using JavaScript
  • Handling API responses and errors
  • Best practices for working with APIs

Prerequisites:

  • Basic JavaScript knowledge
  • A text editor (VS Code recommended)
  • A web browser
  • No special installations required

Time to complete: 30-40 minutes


What is an API?

API stands for Application Programming Interface. Think of it as a waiter in a restaurant:

  • You (the user) sit at a table and want to order food
  • The kitchen (the server) has all the food and knows how to prepare it
  • The waiter (the API) takes your order to the kitchen and brings back your food

The API is the messenger that takes your request, tells the system what you want, and returns the response.

Real-World API Examples

APIs are everywhere in modern applications:

  • Weather apps use weather APIs to get current conditions
  • Social media apps use APIs to post updates and fetch feeds
  • Payment systems use APIs to process transactions
  • Maps use APIs to display locations and directions
  • E-commerce sites use APIs to check product inventory

Understanding HTTP Methods

APIs communicate using HTTP (Hypertext Transfer Protocol). When you interact with an API, you use specific methods to perform different actions:

The Four Main HTTP Methods

1. GET - Retrieve data

  • Used to fetch information without changing anything
  • Example: Getting a list of users, fetching weather data
  • Like asking "Can I see the menu?"

2. POST - Create new data

  • Used to send data to create something new
  • Example: Creating a new user account, submitting a form
  • Like saying "I want to place an order"

3. PUT - Update existing data

  • Used to modify existing information
  • Example: Updating your profile information
  • Like saying "I want to change my order"

4. DELETE - Remove data

  • Used to delete existing information
  • Example: Deleting a post, removing a user
  • Like saying "Cancel my order"

HTTP Status Codes

When you make an API request, the server responds with a status code that tells you what happened:

Success Codes (2xx)

  • 200 OK - Request succeeded
  • 201 Created - New resource was created successfully
  • 204 No Content - Request succeeded but no content to return

Client Error Codes (4xx)

  • 400 Bad Request - Your request was invalid
  • 401 Unauthorized - You need to authenticate first
  • 403 Forbidden - You don't have permission
  • 404 Not Found - The resource doesn't exist

Server Error Codes (5xx)

  • 500 Internal Server Error - Something went wrong on the server
  • 503 Service Unavailable - Server is temporarily down

Your First API Call

Let's make your first API call using a free, public API. We'll use the JSONPlaceholder API, which provides fake data for testing.

Method 1: Using the Browser Console

Open your browser's developer console (F12 or right-click > Inspect > Console) and paste this code:

// Make a GET request to fetch a user
fetch('https://jsonplaceholder.typicode.com/users/1')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));
Enter fullscreen mode Exit fullscreen mode

What happens:

  1. fetch() sends a GET request to the API
  2. .then(response => response.json()) converts the response to JSON format
  3. .then(data => console.log(data)) displays the data in the console
  4. .catch() handles any errors (see error handling section)

You should see user data with properties like name, email, and address.

Method 2: Creating an HTML File

Create a file called api-test.html and add this code:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>API Tutorial</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      max-width: 800px;
      margin: 50px auto;
      padding: 20px;
      background: #f5f5f5;
    }
    .container {
      background: white;
      padding: 30px;
      border-radius: 10px;
      box-shadow: 0 2px 10px rgba(0,0,0,0.1);
    }
    button {
      background: #007bff;
      color: white;
      border: none;
      padding: 10px 20px;
      border-radius: 5px;
      cursor: pointer;
      font-size: 16px;
    }
    button:hover {
      background: #0056b3;
    }
    #result {
      margin-top: 20px;
      padding: 15px;
      background: #f8f9fa;
      border-radius: 5px;
      white-space: pre-wrap;
      font-family: monospace;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>My First API Call</h1>
    <button onclick="fetchUser()">Fetch User Data</button>
    <div id="result"></div>
  </div>

  <script>
    function fetchUser() {
      fetch('https://jsonplaceholder.typicode.com/users/1')
        .then(response => response.json())
        .then(data => {
          document.getElementById('result').textContent = 
            JSON.stringify(data, null, 2);
        })
        .catch(error => {
          document.getElementById('result').textContent = 
            'Error: ' + error.message;
        });
    }
  </script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Open this file in your browser and click the button to see the API response displayed on the page.


Understanding the Response

When you make an API call, you typically receive data in JSON format. Here's what a typical response looks like:

{
  "id": 1,
  "name": "Leanne Graham",
  "username": "Bret",
  "email": "Sincere@april.biz",
  "address": {
    "street": "Kulas Light",
    "city": "Gwenborough",
    "zipcode": "92998-3874"
  },
  "phone": "1-770-736-8031",
  "website": "hildegard.org"
}
Enter fullscreen mode Exit fullscreen mode

JSON Structure:

  • Objects are wrapped in curly braces {}
  • Arrays are wrapped in square brackets []
  • Key-value pairs are separated by colons :
  • Data types include strings, numbers, booleans, objects, and arrays

Making Different Types of Requests

GET Request - Fetching Data

// Fetch all posts
fetch('https://jsonplaceholder.typicode.com/posts')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));
Enter fullscreen mode Exit fullscreen mode

POST Request - Creating Data

// Create a new post
fetch('https://jsonplaceholder.typicode.com/posts', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    title: 'My New Post',
    body: 'This is the content of my post',
    userId: 1
  })
})
  .then(response => response.json())
  .then(data => console.log('Created:', data))
  .catch(error => console.error('Error:', error));
Enter fullscreen mode Exit fullscreen mode

Key differences for POST:

  • Specify method: 'POST'
  • Include headers to tell the server we're sending JSON
  • Use body to send the data (must be stringified)

PUT Request - Updating Data

// Update an existing post
fetch('https://jsonplaceholder.typicode.com/posts/1', {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    id: 1,
    title: 'Updated Title',
    body: 'Updated content',
    userId: 1
  })
})
  .then(response => response.json())
  .then(data => console.log('Updated:', data))
  .catch(error => console.error('Error:', error));
Enter fullscreen mode Exit fullscreen mode

DELETE Request - Removing Data

// Delete a post
fetch('https://jsonplaceholder.typicode.com/posts/1', {
  method: 'DELETE'
})
  .then(response => {
    if (response.ok) {
      console.log('Post deleted successfully');
    }
  })
  .catch(error => console.error('Error:', error));
Enter fullscreen mode Exit fullscreen mode

Understanding JSON.stringify()

What is stringification? It means converting JavaScript objects into text (strings). When you send data to an API, it needs to be in a text format that can travel over the internet.

Why Do We Need to Stringify?

The Problem

JavaScript objects exist only in your code's memory. They can't be sent over the internet directly.

// This is a JavaScript object (lives in your computer's memory)
const user = {
  name: "John",
  age: 25
};

// You CANNOT send this object directly to an API
// The internet doesn't understand JavaScript objects!
Enter fullscreen mode Exit fullscreen mode

The Solution

Convert the object to a JSON string - plain text that can travel anywhere.

// Convert object to string
const userString = JSON.stringify(user);

// Result: '{"name":"John","age":25}'
// This is now plain text that can be sent over the internet
Enter fullscreen mode Exit fullscreen mode

Visual Comparison

Before Stringification (JavaScript Object):

{
  name: "John",
  age: 25
}
Enter fullscreen mode Exit fullscreen mode

JSON.stringify()

After Stringification (Text String):

'{"name":"John","age":25}'
Enter fullscreen mode Exit fullscreen mode

Notice the difference:

  • Object: No quotes around the whole thing
  • String: Has quotes around everything, it's text

Complete Example

// Step 1: Create your data as a JavaScript object
const newPost = {
  title: 'My New Post',
  body: 'This is the content',
  userId: 1
};

// Step 2: Make the API request
fetch('https://jsonplaceholder.typicode.com/posts', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',  // Tell server: "I'm sending JSON"
  },
  body: JSON.stringify(newPost)  // Convert object to string HERE!
})
  .then(response => response.json())  // Convert string back to object
  .then(data => console.log(data));
Enter fullscreen mode Exit fullscreen mode

JSON.stringify() vs JSON.parse()

These are opposites - they do reverse operations:

JSON.stringify() - Object → String

const myObject = { name: "Sarah", age: 30 };
const myString = JSON.stringify(myObject);

console.log(myString);  
// Output: '{"name":"Sarah","age":30}'

console.log(typeof myString);  
// Output: "string"
Enter fullscreen mode Exit fullscreen mode

JSON.parse() - String → Object

const myString = '{"name":"Sarah","age":30}';
const myObject = JSON.parse(myString);

console.log(myObject);  
// Output: { name: "Sarah", age: 30 }

console.log(typeof myObject);  
// Output: "object"
Enter fullscreen mode Exit fullscreen mode

Real-World Analogy

Think of it like sending a package:

Sending Data (POST request):

  1. You have items (JavaScript object)
  2. You pack them in a box (JSON.stringify)
  3. You ship the box over the internet
  4. The server receives and unpacks it

Receiving Data (GET request):

  1. Server sends a packed box (JSON string)
  2. You receive it over the internet
  3. You unpack it (response.json() does JSON.parse)
  4. You use the items (JavaScript object)

Common Stringify Mistakes

Mistake 1: Forgetting to Stringify

// ❌ WRONG
fetch(url, {
  method: 'POST',
  body: { name: "John" }  // Not stringified!
})
Enter fullscreen mode Exit fullscreen mode
// ✅ CORRECT
fetch(url, {
  method: 'POST',
  body: JSON.stringify({ name: "John" })  // Stringified!
})
Enter fullscreen mode Exit fullscreen mode

Mistake 2: Not Setting Content-Type

// ❌ INCOMPLETE - missing header
fetch(url, {
  method: 'POST',
  body: JSON.stringify(data)  // Stringified, but...
  // Missing: headers with Content-Type!
})
Enter fullscreen mode Exit fullscreen mode
// ✅ COMPLETE
fetch(url, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'  // Tell server it's JSON
  },
  body: JSON.stringify(data)
})
Enter fullscreen mode Exit fullscreen mode

Testing Stringification

Try this in your browser console:

// Create an object
const person = {
  name: "Alice",
  age: 28,
  hobbies: ["reading", "coding"]
};

// Stringify it
const stringified = JSON.stringify(person);
console.log("Stringified:", stringified);
console.log("Type:", typeof stringified);  // "string"

// Parse it back
const parsed = JSON.parse(stringified);
console.log("Parsed back:", parsed);
console.log("Type:", typeof parsed);  // "object"
Enter fullscreen mode Exit fullscreen mode

Handling Errors Properly

Always handle errors when working with APIs. Networks can fail, APIs can go down, or you might send invalid data.

Basic Error Handling

fetch('https://jsonplaceholder.typicode.com/users/1')
  .then(response => {
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return response.json();
  })
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error.message));
Enter fullscreen mode Exit fullscreen mode

Comprehensive Error Handling

async function fetchUserWithErrorHandling(userId) {
  try {
    const response = await fetch(
      `https://jsonplaceholder.typicode.com/users/${userId}`
    );

    // Check if response is successful
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const data = await response.json();
    return data;

  } catch (error) {
    // Handle different types of errors
    if (error.message.includes('Failed to fetch')) {
      console.error('Network error - check your connection');
    } else if (error.message.includes('404')) {
      console.error('User not found');
    } else {
      console.error('An error occurred:', error.message);
    }
    return null;
  }
}

// Usage
fetchUserWithErrorHandling(1);
Enter fullscreen mode Exit fullscreen mode

Using Async/Await (Modern Approach)

The async/await syntax makes API calls easier to read and write:

Old Way (Promises)

fetch('https://jsonplaceholder.typicode.com/users/1')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error(error));
Enter fullscreen mode Exit fullscreen mode

New Way (Async/Await)

async function getUser() {
  try {
    const response = await fetch(
      'https://jsonplaceholder.typicode.com/users/1'
    );
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.error('Error:', error);
  }
}

getUser();
Enter fullscreen mode Exit fullscreen mode

Benefits of async/await:

  • More readable code
  • Easier error handling with try/catch
  • Looks similar to synchronous code
  • Better for complex operations with multiple API calls

Building a Complete Example: User Directory

Let's build a simple user directory that displays data from an API:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>User Directory</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      min-height: 100vh;
      padding: 20px;
    }

    .container {
      max-width: 1200px;
      margin: 0 auto;
    }

    h1 {
      color: white;
      text-align: center;
      margin-bottom: 30px;
      font-size: 2.5rem;
    }

    .controls {
      text-align: center;
      margin-bottom: 30px;
    }

    button {
      background: white;
      color: #667eea;
      border: none;
      padding: 12px 30px;
      border-radius: 25px;
      font-size: 16px;
      font-weight: bold;
      cursor: pointer;
      transition: all 0.3s ease;
    }

    button:hover {
      transform: translateY(-2px);
      box-shadow: 0 5px 15px rgba(0,0,0,0.3);
    }

    .loading {
      text-align: center;
      color: white;
      font-size: 1.2rem;
      margin: 50px 0;
    }

    .error {
      background: #ff6b6b;
      color: white;
      padding: 20px;
      border-radius: 10px;
      text-align: center;
      margin: 20px 0;
    }

    .user-grid {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
      gap: 20px;
    }

    .user-card {
      background: white;
      padding: 25px;
      border-radius: 15px;
      box-shadow: 0 5px 15px rgba(0,0,0,0.2);
      transition: transform 0.3s ease;
    }

    .user-card:hover {
      transform: translateY(-5px);
    }

    .user-card h2 {
      color: #667eea;
      margin-bottom: 10px;
    }

    .user-card p {
      color: #666;
      margin: 5px 0;
    }

    .user-card .label {
      font-weight: bold;
      color: #333;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>👥 User Directory</h1>

    <div class="controls">
      <button onclick="loadUsers()">Load Users</button>
    </div>

    <div id="content"></div>
  </div>

  <script>
    const contentDiv = document.getElementById('content');

    async function loadUsers() {
      try {
        // Show loading message
        contentDiv.innerHTML = '<div class="loading">Loading users...</div>';

        // Fetch users from API
        const response = await fetch(
          'https://jsonplaceholder.typicode.com/users'
        );

        // Check if request was successful
        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }

        // Parse JSON response
        const users = await response.json();

        // Display users
        displayUsers(users);

      } catch (error) {
        // Show error message
        contentDiv.innerHTML = `
          <div class="error">
            <h2>Oops! Something went wrong</h2>
            <p>${error.message}</p>
            <p>Please try again later.</p>
          </div>
        `;
        console.error('Error loading users:', error);
      }
    }

    function displayUsers(users) {
      const html = `
        <div class="user-grid">
          ${users.map(user => `
            <div class="user-card">
              <h2>${user.name}</h2>
              <p><span class="label">Username:</span> ${user.username}</p>
              <p><span class="label">Email:</span> ${user.email}</p>
              <p><span class="label">Phone:</span> ${user.phone}</p>
              <p><span class="label">Website:</span> ${user.website}</p>
              <p><span class="label">Company:</span> ${user.company.name}</p>
              <p><span class="label">City:</span> ${user.address.city}</p>
            </div>
          `).join('')}
        </div>
      `;

      contentDiv.innerHTML = html;
    }
  </script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

What this example demonstrates:

  • Loading state management
  • Error handling
  • Data transformation
  • Dynamic HTML generation
  • Responsive grid layout

Working with Query Parameters

APIs often accept query parameters to filter or customize results:

// Basic URL
const baseUrl = 'https://jsonplaceholder.typicode.com/posts';

// With query parameters
const urlWithParams = `${baseUrl}?userId=1&_limit=5`;

// Fetch posts by user 1, limited to 5 results
fetch(urlWithParams)
  .then(response => response.json())
  .then(data => console.log(data));
Enter fullscreen mode Exit fullscreen mode

Building URLs with URLSearchParams

// Create URL with parameters programmatically
const baseUrl = 'https://jsonplaceholder.typicode.com/posts';
const params = new URLSearchParams({
  userId: 1,
  _limit: 5
});

const fullUrl = `${baseUrl}?${params.toString()}`;
// Result: https://jsonplaceholder.typicode.com/posts?userId=1&_limit=5

fetch(fullUrl)
  .then(response => response.json())
  .then(data => console.log(data));
Enter fullscreen mode Exit fullscreen mode

API Authentication Basics

Many real-world APIs require authentication to protect data and track usage.

Common Authentication Methods

1. API Keys

const apiKey = 'your-api-key-here';

fetch('https://api.example.com/data', {
  headers: {
    'Authorization': `Bearer ${apiKey}`
  }
})
  .then(response => response.json())
  .then(data => console.log(data));
Enter fullscreen mode Exit fullscreen mode

2. Basic Authentication

const username = 'user';
const password = 'pass';
const credentials = btoa(`${username}:${password}`);

fetch('https://api.example.com/data', {
  headers: {
    'Authorization': `Basic ${credentials}`
  }
})
  .then(response => response.json())
  .then(data => console.log(data));
Enter fullscreen mode Exit fullscreen mode

Security Note: Never expose API keys in frontend code. Use environment variables and backend proxies for sensitive keys.


Best Practices for Working with APIs

1. Always Handle Errors

// Bad
fetch(url).then(r => r.json()).then(data => console.log(data));

// Good
fetch(url)
  .then(response => {
    if (!response.ok) throw new Error('Request failed');
    return response.json();
  })
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));
Enter fullscreen mode Exit fullscreen mode

2. Use Async/Await for Readability

// More readable than promise chains
async function getData() {
  try {
    const response = await fetch(url);
    const data = await response.json();
    return data;
  } catch (error) {
    console.error('Error:', error);
  }
}
Enter fullscreen mode Exit fullscreen mode

3. Don't Repeat Yourself - Create Helper Functions

// Reusable API call function
async function apiCall(url, options = {}) {
  try {
    const response = await fetch(url, options);
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return await response.json();
  } catch (error) {
    console.error('API call failed:', error);
    throw error;
  }
}

// Usage
const users = await apiCall('https://jsonplaceholder.typicode.com/users');
Enter fullscreen mode Exit fullscreen mode

4. Validate Data

async function getUser(userId) {
  const data = await apiCall(`https://api.example.com/users/${userId}`);

  // Validate the response has expected properties
  if (!data || !data.id || !data.name) {
    throw new Error('Invalid user data received');
  }

  return data;
}
Enter fullscreen mode Exit fullscreen mode

5. Handle Loading States

let isLoading = false;

async function fetchData() {
  if (isLoading) return; // Prevent duplicate requests

  isLoading = true;
  showLoadingSpinner();

  try {
    const data = await apiCall(url);
    displayData(data);
  } catch (error) {
    showError(error);
  } finally {
    isLoading = false;
    hideLoadingSpinner();
  }
}
Enter fullscreen mode Exit fullscreen mode

Free APIs for Practice

Here are some free public APIs you can use to practice:

No Authentication Required

Practice Projects

  1. Build a weather dashboard using OpenWeather API
  2. Create a random dog image generator
  3. Make a country information lookup tool
  4. Build a quote of the day app

Common Mistakes to Avoid

1. Forgetting to Parse JSON

// Wrong - response is not parsed
fetch(url).then(response => console.log(response));

// Right - parse JSON first
fetch(url)
  .then(response => response.json())
  .then(data => console.log(data));
Enter fullscreen mode Exit fullscreen mode

2. Not Checking Response Status

// Wrong - doesn't check if request succeeded
fetch(url)
  .then(response => response.json())
  .then(data => console.log(data));

// Right - check status first
fetch(url)
  .then(response => {
    if (!response.ok) throw new Error('Failed');
    return response.json();
  })
  .then(data => console.log(data));
Enter fullscreen mode Exit fullscreen mode

3. Exposing Sensitive Data

// Never do this in production code
const apiKey = 'sk_live_12345'; // Exposed to everyone
fetch(`https://api.example.com?key=${apiKey}`);

// Use environment variables instead
const apiKey = process.env.API_KEY;
Enter fullscreen mode Exit fullscreen mode

4. Not Handling Network Errors

// Wrong - no catch block
fetch(url).then(response => response.json());

// Right - always catch errors
fetch(url)
  .then(response => response.json())
  .catch(error => console.error('Network error:', error));
Enter fullscreen mode Exit fullscreen mode

5. Forgetting to Stringify POST Data

See the detailed explanation in the Understanding JSON.stringify() section.


Troubleshooting Guide

Issue: CORS Error

Error Message: "Access to fetch has been blocked by CORS policy"

Solution:

  • CORS errors occur when browsers block requests to different domains
  • For learning: Use APIs that allow CORS (like JSONPlaceholder)
  • For production: Configure CORS on your backend server
  • Alternative: Use a CORS proxy for testing (not for production)

Issue: JSON Parse Error

Error Message: "Unexpected token in JSON"

Solution:

// Check if response is actually JSON
const response = await fetch(url);
const contentType = response.headers.get('content-type');

if (contentType && contentType.includes('application/json')) {
  const data = await response.json();
} else {
  const text = await response.text();
  console.log('Response is not JSON:', text);
}
Enter fullscreen mode Exit fullscreen mode

Issue: Request Timeout

Solution:

// Add timeout to fetch request
const fetchWithTimeout = (url, timeout = 5000) => {
  return Promise.race([
    fetch(url),
    new Promise((_, reject) =>
      setTimeout(() => reject(new Error('Request timeout')), timeout)
    )
  ]);
};
Enter fullscreen mode Exit fullscreen mode

Next Steps

Now that you understand API basics, here's how to continue learning:

Immediate Practice

  1. Complete all the examples in this tutorial
  2. Modify the User Directory to display different data
  3. Try making POST, PUT, and DELETE requests
  4. Experiment with different public APIs

Intermediate Level

  • Learn about REST API design principles
  • Understand API rate limiting and pagination
  • Study API versioning
  • Learn about GraphQL as an alternative to REST
  • Explore API testing tools (Postman, Insomnia)

Advanced Topics

  • OAuth authentication flows
  • WebSockets for real-time data
  • Building your own API with Node.js/Express
  • API documentation with Swagger/OpenAPI
  • API security best practices

Key Takeaways

APIs enable communication between different applications and services

HTTP methods (GET, POST, PUT, DELETE) define what action to perform

Status codes indicate whether requests succeeded or failed

JSON.stringify() converts objects to strings for sending data

Always handle errors - networks fail and APIs have issues

Async/await makes API code more readable than promise chains

Parse JSON responses before

Top comments (0)