TABLE OF CONTENTS
- About Headless APIs
- This article aims to:
- Environment Setup
- Understanding the Target API
- Sending Requests to Endpoints
- Handling Responses
- Error Handling Strategies
- Authentication (Who You Are)
- Consuming APIs (Using the Access Token)
- API Discovery and Documentation
- Using the Data in Your Application
- Testing and Debugging
- Best Practices Summary
- Conclusion
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.
- 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.