Headless API Consumption

TABLE OF CONTENTS


About Headless APIs

A headless API (Application Programming Interface) provides data and functionality without dictating how it should be presented. It separates the back-end (data and logic) from the front-end (user interface), allowing developers to build diverse applications (web, mobile, Internet of Things) using the same back-end source.

This guide provides a step-by-step explanation of how to consume Znode’s headless APIs effectively—from setup to implementation and testing.

This article aims to:

  • Explain the structure and purpose of Znode's headless multi-store APIs.
  • Demonstrate how to authenticate and interact with the APIs for various e-commerce functionalities such as product catalog, cart, checkout, and customer management.
  • Highlight best practices and use cases for integrating these APIs into custom applications and digital Storefronts.
  • Enable development teams to accelerate implementation and deliver scalable, flexible, and personalized e-commerce solutions using Znode’s headless architecture.


Prerequisites

To interact with an API over the network, a suitable HTTP client is required. The appropriate tool depends on the programming language and environment:

JavaScript (Node.js):

  • node-fetch or axios (libraries)
  • Built-in http or https modules (lower-level)

C# / .NET:

  • HttpClient (built-in)

Manual Testing/Exploration:

  • Postman
  • Insomnia

Environment Setup

The following tools and configurations are required for consuming Znode APIs:

  • Visual Studio 2022 or later
  • SQL Server
  • Git access for repository management
  • NuGet package source URL for access to internal/private NuGet feeds
  • CLI tools (optional) for Admin Console setup

Znode API Client Packages

Ensure the following client packages are available or can be generated as needed:

  • Znode10.Engine.ApiV2.Client
  • Znode10.Engine.Api.Client
  • Znode10.Engine.CommercePortal.Client
  • Znode10.Payment.API.Client
  • Znode10.Engine.Custom.Api.Client

Note: Install the generated client details from the packages listed above.

Understanding the Target API

Before writing code, it is essential to understand the API thoroughly:

  • Base URL: The root URL for all API endpoints (e.g., https://api.example.com/v1/)
  • Endpoints: Specific paths for different resources or actions (e.g., /users, /products/{id})
  • HTTP Methods: Identify which methods (GET, POST, PUT, DELETE, etc.) are used for each endpoint
  • Authentication: Understand authentication mechanisms (API keys, OAuth tokens, JWT), typically sent in headers
  • Request Parameters: Determine required and optional parameters
  • Request/Response Formats: Usually JSON
  • Rate Limits: Understand request limits
  • Error Codes: Learn how different errors are indicated

Sending Requests to Endpoints

Examples for common HTTP methods using tools such as axios or fetch:

GET (Retrieve Data)

async function getUsers() {
  try {
    const response = await apiClient.get('/users');
    return response.data;
  } catch (error) {
    handleApiError(error);
    return null;
  }
}
async function getUserById(userId) {
  try {
    const response = await apiClient.get(`/users/${userId}`);
    return response.data;
  } catch (error) {
    handleApiError(error);
    return null;
  }
}

POST (Create Data)

async function createUser(userData) {
  try {
    const response = await apiClient.post('/users', userData);
    return response.data;
  } catch (error) {
    handleApiError(error);
    return null;
  }
}

PUT (Update Data)

async function updateUser(userId, updatedData) {
  try {
    const response = await apiClient.put(`/users/${userId}`, updatedData);
    return response.data;
  } catch (error) {
    handleApiError(error);
    return null;
  }
}

DELETE (Remove Data)

async function deleteUser(userId) {
  try {
    const response = await apiClient.delete(`/users/${userId}`);
    return true;
  } catch (error) {
    handleApiError(error);
    return false;
  }
}

Handling Responses

Steps for Processing Responses

  • Check the Status Code
    • 200 OK – Success (GET/PUT)
    • 201 Created – Resource created (POST)
    • 204 No Content – Success with no body (DELETE)
  • Parse the Response Body
    • Use .json() in fetch or rely on automatic parsing in axios
  • Check Headers
    • Headers may include pagination, rate limit details, etc.

Example using fetch:

async function getUsersWithFetch() {
  try {
    const response = await fetch('https://api.example.com/v1/users', {
      headers: {
        'Authorization': `Bearer ${localStorage.getItem('authToken')}`
      }
    });
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    if (response.status === 204) {
       return [];
    }
    return await response.json();
  } catch (error) {
    console.error("Fetch error:", error);
    return null;
  }
}

Error Handling Strategies

Implement robust error handling for reliability:

  • Network Errors: Use try...catch or .catch()
  • HTTP Status Errors: Use status codes to provide clear user feedback
    • 400: Invalid input
    • 401/403: Authentication issues
    • 404: Resource not found
  • Server Errors (5xx): Log errors and notify users generically
  • Response Body Errors: Check for logical errors even if the status is 200
  • Data Validation: Validate the structure and types of received data

Example Error Handling Function

function handleApiError(error) {
  if (error.response) {
    if (error.response.status === 401) {
      alert('Authentication failed. Please log in.');
    } else if (error.response.status === 404) {
      alert('Requested item not found.');
    } else {
      alert('An error occurred while communicating with the server.');
    }
  } else if (error.request) {
    alert('Network error. Please check your connection.');
  } else {
    alert('An unexpected error occurred.');
  }
}

Authentication (Who You Are)

Authentication is required to verify identity before API access.

  • Obtain Credentials: Provided by the Znode account manager
  • Request Access Token:

POST /token
Host: <Your Znode Instance URL>/token
Content-Type: application/x-www-form-urlencoded


Sample Response:

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6Ikp...",
  "hasError": false,
  "errorCode": null,
  "errorMessage": null,
  "refreshToken": "nFWgjnUb80aKb5kL2VAfbA",
  "refreshTokenExpiryTime": null
}


Token Expiration:

"JWTExpirySpan": 30, // Minutes
"JWTRefreshExpirySpan": 30 // Days

Consuming APIs (Using the Access Token)

In every API request, include the following header:

Authorization: Bearer <your_access_token>

Example: Postman

GET /api/v2/products HTTP/1.1
Host: <Your Znode Instance URL>
Authorization: Bearer <your_access_token>


Example: .NET (C#)

using System;
using System.Net.Http;
using System.Threading.Tasks;
class Program {
  static async Task Main(string[] args) {
    using (HttpClient client = new HttpClient()) {
      client.BaseAddress = new Uri("https://api.example.com/");
      HttpResponseMessage response = await client.GetAsync("endpoint");
      if (response.IsSuccessStatusCode) {
        string data = await response.Content.ReadAsStringAsync();
        Console.WriteLine(data);
      } else {
        Console.WriteLine($"Error: {response.StatusCode}");
      }
    }
  }
}

Example: JavaScript (Vanilla)

fetch('https://api.example.com/endpoint')
  .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));

Example: React

import React, { useEffect, useState } from 'react';
const App = () => {
  const [data, setData] = useState(null);
  useEffect(() => {
    fetch('https://api.example.com/endpoint')
      .then(response => {
        if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
        return response.json();
      })
      .then(data => setData(data))
      .catch(error => console.error('Error:', error));
  }, []);
  return (
    <div>
      <h1>API Data</h1>
      {data ? <pre>{JSON.stringify(data, null, 2)}</pre> : <p>Loading...</p>}
    </div>
  );
};
export default App;

API Discovery and Documentation

Znode uses Stoplight for API documentation: apidocs.znode.com

Benefits:

  • Interactive reference for all endpoints
  • Detailed request/response structure
  • Code samples in various languages

Using the Data in Your Application

After retrieving data:

  • Store in application state (e.g., React state, Vuex)
  • Bind to UI elements
  • Trigger application logic

Testing and Debugging

  • API Clients: Use Postman or Insomnia
  • Browser Dev Tools: Inspect requests and logs
  • Logging: Log status, payload, and endpoint (avoid sensitive data)
  • Code Debugging: Step through using IDE
  • Automated Testing:
    • Unit: Mock API responses
    • Integration: Use staging/test environments

Best Practices Summary

  • Read the API documentation thoroughly
  • Centralize API logic into reusable services
  • Handle errors clearly and gracefully
  • Secure credentials using environment variables
  • Validate all API responses
  • Follow REST conventions
  • Implement rate-limit handling and caching strategies
  • Use kabab-case routing with camelCase parameters
  • Leverage built-in paging and validation
  • Authenticate using a gateway-based token mechanism
  • Use Stoplight and Swagger documentation

Conclusion

Consuming headless APIs is critical for building modern, scalable ecommerce applications. Znode's headless capabilities allow for flexible integration across various front-end frameworks, enabling rich user experiences while maintaining centralized business logic and data management.

Did you find it helpful? Yes No

Send feedback
Sorry we couldn't be helpful. Help us improve this article with your feedback.