Package Exports
- @kyvan2x/payload-rest-client
- @kyvan2x/payload-rest-client/dist/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@kyvan2x/payload-rest-client) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
payload-rest-client
A typesafe rest api client for the payload cms.
Quick Start
- Assume you have a users (auth enabled) and a posts collection with following fields:
interface User {
id: string;
email: string;
name: string;
password: string;
createdAt: string;
updatedAt: string;
}
interface Post {
id: string;
title: string;
content: string;
createdAt: string;
updatedAt: string;
}
- Create the client:
import { createClient } from "@kyvan2x/payload-rest-client";
import { Config } from "./payload-types"; // auto generated types from payload
type Locales = "de" | "en";
const client = createClient<Config, Locales>({
apiUrl: "http://localhost:4000/api",
});
- Now you can use all available queries for all collections and globals in a typesafe way:
// if you wan't to use protected routes, use login api...
const loginResponse = await client.collections.users.login({
email: process.env.PAYLOAD_API_EMAIL,
password: process.env.PAYLOAD_API_PASSWORD,
});
// ...and create another client with authorization header
const protectedClient = createClient<Config, Locales>({
apiUrl: "http://localhost:4000/api",
headers: {
"Authorization": `Bearer ${loginResponse.token}`,
},
});
const posts = await protectedClient.collections.posts.find({
sort: "title", // only top level keys (optionally prefixed with "-") of Post allowed
locale: "de", // only defined locales allowed
limit: 10,
page: 2,
});
console.log(posts); // type of posts is FindResult<Post>
Error Handling
The client provides two approaches for error handling:
1. Traditional try/catch approach
import {
PayloadClientError,
ValidationError,
UnauthorizedError,
NotFoundError
} from "@kyvan2x/payload-rest-client";
try {
const user = await client.collections.users.create({
doc: { email: "invalid-email", name: "Test" }
});
} catch (error) {
if (error instanceof ValidationError) {
// Get structured validation errors
const fieldErrors = error.getFieldErrors();
console.log("Field errors:", fieldErrors);
// Get full error data
const errorData = error.getErrorData();
console.log("Error details:", errorData);
} else if (error instanceof UnauthorizedError) {
console.log("Authentication required");
} else if (error instanceof PayloadClientError) {
console.log(`API Error (${error.statusCode}):`, error.message);
console.log("Response data:", error.data);
}
}
2. Functional error handling with client.safe
For a more functional approach without try/catch blocks, use the safe
version of the client:
// Using the safe client - returns [error, undefined] or [undefined, result]
const [error, user] = await client.safe.collections.users.create({
doc: { email: "invalid-email", name: "Test" }
});
if (error) {
if (error instanceof ValidationError) {
const fieldErrors = error.getFieldErrors();
console.log("Validation failed:", fieldErrors);
} else {
console.log("Error:", error.message);
}
return;
}
// user is guaranteed to be defined here
console.log("User created:", user.doc);
3. Using the standalone tryCatch
utility
You can also use the tryCatch
utility function directly:
import { tryCatch, ValidationError, UnauthorizedError } from "@kyvan2x/payload-rest-client";
// Catch specific error types
const [error, result] = await tryCatch(
client.collections.users.create({ doc: userData }),
[ValidationError, UnauthorizedError]
);
if (error) {
// Handle specific errors
console.log("Caught expected error:", error.message);
} else {
// Success case
console.log("User created:", result.doc);
}
// Catch all errors
const [anyError, posts] = await tryCatch(
client.collections.posts.find()
);
if (anyError) {
console.log("Something went wrong:", anyError.message);
} else {
console.log("Posts:", posts.docs);
}
Error Types
PayloadClientError
: Base error class withstatusCode
,data
, andresponse
propertiesValidationError
(400): Validation errors with field-specific detailsUnauthorizedError
(401): Authentication requiredForbiddenError
(403): Access deniedNotFoundError
(404): Resource not foundConflictError
(409): Resource conflictServerError
(500+): Server-side errors
Custom Endpoints
- Define input and output types for alle custom endpoints:
import { CustomEndpoint } from "@kyvan2x/payload-rest-client";
/**
* shape of generic CustomEndpoint type
*
* type Input = {
* params?: Record<string, string>;
* query?: Record<string, any>;
* body?: any;
* };
*
* type Output = any;
*
* type CustomEndpoint<Input, Output>;
*/
type CustomEndpoints = {
greet: CustomEndpoint<{
params: { name: string };
query: { locale: Locales };
}, string>,
};
- Add it to
createClient
function:
-const client = createClient<Config, Locales>({
- apiUrl: "http://localhost:4000/api",
-});
+const client = createClient<Config, Locales, CustomEndpoints>({
+ apiUrl: "http://localhost:4000/api",
+ customEndpoints: {
+ greet: { method: "GET", path: params => `hello/${params.name}` },
+ },
+});
- Call custom endpoints like this:
// Traditional approach
try {
const greeting = await client.custom.greet({
params: { name: "John Doe" },
query: { locale: "en" },
});
console.log(greeting);
} catch (error) {
console.error("Failed to greet:", error);
}
// Safe approach
const [error, greeting] = await client.safe.custom.greet({
params: { name: "John Doe" },
query: { locale: "en" },
});
if (error) {
console.error("Failed to greet:", error.message);
} else {
console.log("Greeting:", greeting);
}
API
Full documentation of the rest api
Client options
apiUrl
: string - Base URL for the Payload APIcache?
: RequestCache - Cache strategy for requestsheaders?
: HeadersInit - Default headers to include with requestsdebug?
: boolean - Enable debug logginggetAdditionalFetchOptions?
: (params: GetAdditionalFetchOptionsParams) => any - Function to add additional fetch optionscustomFetchFn?
: (input: RequestInfo | URL, init?: RequestInit) => Promise- Custom fetch function customEndpoints?
: Record<String, CustomEndpointFactory> - Custom endpoint definitions
Collections
find
: (params?: FindParams<T, LOCALES>) => Promise<FindResult> findById
: (params: FindByIdParams) => Promise count
: (params?: CountParams) => Promise create
: (params: CreateParams<T, LOCALES>) => Promise<CreateResult> createDraft
: (params: CreateDraftParams<T, LOCALES>) => Promise<CreateDraftResult> update
: (params: UpdateParams<T, LOCALES>) => Promise<UpdateResult> updateById
: (params: UpdateByIdParams<T, LOCALES>) => Promise<UpdateByIdResult> delete
: (params?: DeleteParams<T, LOCALES>) => Promise<DeleteResult> deleteById
: (params: DeleteByIdParams) => Promise
Collections with auth enabled (additional to above)
login
: (params: LoginParams) => Promise<LoginResult> logout
: (params?: LogoutParams) => Promiseunlock
: (params: UnlockParams) => Promiserefresh-token
: (params?: RefreshTokenParams) => Promiseme
: (params?: MeParams) => Promise<MeResult> forgot-password
: (params: ForgotPasswordParams) => Promisereset-password
: (params: ResetPasswordParams) => Promise<ResetPasswordResult>
Globals
get
: (params?: BaseParams) => Promise update
: (params: UpdateGlobalParams<T, LOCALES>) => Promise
Others
access
: () => Promise
Changelog
v 3.0.7
- NEW: Added functional error handling with
client.safe
- no more try/catch needed! - NEW: Added
tryCatch
utility function for manual error handling - NEW: All client methods now available in both traditional and safe versions
- BREAKING: Client now returns an object with both regular and safe APIs
- Added: Complete TypeScript support for safe error handling patterns
- Added: Comprehensive examples for both error handling approaches
v 3.0.6
- BREAKING: Improved error handling with structured error types
- BREAKING: Better query string encoding with proper URL encoding
- BREAKING: Enhanced type safety for auth endpoints (optional parameters)
- Fixed: JSON error responses are now properly parsed and preserved as objects
- Fixed: Content-Type header is only added when there's a request body
- Fixed: Better handling of network errors and malformed responses
- Fixed: Improved debug logging with more detailed information
- Added: Comprehensive error types with field-specific validation errors
- Added: Better handling of array parameters in query strings
- Added: Input validation for client options
v 3.0.5
- Infer id params (
string
ornumber
) from type.
v 3.0.4
- Added custom endpoints
v 3.0.3
- Added option to use custom fetch function
v 3.0.2
- Export error types
- Added access api
v 3.0.1
- Better type inference for joins
v 3.0.0
- Payload 3 (for Payload 2 use older versions)
- Added
select
,populate
andjoin
params - Added
count
api