Skillshub appfolio-sdk-patterns
install
source · Clone the upstream repo
git clone https://github.com/ComeOnOliver/skillshub
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/ComeOnOliver/skillshub "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/jeremylongshore/claude-code-plugins-plus-skills/appfolio-sdk-patterns" ~/.claude/skills/comeonoliver-skillshub-appfolio-sdk-patterns && rm -rf "$T"
manifest:
skills/jeremylongshore/claude-code-plugins-plus-skills/appfolio-sdk-patterns/SKILL.mdsource content
appfolio sdk patterns | sed 's/\b(.)/\u\1/g'
Overview
Production patterns for AppFolio API: typed client, pagination, response caching, and error handling.
Instructions
Step 1: Typed API Client
// src/appfolio/typed-client.ts import axios, { AxiosInstance } from "axios"; interface Property { id: string; name: string; property_type: string; address: { street: string; city: string; state: string; zip: string }; unit_count: number; } interface Tenant { id: string; first_name: string; last_name: string; email: string; phone: string; unit_id: string; } interface Lease { id: string; unit_id: string; tenant_name: string; start_date: string; end_date: string; rent_amount: number; status: string; } class AppFolioTypedClient { private api: AxiosInstance; constructor() { this.api = axios.create({ baseURL: process.env.APPFOLIO_BASE_URL, auth: { username: process.env.APPFOLIO_CLIENT_ID!, password: process.env.APPFOLIO_CLIENT_SECRET! }, timeout: 30000, }); } async getProperties(): Promise<Property[]> { return (await this.api.get("/properties")).data; } async getTenants(): Promise<Tenant[]> { return (await this.api.get("/tenants")).data; } async getLeases(): Promise<Lease[]> { return (await this.api.get("/leases")).data; } } export { AppFolioTypedClient, Property, Tenant, Lease };
Step 2: Response Cache
const cache = new Map<string, { data: any; expiry: number }>(); async function cachedGet<T>(client: AxiosInstance, path: string, ttlMs = 60000): Promise<T> { const cached = cache.get(path); if (cached && cached.expiry > Date.now()) return cached.data; const { data } = await client.get(path); cache.set(path, { data, expiry: Date.now() + ttlMs }); return data; }