weableColor Icon
OverviewPricingDocsToolsBlogCase Studies
Get Started
Back to Blog

Tutorial: Server-Side Accessibility Checks with @weable/a11y-color-utils API

7/27/2025

color
accessibility
wcag
apca
api
server-side
node.js
express
tutorial
@weable/a11y-color-utils

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

  1. Create a new project directory:
    mkdir a11y-color-api
    cd a11y-color-api
    npm init -y
    
  2. Install dependencies:
    npm install express @weable/a11y-color-utils
    # Optional: Install nodemon for easier development
    # npm install --save-dev nodemon
    
  3. Create a server.js file.

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

  1. Setup: We import express and the necessary functions from @weable/a11y-color-utils.
  2. Middleware: express.json() is used to automatically parse incoming JSON request bodies.
  3. Route (/check-contrast): A POST route is defined.
  4. Input Handling: It expects a JSON body like {"textColor": "#ffffff", "backgroundColor": "#000000"}. It performs basic validation to ensure both colors are present.
  5. Color Conversion: hexToRgb converts the input HEX strings to RGB objects, which are required by the contrast functions. Further validation checks if the conversion was successful.
  6. Contrast Calculation: getColorContrast (WCAG) and getColorContrastAPCA are called with the RGB color pairs.
  7. 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.
  8. Error Handling: A basic try...catch block handles potential errors during calculation and returns a 500 status code.
  9. 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 joi or zod for stricter validation of the request body schema and color formats.
  • Advanced APCA: Modify the API to accept fontSize and fontWeight parameters 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.

weableColor Icon
weableColor

Making accessibility sexy, one color at a time. Professional tools for developers who care about inclusive design.

WCAG 2.1 AA
APCA Ready
Products

© 2025 weableColor. All rights reserved. Made with ❤️ for accessible design.

Built with:

TypeScript
SACA