All skills
asyrafhussin avatar

/api-design-patterns

@1de3a7a

RESTful API design, error handling, versioning, and best practices. Use when designing APIs, reviewing endpoints, implementing error responses, or setting up API structure. Triggers on "design API", "review API", "REST best practices", or "API patterns".

Use this Skill: https://skilld.dev/gh/asyrafhussin/agent-skills/api-design-patterns

This session only. Nothing lands on disk.

ruleserror-meaningful-messages.md

≈2k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Provide Meaningful Error Messages

Impact: CRITICAL (Reduces support burden and improves developer experience)

Error messages should be clear, actionable, and help users understand what went wrong and how to fix it.

Incorrect

// ❌ Vague or unhelpful messages
{
  "error": "Error"
}

{
  "error": "Bad request"
}

{
  "error": "Invalid input"
}

{
  "error": "Something went wrong"
}

{
  "error": "null"
}

{
  "error": "Error code: 0x8004005"
}

// ❌ Technical jargon users can't understand
{
  "error": "SQLITE_CONSTRAINT_FOREIGNKEY"
}

{
  "error": "MongoServerError: E11000 duplicate key error"
}
// ❌ Unhelpful error responses
app.post('/users', async (req, res) => {
  try {
    await db.createUser(req.body);
  } catch (error) {
    res.status(400).json({ error: 'Bad request' }); // What's bad about it?
  }
});

Problems:

  • Users cannot determine what went wrong or how to fix it
  • Developers waste time debugging vague error messages
  • Support burden increases with every unclear error
  • Internal database errors leak implementation details
  • No actionable guidance for the next step

Correct

// ✅ Clear, actionable error messages
const errorMessages = {
  email_required: 'Email address is required to create an account',
  email_invalid: 'Please provide a valid email address (e.g., user@example.com)',
  email_taken: 'An account with this email already exists. Try signing in instead',
  password_weak: 'Password must be at least 8 characters with one uppercase, one lowercase, and one number',
  rate_limited: 'Too many requests. Please wait 60 seconds before trying again',
  resource_not_found: 'The requested user could not be found. It may have been deleted',
  permission_denied: 'You do not have permission to access this resource. Contact your administrator',
  payment_failed: 'Your payment could not be processed. Please check your card details and try again'
};

app.post('/users', async (req, res, next) => {
  try {
    const { email, password, name } = req.body;

    // Specific validation messages
    if (!email) {
      return res.status(400).json({
        error: {
          code: 'validation_error',
          message: 'Email address is required to create an account',
          field: 'email'
        }
      });
    }

    if (!isValidEmail(email)) {
      return res.status(400).json({
        error: {
          code: 'validation_error',
          message: 'Please provide a valid email address (e.g., user@example.com)',
          field: 'email',
          provided: email
        }
      });
    }

    const existingUser = await db.findUserByEmail(email);
    if (existingUser) {
      return res.status(409).json({
        error: {
          code: 'resource_conflict',
          message: 'An account with this email already exists. Try signing in or resetting your password',
          field: 'email',
          links: {
            signin: '/auth/signin',
            passwordReset: '/auth/password-reset'
          }
        }
      });
    }

    const user = await db.createUser({ email, password, name });
    res.status(201).json(user);

  } catch (error) {
    next(error);
  }
});
# ✅ FastAPI with meaningful errors
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, validator, EmailStr

app = FastAPI()

class UserCreate(BaseModel):
    email: EmailStr
    password: str
    name: str

    @validator('password')
    def password_strength(cls, v):
        if len(v) < 8:
            raise ValueError(
                'Password must be at least 8 characters long. '
                'Strong passwords help protect your account.'
            )
        if not any(c.isupper() for c in v):
            raise ValueError(
                'Password must contain at least one uppercase letter (A-Z)'
            )
        if not any(c.islower() for c in v):
            raise ValueError(
                'Password must contain at least one lowercase letter (a-z)'
            )
        if not any(c.isdigit() for c in v):
            raise ValueError(
                'Password must contain at least one number (0-9)'
            )
        return v

    @validator('name')
    def name_not_empty(cls, v):
        if not v or not v.strip():
            raise ValueError(
                'Name is required. Please enter your full name as you would '
                'like it to appear on your profile.'
            )
        if len(v) > 100:
            raise ValueError(
                f'Name must be 100 characters or less. You entered {len(v)} characters.'
            )
        return v.strip()

@app.post("/users")
async def create_user(user: UserCreate):
    existing = await db.find_user_by_email(user.email)
    if existing:
        raise HTTPException(
            status_code=409,
            detail={
                "code": "email_already_registered",
                "message": (
                    f"The email '{user.email}' is already registered. "
                    "If this is your email, try signing in or resetting your password."
                ),
                "suggestions": [
                    "Sign in with your existing account",
                    "Reset your password if you forgot it",
                    "Use a different email address"
                ]
            }
        )
    return await db.create_user(user)
// ✅ Good error response examples

// Validation error with guidance
{
  "error": {
    "code": "validation_error",
    "message": "The email address format is invalid",
    "details": [
      {
        "field": "email",
        "message": "Please provide a valid email address (e.g., user@example.com)",
        "provided": "not-an-email",
        "suggestion": "Check for typos and ensure the email includes an @ symbol"
      }
    ]
  }
}

// Resource not found with context
{
  "error": {
    "code": "resource_not_found",
    "message": "Order #12345 could not be found",
    "details": [
      {
        "message": "This order may have been deleted or the ID may be incorrect",
        "suggestions": [
          "Verify the order ID is correct",
          "Check your order history for the correct ID",
          "The order may have been archived after 90 days"
        ]
      }
    ]
  }
}

// Permission error with next steps
{
  "error": {
    "code": "permission_denied",
    "message": "You don't have permission to delete this project",
    "details": [
      {
        "message": "Only project owners and administrators can delete projects",
        "currentRole": "member",
        "requiredRoles": ["owner", "admin"],
        "suggestion": "Contact the project owner to request deletion or elevated permissions"
      }
    ]
  }
}

// Rate limit with retry info
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "You've made too many requests. Please slow down.",
    "details": [
      {
        "limit": 100,
        "window": "1 minute",
        "retryAfter": 45,
        "message": "You can make another request in 45 seconds"
      }
    ]
  }
}

Benefits:

  • Clear messages help users fix problems without contacting support
  • Self-explanatory errors reduce support ticket volume
  • API consumers can debug issues faster with meaningful context
  • Actionable guidance tells users what to do next, not just what went wrong
  • Professional error messages build confidence in your API
  • Clear messages are easier to translate for localization

Reference: Microsoft REST API Guidelines - Errors

Source: SKILL.md on GitHub

1 alert16d5 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    This skill is a comprehensive documentation library for RESTful API design patterns. It provides best practices for resource design, error handling, security, and documentation. The skill contains no executable code, malicious instructions, or hidden functionality, and its references are restricted to well-known technical documentation sources.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer6mo

    4/28 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 1de3a7a. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub last month.

Steadyupdated 7 months ago
metadata
{
  "author": "agent-skills",
  "version": "2.0.0"
}

README badge

README badge for asyrafhussin/agent-skills/api-design-patterns