-
Notifications
You must be signed in to change notification settings - Fork 5
Supporting multiple Lemmy API versions and other similar APIs
Christian :) edited this page Jun 4, 2025
·
2 revisions
This is a placeholder as I'm still working on support for multiple Lemmy versions.
But high level, the plan is:
const api = await apiClient({ instance: "https://lemmy.ml" })
// When we initialize apiClient, it will hit https://lemmy.ml/nodeinfo/2.1 and check which Lemmy version it's using
// Depending on the Lemmy version, 1 of 2 API wrappers will be returned, LemmyV3Api or LemmyV4Api
// LemmyV3Api and LemmyV4Api both implement abstract class ApiBlueprint
const post = api.getPost({ apId: "" })
// When I call the above function, it knows how to hit both Lemmy v3 or v4 Lemmy API endpoints depending
// on the API version hit https://lemmy.ml/nodeinfo/2.1 returned
// Instead of post being the raw data returned from the Lemmy API, we have normalized it by converting it
// into an internal representation of post that is identically regardless of the API version we are fetching from
// That means we can fetch from lemmy.ml v3, cache that data, fetch from lemmy.ml v4 the next day, and append to the cache
// without worrying about mixing data types since it's all been normalized
const postSchema = z.object({
createdAt: z.string(),
id: z.number(),
apId: z.string(),
communitySlug,
communityApId: z.string(),
creatorId: z.number(),
creatorApId: z.string(),
creatorSlug: z.string(),
title: z.string(),
body: z.string().nullable(),
thumbnailUrl: z.string().nullable(),
thumbnailAspectRatio: z.number().nullable(),
downvotes: z.number(),
upvotes: z.number(),
commentsCount: z.number(),
altText: z.string().optional(),
url: z.string().nullable(),
urlContentType: z.string().nullable(),
removed: z.boolean(),
optimisticRemoved: z.boolean().optional(),
deleted: z.boolean(),
optimisticDeleted: z.boolean().optional(),
crossPosts: z
.array(
z.object({
apId: z.string(),
communitySlug,
}),
)
.nullable(),
myVote: z.number().optional(),
optimisticMyVote: z.number().optional(),
featuredCommunity: z.boolean(),
optimisticFeaturedCommunity: z.boolean().optional(),
featuredLocal: z.boolean(),
optimisticFeaturedLocal: z.boolean().optional(),
read: z.boolean(),
optimisticRead: z.boolean().optional(),
saved: z.boolean(),
optimisticSaved: z.boolean().optional(),
});
// These internal representations of e.g. posts are defined via zod so we can validate the actual data if we want to.
// The example I've given is for post, but I plan on doing the same for person, community, comment, and maybe more
It's still a work in progress, but you can view the api adapter on this branch.