npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@jentic/problem-details

v1.0.1

Published

RFC 9457 Problem Details types for Jentic APIs

Downloads

182

Readme

@jentic/problem-details (TypeScript)

RFC 9457 Problem Details types for Jentic APIs.

Installation

npm install @jentic/problem-details

Quick Start

Type Definitions

import type { ProblemDetail, ErrorItem } from '@jentic/problem-details';

// Use as response types
interface ApiError extends ProblemDetail {
	// Add custom fields if needed
}

// Type-safe error handling
function handleError(error: ProblemDetail) {
	console.log(`${error.status}: ${error.title}`);
	console.log(error.detail);
	
	if (error.errors) {
		error.errors.forEach(err => {
			if (err.pointer) {
				console.log(`  - ${err.pointer}: ${err.detail}`);
			}
		});
	}
}

Creating Problem Details

import { createProblemDetail, createErrorItem } from '@jentic/problem-details';

// Simple error
const notFound = createProblemDetail.notFound('User not found', {
	instance: '/api/users/123',
});

// Validation error with multiple fields
const validation = createProblemDetail.validationError(
	'Multiple validation errors occurred',
	{
		instance: '/api/users',
		errors: [
			createErrorItem("Field 'name' is required", { pointer: '#/name' }),
			createErrorItem("Field 'email' must be valid", { pointer: '#/email' }),
		],
	}
);

Error Handling with Fetch

import { ProblemDetailError } from '@jentic/problem-details';

async function fetchUser(id: string) {
	const response = await fetch(`/api/users/${id}`);
	
	if (!response.ok) {
		throw await ProblemDetailError.fromResponse(response);
	}
	
	return response.json();
}

// Usage
try {
	const user = await fetchUser('123');
} catch (err) {
	if (err instanceof ProblemDetailError) {
		console.error('API Error:', err.problemDetail);
		
		// Access structured error data
		if (err.problemDetail.status === 404) {
			console.log('User not found');
		}
		
		// Show validation errors to user
		if (err.problemDetail.errors) {
			err.problemDetail.errors.forEach(error => {
				console.log(`${error.pointer}: ${error.detail}`);
			});
		}
	} else {
		console.error('Unexpected error:', err);
	}
}

Type Guards

import { isProblemDetail, isErrorItem } from '@jentic/problem-details';

// Check if response is a ProblemDetail
const response = await fetch('/api/users');
const data = await response.json();

if (isProblemDetail(data)) {
	console.error('API returned error:', data.detail);
	
	if (data.errors && data.errors.every(isErrorItem)) {
		// TypeScript knows these are ErrorItems
		data.errors.forEach(err => console.log(err.detail));
	}
}

React Example

import { useState } from 'react';
import { ProblemDetailError, type ProblemDetail } from '@jentic/problem-details';

function UserForm() {
	const [error, setError] = useState<ProblemDetail | null>(null);

	async function handleSubmit(data: FormData) {
		try {
			const response = await fetch('/api/users', {
				method: 'POST',
				body: JSON.stringify(data),
			});

			if (!response.ok) {
				throw await ProblemDetailError.fromResponse(response);
			}

			// Success
		} catch (err) {
			if (err instanceof ProblemDetailError) {
				setError(err.problemDetail);
			}
		}
	}

	return (
		<form onSubmit={handleSubmit}>
			{error && (
				<div className="error">
					<h3>{error.title}</h3>
					<p>{error.detail}</p>
					{error.errors && (
						<ul>
							{error.errors.map((err, i) => (
								<li key={i}>
									{err.pointer && <strong>{err.pointer}:</strong>} {err.detail}
								</li>
							))}
						</ul>
					)}
				</div>
			)}
			{/* Form fields */}
		</form>
	);
}

API Reference

Types

ProblemDetail

interface ProblemDetail {
	type?: string;        // URI identifying problem type (default: "about:blank")
	status?: number;      // HTTP status code
	title?: string;       // Short summary of the problem
	detail: string;       // Human-readable explanation (required)
	instance?: string;    // URI reference to this occurrence
	code?: string;        // Provider-specific error code
	errors?: ErrorItem[]; // Array of granular error details
}

ErrorItem

interface ErrorItem {
	detail: string;    // Human-readable error explanation (required)
	pointer?: string;  // JSON Pointer to request body property
	parameter?: string;// Query/path parameter name
	header?: string;   // Request header name
	code?: string;     // Provider-specific code
}

Functions

createProblemDetail

Factory functions for common HTTP errors:

  • createProblemDetail.badRequest(detail, options?) — 400
  • createProblemDetail.unauthorized(detail, options?) — 401
  • createProblemDetail.forbidden(detail, options?) — 403
  • createProblemDetail.notFound(detail, options?) — 404
  • createProblemDetail.conflict(detail, options?) — 409
  • createProblemDetail.validationError(detail, options?) — 422
  • createProblemDetail.tooManyRequests(detail, options?) — 429
  • createProblemDetail.serverError(detail, options?) — 500
  • createProblemDetail.serviceUnavailable(detail, options?) — 503

createErrorItem(detail, options?)

Helper to create validation error items.

isProblemDetail(obj)

Type guard to check if an object is a ProblemDetail.

isErrorItem(obj)

Type guard to check if an object is an ErrorItem.

Classes

ProblemDetailError extends Error

Custom error class carrying RFC 9457 Problem Details data.

Constructor:

new ProblemDetailError(problemDetail: ProblemDetail)

Properties:

  • problemDetail: ProblemDetail — The problem detail data

Static Methods:

  • ProblemDetailError.fromResponse(response: Response): Promise<ProblemDetailError> — Create from a fetch Response

Methods:

  • toJSON(): ProblemDetail — Serialize to JSON

Development

# Install dependencies
npm install

# Build
npm run build

# Run tests
npm test

# Type checking
npm run typecheck

# Coverage
npm run test:coverage

Standards

License

@jentic/problem-details is licensed under Apache 2.0 license. @jentic/problem-details comes with an explicit NOTICE file containing additional legal notices and information.