Files
Modrinth-plus/packages/api-client
Truman Gao 681ae5d1d8 refactor: removing useAsyncData for tanstack query (#5262)
* refactor: most places with useAsyncData replaced with tanstack query

* refactor report list and report view

* refactor organization page to use tanstack query

* fix types

* refactor collection page and include proper loading state

* fix followed projects proper loading state

* fix 404 handling

* fix organization loading and 404 states

* pnpm prepr

* refactor: remove useAsyncData on newsletter button

* refactor: remove useAsyncData on auth globals fetch

* refactor: settings/billing/index.vue to useQuery instead of useAsyncData

* refactor: user page to remove useAsyncData

* pnpm prepr

* fix reports pages

* fix notifications page

* fix billing page cannot read properties of null and prop warnings

* fix refresh causing 404 by removing useBaseFetch and use api-client

* fix stale data after removing organization from project

* pnpm prepr

* fix news erroring in build

* fix: project page loads header only after content

* fix: user page tanstack problems (start on migrating away from useBaseFetch)

* fix: start swapping useBaseFetch usages to api-client

* Revert "fix: start swapping useBaseFetch usages to api-client"

This reverts commit 3df3fab11d535159132b1288dd7cacc38282b553.

* fix: remove debug logging

* fix: lint

---------

Co-authored-by: Calum H. <calum@modrinth.com>
Co-authored-by: Calum H. (IMB11) <contact@cal.engineer>
2026-03-16 19:10:29 +00:00
..
2025-11-12 20:29:12 +00:00

Modrinth Monorepo Cover

@modrinth/api-client

TypeScript License: GPL-3.0

A flexible, type-safe API client for Modrinth's APIs (Labrinth, Kyros & Archon). Works across Node.js, browsers, Nuxt, and Tauri with a feature system for authentication, retries, circuit breaking and other custom processing of requests and responses.

Installation

pnpm add @modrinth/api-client
# or
npm install @modrinth/api-client
# or
yarn add @modrinth/api-client

Usage

Plain JavaScript/Node.js

import { GenericModrinthClient, AuthFeature, ProjectV2 } from '@modrinth/api-client'

const client = new GenericModrinthClient({
	userAgent: 'my-app/1.0.0',
	features: [new AuthFeature({ token: 'mrp_...' })],
})

// Explicitly make a request using client.request
const project: any = await client.request('/project/sodium', { api: 'labrinth', version: 2 })

// Example for archon (Modrinth Hosting)
const servers = await client.request('/servers?limit=10', { api: 'archon', version: 0 })

// Or use the provided wrappers for better type support.
const project: ProjectV2 = await client.projects_v2.get('sodium')

Nuxt

import { NuxtModrinthClient, AuthFeature, NuxtCircuitBreakerStorage } from '@modrinth/api-client'

// Alternatively you can create a singleton of the client and provide it via DI.
export const useModrinthClient = () => {
	const config = useRuntimeConfig()

	// example using the useAuth composable from our frontend, replace this with whatever you're using to store auth token
	const auth = await useAuth()

	return new NuxtModrinthClient({
		userAgent: 'my-nuxt-app/1.0.0', // leave blank to use default user agent from fetch function
		rateLimitKey: import.meta.server ? config.rateLimitKey : undefined,
		features: [
			new AuthFeature({
				token: async () => auth.value.token,
			}),
			new CircuitBreakerFeature({
				storage: new NuxtCircuitBreakerStorage(),
			}),
		],
	})
}

const client = useModrinthClient()
const project = await client.request('/project/sodium', { api: 'labrinth', version: 2 })

Tauri

import { TauriModrinthClient, AuthFeature } from '@modrinth/api-client'
import { getVersion } from '@tauri-apps/api/app'

const version = await getVersion()
const client = new TauriModrinthClient({
	userAgent: `modrinth/theseus/${version} (support@modrinth.com)`,
	features: [new AuthFeature({ token: 'mrp_...' })],
})

const project = await client.request('/project/sodium', { api: 'labrinth', version: 2 })

Overriding Base URLs

By default, the client uses the production base URLs:

  • labrinthBaseUrl: https://api.modrinth.com/ (Labrinth API)
  • archonBaseUrl: https://archon.modrinth.com/ (Archon/Servers API)

You can override these for staging environments or custom instances:

const client = new GenericModrinthClient({
	userAgent: 'my-app/1.0.0',
	labrinthBaseUrl: 'https://staging-api.modrinth.com/',
	archonBaseUrl: 'https://staging-archon.modrinth.com/',
	features: [new AuthFeature({ token: 'mrp_...' })],
})

// Now requests will use the staging URLs
await client.request('/project/sodium', { api: 'labrinth', version: 2 })
// -> https://staging-api.modrinth.com/v2/project/sodium

You can also use custom URLs directly in requests:

// One-off custom URL (useful for Kyros nodes or dynamic endpoints)
await client.request('/some-endpoint', {
	api: 'https://eu-lim16.nodes.modrinth.com/',
	version: 0,
})

Features

Authentication

Supports both static and dynamic tokens:

// Static token
new AuthFeature({ token: 'mrp_...' })

// Dynamic token (e.g., from auth state)
const auth = await useAuth()
new AuthFeature({
	token: async () => auth.value.token,
})

Retry

Automatically retries failed requests with configurable backoff:

new RetryFeature({
	maxAttempts: 3,
	backoffStrategy: 'exponential',
	initialDelay: 1000,
	maxDelay: 15000,
})

Circuit Breaker

Prevents cascade failures by opening circuits after repeated failures:

new CircuitBreakerFeature({
	maxFailures: 3,
	resetTimeout: 30000,
	failureStatusCodes: [500, 502, 503, 504],
})

Documentation

This package is self-documenting through TypeScript types and JSDoc comments. Use your IDE's IntelliSense to explore available methods, classes, and configuration options.

For Modrinth API endpoints and routes, refer to the Modrinth API Documentation.

Contributing

  • Modules are available in the modules/<api>/... folders.
    • When a module has different versions available, you should do it like so: modules/labrinth/projects/v2.ts etc.
    • Types for a module's requests should be made available in modules/<api>/module/types.ts or .../types/v2.ts.
    • You should expose these types in the modules/types.ts file.
  • When creating a new module, add it to the modules/index.ts's MODULE_REGISTRY for it to become available in the api client class.

Dont forget to run pnpm fix before committing.

License

Licensed under GPL-3.0 - see the LICENSE file for details.