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