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.