Files
MyActivityPub/docs/API.md
2026-01-24 17:45:29 +01:00

338 líneas
9.3 KiB
Markdown

# API Documentation
## Overview
This document describes the Mastodon API integration used in My ActivityPub app. The app communicates with Mastodon-compatible servers using their REST API v1.
## Base URL
Default: `https://mastodon.social/`
You can configure this to any Mastodon or ActivityPub-compatible instance.
## Authentication
Currently, the app accesses public endpoints that don't require authentication. Future versions will implement OAuth 2.0 for authenticated requests.
## Endpoints
### 1. Get Public Timeline
Retrieve statuses from the public timeline.
**Endpoint**: `GET /api/v1/timelines/public`
**Parameters**:
- `limit` (integer, optional): Maximum number of results. Default: 20
- `local` (boolean, optional): Show only local statuses. Default: false
- `max_id` (string, optional): Return results older than this ID
- `since_id` (string, optional): Return results newer than this ID
- `min_id` (string, optional): Return results immediately newer than this ID
**Example Request**:
```
GET https://mastodon.social/api/v1/timelines/public?limit=20&local=false
```
**Response**: Array of Status objects
**Example Response**:
```json
[
{
"id": "109382159165398564",
"created_at": "2022-11-23T07:49:01.940Z",
"content": "<p>Hello world!</p>",
"account": {
"id": "109382",
"username": "alice",
"display_name": "Alice",
"avatar": "https://...",
...
},
"media_attachments": [],
"favourites_count": 5,
"reblogs_count": 2,
"replies_count": 1,
...
}
]
```
### 2. Get Instance Information
Get information about the Mastodon instance.
**Endpoint**: `GET /api/v1/instance`
**Parameters**: None
**Example Request**:
```
GET https://mastodon.social/api/v1/instance
```
**Response**: Instance object
**Example Response**:
```json
{
"uri": "mastodon.social",
"title": "Mastodon",
"short_description": "The original server operated by the Mastodon gGmbH non-profit",
"description": "...",
"version": "4.0.0",
"languages": ["en"],
"thumbnail": "https://..."
}
```
### 3. Get Account
Get account information.
**Endpoint**: `GET /api/v1/accounts/:id`
**Parameters**:
- `id` (string, required): Account ID
**Example Request**:
```
GET https://mastodon.social/api/v1/accounts/109382
```
**Response**: Account object
**Example Response**:
```json
{
"id": "109382",
"username": "alice",
"acct": "alice",
"display_name": "Alice",
"locked": false,
"bot": false,
"created_at": "2022-11-23T07:49:01.940Z",
"note": "<p>Bio goes here</p>",
"url": "https://mastodon.social/@alice",
"avatar": "https://...",
"header": "https://...",
"followers_count": 100,
"following_count": 50,
"statuses_count": 500
}
```
### 4. Get Account Statuses
Get statuses posted by an account.
**Endpoint**: `GET /api/v1/accounts/:id/statuses`
**Parameters**:
- `id` (string, required): Account ID
- `limit` (integer, optional): Maximum number of results. Default: 20
- `max_id` (string, optional): Return results older than this ID
- `since_id` (string, optional): Return results newer than this ID
- `exclude_replies` (boolean, optional): Skip statuses that reply to other statuses
- `exclude_reblogs` (boolean, optional): Skip statuses that are reblogs of other statuses
- `only_media` (boolean, optional): Show only statuses with media attached
**Example Request**:
```
GET https://mastodon.social/api/v1/accounts/109382/statuses?limit=20
```
**Response**: Array of Status objects
## Data Models
### Status
Represents a post/toot on Mastodon.
**Properties**:
```typescript
{
id: string // Unique identifier
created_at: string // ISO 8601 datetime
content: string // HTML content
account: Account // Account that posted this status
media_attachments: Array // Media attachments
reblog: Status | null // If this is a reblog, the original status
favourites_count: number // Number of favorites
reblogs_count: number // Number of reblogs/boosts
replies_count: number // Number of replies
favourited: boolean // Has the current user favorited this?
reblogged: boolean // Has the current user reblogged this?
url: string | null // URL to the status
visibility: string // Visibility level (public, unlisted, private, direct)
}
```
### Account
Represents a user account.
**Properties**:
```typescript
{
id: string // Unique identifier
username: string // Username (without @domain)
acct: string // Full username (@username@domain)
display_name: string // Display name
avatar: string // URL to avatar image
header: string // URL to header image
note: string // Bio/description (HTML)
url: string | null // URL to profile page
followers_count: number // Number of followers
following_count: number // Number of accounts being followed
statuses_count: number // Number of statuses posted
bot: boolean // Is this a bot account?
locked: boolean // Does this account require follow requests?
}
```
### MediaAttachment
Represents media files attached to statuses.
**Properties**:
```typescript
{
id: string // Unique identifier
type: string // Type: image, video, gifv, audio, unknown
url: string // URL to the media file
preview_url: string | null // URL to the preview/thumbnail
remote_url: string | null // Remote URL if the media is from another server
description: string | null // Alt text description
}
```
### Instance
Represents a Mastodon instance.
**Properties**:
```typescript
{
uri: string // Domain name
title: string // Instance name
description: string // Long description (HTML)
short_description: string // Short description (plaintext)
version: string // Mastodon version
thumbnail: string | null // URL to thumbnail image
languages: Array<string> // ISO 639 Part 1-5 language codes
email: string | null // Contact email
contact_account: Account // Contact account
}
```
## Error Handling
The API returns standard HTTP status codes:
- `200 OK` - Request succeeded
- `400 Bad Request` - Invalid parameters
- `401 Unauthorized` - Authentication required
- `403 Forbidden` - Access denied
- `404 Not Found` - Resource not found
- `429 Too Many Requests` - Rate limit exceeded
- `500 Internal Server Error` - Server error
- `503 Service Unavailable` - Server temporarily unavailable
**Error Response Format**:
```json
{
"error": "Error message here"
}
```
## Rate Limiting
Mastodon implements rate limiting to prevent abuse. Limits vary by instance but typically:
- 300 requests per 5 minutes for authenticated requests
- Lower limits for unauthenticated requests
Rate limit information is returned in response headers:
- `X-RateLimit-Limit` - Maximum number of requests
- `X-RateLimit-Remaining` - Remaining requests in current window
- `X-RateLimit-Reset` - Time when the limit resets (ISO 8601)
## Best Practices
1. **Respect Rate Limits**: Implement exponential backoff when hitting rate limits
2. **Cache Responses**: Cache instance info and other static data
3. **Use Pagination**: Use `max_id` and `since_id` for efficient pagination
4. **Handle Errors**: Always handle network errors and API errors gracefully
5. **Validate Input**: Validate user input before making API calls
6. **Use HTTPS**: Always use HTTPS for API requests
7. **Set User-Agent**: Include a descriptive User-Agent header
## Implementation in the App
### Service Layer
`MastodonApiService.kt` defines the API interface using Retrofit annotations:
```kotlin
interface MastodonApiService {
@GET("api/v1/timelines/public")
suspend fun getPublicTimeline(
@Query("limit") limit: Int = 20,
@Query("local") local: Boolean = false
): Response<List<Status>>
// Other endpoints...
}
```
### Repository Layer
`MastodonRepository.kt` wraps API calls with error handling:
```kotlin
suspend fun getPublicTimeline(limit: Int = 20, local: Boolean = false): Result<List<Status>> {
return withContext(Dispatchers.IO) {
try {
val response = apiService.getPublicTimeline(limit, local)
if (response.isSuccessful) {
Result.success(response.body() ?: emptyList())
} else {
Result.failure(Exception("Error: ${response.code()}"))
}
} catch (e: Exception) {
Result.failure(e)
}
}
}
```
### ViewModel Layer
`TimelineViewModel.kt` manages UI state and calls repository methods:
```kotlin
fun loadTimeline() {
viewModelScope.launch {
_uiState.value = TimelineUiState.Loading
repository.getPublicTimeline().fold(
onSuccess = { statuses ->
_uiState.value = TimelineUiState.Success(statuses)
},
onFailure = { error ->
_uiState.value = TimelineUiState.Error(error.message ?: "Unknown error")
}
)
}
}
```
## Further Reading
- [Official Mastodon API Documentation](https://docs.joinmastodon.org/api/)
- [ActivityPub Specification](https://www.w3.org/TR/activitypub/)
- [Retrofit Documentation](https://square.github.io/retrofit/)
- [Kotlin Coroutines Guide](https://kotlinlang.org/docs/coroutines-guide.html)