Tutorial: Server-Side Accessibility Checks with @weable/a11y-color-utils API
7/27/2025
Tutorial: Server-Side Accessibility Checks with @weable/a11y-color-utils API
While client-side checks are useful during development, integrating accessibility checks into your backend offers powerful automation possibilities. You can validate user-generated content, ensure programmatic color combinations meet standards, or build internal tools. This tutorial shows how to create a simple Node.js API endpoint using Express and @weable/a11y-color-utils to perform these checks.
Prerequisites
- Node.js and npm (or yarn) installed.
- Basic understanding of Node.js, Express, and REST APIs.
- Familiarity with color concepts (HEX, RGB).
Project Setup
- Create a new project directory:
mkdir a11y-color-api cd a11y-color-api npm init -y - Install dependencies:
npm install express @weable/a11y-color-utils # Optional: Install nodemon for easier development # npm install --save-dev nodemon - Create a
server.jsfile.
API Implementation (server.js)
We'll create a simple Express server with one POST endpoint (/check-contrast) that accepts a JSON body containing textColor and backgroundColor (as HEX strings) and returns their WCAG 2.x and APCA contrast values.
// server.js
const express = require('express');
const {
getColorContrast,
getColorContrastAPCA,
hexToRgb,
} = require('@weable/a11y-color-utils');
const app = express();
const port = process.env.PORT || 3000;
// Middleware to parse JSON bodies
app.use(express.json());
// --- API Endpoint: /check-contrast ---
app.post('/check-contrast', (req, res) => {
const { textColor: textColorHex, backgroundColor: backgroundColorHex } = req.body;
// Basic Input Validation
if (!textColorHex || !backgroundColorHex) {
return res.status(400).json({ error: 'Missing textColor or backgroundColor in request body.' });
}
const textColorRgb = hexToRgb(textColorHex);
const backgroundColorRgb = hexToRgb(backgroundColorHex);
if (!textColorRgb || !backgroundColorRgb) {
return res.status(400).json({ error: 'Invalid HEX color format provided.' });
}
try {
// --- Perform Contrast Checks ---
const wcagContrast = getColorContrast(textColorRgb, backgroundColorRgb);
const apcaContrast = getColorContrastAPCA(textColorRgb, backgroundColorRgb);
// --- Prepare Response ---
const response = {
inputs: {
textColor: textColorHex,
backgroundColor: backgroundColorHex,
},
results: {
wcag: {
ratio: parseFloat(wcagContrast.toFixed(2)),
// Example pass/fail interpretation (adjust per requirements)
aaNormalPass: wcagContrast >= 4.5,
aaaNormalPass: wcagContrast >= 7.0,
},
apca: {
lc: parseFloat(apcaContrast.toFixed(1)),
// Example interpretation (highly context-dependent!)
// Thresholds like 60, 75, 90 depend on font size/weight/use case.
meetsLc60: Math.abs(apcaContrast) >= 60,
},
},
};
res.json(response);
} catch (error) {
console.error('Error calculating contrast:', error);
res.status(500).json({ error: 'Internal server error during contrast calculation.' });
}
});
// --- Start Server ---
app.listen(port, () => {
console.log(`Accessibility Color Check API listening on http://localhost:${port}`);
});
Explanation
- Setup: We import
expressand the necessary functions from@weable/a11y-color-utils. - Middleware:
express.json()is used to automatically parse incoming JSON request bodies. - Route (
/check-contrast): A POST route is defined. - Input Handling: It expects a JSON body like
{"textColor": "#ffffff", "backgroundColor": "#000000"}. It performs basic validation to ensure both colors are present. - Color Conversion:
hexToRgbconverts the input HEX strings to RGB objects, which are required by the contrast functions. Further validation checks if the conversion was successful. - Contrast Calculation:
getColorContrast(WCAG) andgetColorContrastAPCAare called with the RGB color pairs. - Response: The results (WCAG ratio and APCA Lc value) are packaged into a JSON object. We include example pass/fail boolean flags based on common thresholds (WCAG 4.5:1 AA, 7:1 AAA for normal text; APCA Lc 60). Remember that APCA interpretation is highly dependent on font characteristics and context.
- Error Handling: A basic
try...catchblock handles potential errors during calculation and returns a 500 status code. - Server Start: The server starts listening on the specified port (defaulting to 3000).
Running the Server
node server.js
# Or if using nodemon:
# nodemon server.js
The console should output: Accessibility Color Check API listening on http://localhost:3000
Testing the API
You can use tools like curl, Postman, or Insomnia to test the endpoint.
Example using curl:
curl -X POST http://localhost:3000/check-contrast \
-H "Content-Type: application/json" \
-d '{
"textColor": "#FFFFFF",
"backgroundColor": "#777777"
}'
Expected Response (Example):
{
"inputs": {
"textColor": "#FFFFFF",
"backgroundColor": "#777777"
},
"results": {
"wcag": {
"ratio": 4.57,
"aaNormalPass": true,
"aaaNormalPass": false
},
"apca": {
"lc": 61.9,
"meetsLc60": true
}
}
}
Next Steps
- Robust Error Handling: Implement more specific error handling and logging.
- Input Validation: Use a library like
joiorzodfor stricter validation of the request body schema and color formats. - Advanced APCA: Modify the API to accept
fontSizeandfontWeightparameters to provide more contextually accurate APCA interpretations or use lookup tables based on the APCA guidelines. - Batch Processing: Create an endpoint that accepts an array of color pairs for bulk checking.
- Deployment: Deploy the API using platforms like Heroku, Vercel (Serverless Functions), AWS Lambda, etc.
- Authentication/Authorization: Secure the API if it's intended for wider use.
This tutorial demonstrates how easily you can leverage @weable/a11y-color-utils on the server-side to build powerful, automated accessibility workflows.