chore: copied WEB_API.md from, UpdateForge project for reference
This commit is contained in:
parent
f25a4bb680
commit
53e35c7263
1 changed files with 198 additions and 0 deletions
198
WEB_API.md
Normal file
198
WEB_API.md
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
# UpdateForge API
|
||||
|
||||
Base URL: `https://<your-server>`
|
||||
All API routes are under `/api/v1`.
|
||||
All request and response bodies are JSON.
|
||||
|
||||
---
|
||||
|
||||
## Authentication
|
||||
|
||||
UpdateForge uses **Bearer token** authentication. Obtain a token via the login endpoint and include it in every subsequent request:
|
||||
|
||||
```
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
Tokens are long-lived JWTs signed by the server. Store them securely (e.g. Android `EncryptedSharedPreferences`). There is no built-in expiry endpoint — simply re-authenticate when you receive a `401`.
|
||||
|
||||
---
|
||||
|
||||
## Endpoints
|
||||
|
||||
### `POST /api/v1/auth`
|
||||
|
||||
Authenticate with email and password. Does not require an existing token.
|
||||
|
||||
**Request**
|
||||
|
||||
```json
|
||||
{
|
||||
"email": "user@example.com",
|
||||
"password": "secret"
|
||||
}
|
||||
```
|
||||
|
||||
**Response `200`**
|
||||
|
||||
```json
|
||||
{
|
||||
"token": "eyJ...",
|
||||
"userId": "abc123",
|
||||
"email": "user@example.com"
|
||||
}
|
||||
```
|
||||
|
||||
**Error responses**
|
||||
|
||||
| Status | Body | Reason |
|
||||
| ------ | ---------------------------------------------- | ----------------------- |
|
||||
| `400` | `{"error": "email and password are required"}` | Missing fields |
|
||||
| `401` | `{"error": "invalid credentials"}` | Wrong email or password |
|
||||
|
||||
---
|
||||
|
||||
### `GET /api/v1/apps`
|
||||
|
||||
Returns all teams the authenticated user belongs to, each with its apps. A user may belong to multiple teams. Within each app, the response includes the latest **current** and **pending** version per build type.
|
||||
|
||||
- **current** — the highest semver version that has an artifact file attached. Always present (may be `null` if none exists yet).
|
||||
- **pending** — the highest semver version with no artifact file yet (work in progress). `null` when none exists.
|
||||
|
||||
Teams and apps are ordered oldest-first by creation date.
|
||||
|
||||
**Response `200`**
|
||||
|
||||
```json
|
||||
{
|
||||
"teams": [
|
||||
{
|
||||
"id": "team_id",
|
||||
"name": "Acme",
|
||||
"apps": [
|
||||
{
|
||||
"id": "app_id",
|
||||
"title": "My App",
|
||||
"packageName": "com.example.myapp",
|
||||
"icon": "/api/files/apps/app_id/icon.png",
|
||||
"release": {
|
||||
"current": {
|
||||
"id": "ver_id",
|
||||
"version": "1.2.0",
|
||||
"name": "January update",
|
||||
"public": true,
|
||||
"hasFile": true,
|
||||
"created": "2026-01-15T10:30:00Z"
|
||||
},
|
||||
"pending": null
|
||||
},
|
||||
"debug": {
|
||||
"current": {
|
||||
"id": "ver_id_2",
|
||||
"version": "1.3.0",
|
||||
"name": "",
|
||||
"public": false,
|
||||
"hasFile": true,
|
||||
"created": "2026-01-20T08:00:00Z"
|
||||
},
|
||||
"pending": {
|
||||
"id": "ver_id_3",
|
||||
"version": "1.4.0",
|
||||
"name": "Next sprint",
|
||||
"public": false,
|
||||
"hasFile": false,
|
||||
"created": "2026-01-21T09:00:00Z"
|
||||
}
|
||||
},
|
||||
"profile": {
|
||||
"current": null,
|
||||
"pending": null
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`teams` is an empty array if the user belongs to no teams.
|
||||
|
||||
**Version object fields**
|
||||
|
||||
| Field | Type | Description |
|
||||
| --------- | ------ | ------------------------------------------------------ |
|
||||
| `id` | string | Version record ID — use this for downloads |
|
||||
| `version` | string | Semantic version string, e.g. `"1.2.0"` |
|
||||
| `name` | string | Optional human-readable label, empty string if not set |
|
||||
| `public` | bool | Whether this version is intended for all testers |
|
||||
| `hasFile` | bool | Whether an artifact is available for download |
|
||||
| `created` | string | ISO 8601 UTC timestamp |
|
||||
|
||||
**Error responses**
|
||||
|
||||
| Status | Body | Reason |
|
||||
| ------ | --------------------------- | ------------------------ |
|
||||
| `401` | `{"error": "unauthorized"}` | Missing or invalid token |
|
||||
|
||||
---
|
||||
|
||||
### `GET /api/v1/versions/{id}/download`
|
||||
|
||||
Download the artifact file for a version. `{id}` is the version's `id` field from the apps response.
|
||||
|
||||
The response is the raw file with `Content-Type: application/octet-stream` and a `Content-Disposition: attachment` header carrying the original filename. Supports HTTP range requests, so partial downloads and resume work out of the box.
|
||||
|
||||
**Error responses**
|
||||
|
||||
| Status | Body | Reason |
|
||||
| ------ | -------------------------------- | ------------------------------------------ |
|
||||
| `401` | `{"error": "unauthorized"}` | Missing or invalid token |
|
||||
| `403` | `{"error": "forbidden"}` | User is not a member of the version's team |
|
||||
| `404` | `{"error": "version not found"}` | ID does not exist |
|
||||
| `404` | `{"error": "no file attached"}` | Version exists but `hasFile` is `false` |
|
||||
|
||||
---
|
||||
|
||||
## Build types
|
||||
|
||||
Every version belongs to exactly one build type:
|
||||
|
||||
| Type | Intended use |
|
||||
| --------- | ------------------------------------------- |
|
||||
| `release` | Production-ready builds for general testers |
|
||||
| `debug` | Debug builds with logging/tooling enabled |
|
||||
| `profile` | Performance-profiling builds |
|
||||
|
||||
---
|
||||
|
||||
## Icons
|
||||
|
||||
The `icon` field in the app object is a root-relative URL path. Prepend the server base URL to fetch it:
|
||||
|
||||
```
|
||||
GET https://<your-server>/api/files/apps/<app_id>/<filename>
|
||||
```
|
||||
|
||||
Icon files are served publicly and do not require authentication.
|
||||
|
||||
---
|
||||
|
||||
## Typical client flow
|
||||
|
||||
```
|
||||
1. POST /api/v1/auth → store token
|
||||
2. GET /api/v1/apps → display teams and their apps; cache version IDs
|
||||
3. For each app, compare installed version string with current.version
|
||||
4. If update available and current.hasFile == true:
|
||||
GET /api/v1/versions/{id}/download → save & install APK
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Error format
|
||||
|
||||
All error responses share the same shape:
|
||||
|
||||
```json
|
||||
{ "error": "<human-readable message>" }
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue