@aibulat/restclients/jsonplaceholder
jsonplaceholder.typicode.com — fake blog data with full CRUD. No key, no limits.
import {JsonPlaceHolderApi} from '@aibulat/restclients/jsonplaceholder';
const api = new JsonPlaceHolderApi();
const res = await api.getPosts({limit: 5});jsonplaceholder is a testing service: nothing is persisted. Created and updated items are echoed back with a plausible id, but you cannot read one back. Point the client at a local json-server if you need real writes:
const local = new JsonPlaceHolderApi({baseUrl: 'http://localhost:3000'});Methods
Every method takes an optional trailing RequestOptions — a RequestInit plus timeout, params and validateStatus.
Collections
getPosts(options?, config?)
getComments(options?, config?)
getAlbums(options?, config?)
getPhotos(options?, config?)
getTodos(options?, config?)
getUsers(options?, config?)options is either a bare number (a limit, which is what these took before 3.0.0) or a ListOptions object:
interface ListOptions {
limit?: number, // _limit
start?: number, // _start
page?: number, // _page
sort?: string, // _sort
order?: 'asc' | 'desc',
embed?: string, // _embed
expand?: string // _expand
}
await api.getPosts(5);
await api.getPosts({limit: 5, sort: 'id', order: 'desc'});Single items
getPost(id, options?, config?)
getComment(id, options?, config?)
getAlbum(id, options?, config?)
getPhoto(id, options?, config?)
getTodo(id, options?, config?)
getUser(id, options?, config?)options here is ItemOptions — just embed and expand.
Nested routes
getPostComments(postId, options?, config?)
getAlbumPhotos(albumId, options?, config?)
getUserPosts(userId, options?, config?)
getUserAlbums(userId, options?, config?)
getUserTodos(userId, options?, config?)
getCommentsByPost(postId, config?) // the ?postId= form of the same thingWrites
createPost(item, config?) // and createComment, createAlbum, createPhoto, createTodo, createUser
updatePost(id, item, config?) // PUT, replaces the whole item
patchPost(id, item, config?) // PATCH, partial
deletePost(id, config?)…and the same five siblings for each verb.
Types
Entities carry the server-assigned id: Post, Comment, Album, Photo, Todo, User (plus Geo, Address, Company nested inside User). Full definitions are in the shipped .d.ts — your editor has them.
Create and update take the entity without its id, because the server assigns it and on update it travels in the URL:
import type {NewPost} from '@aibulat/restclients/jsonplaceholder';
const draft: NewPost = {
userId: 1,
title: 'Comparing Floating-Point Numbers Is Tricky',
body: 'https://bitbashing.io/comparing-floats.html'
};
const res = await api.createPost(draft);
console.log((await res.json()).id); // assigned by the serverNewComment, NewAlbum, NewPhoto, NewTodo and NewUser follow the same Omit<T, 'id'> pattern. Patch methods take a Partial of these.
Notes
_embedand_expandare single strings. json-server reads a repeated?_embed=a&_embed=b, and the shared params helper comma-joins arrays instead. Pass a per-request config if you need more than one.- Embedded fields are not typed.
getPost(1, {embed: 'comments'})still resolves toPost; the extracommentsarray is there at runtime but the type does not know about it. - Changed in 3.0.0:
getPosts(0)now sends_limit=0rather than dropping the param. Onlyundefinedmeans "absent" now — see core.