# Documentación de la API

Esta página cubre los estándares para documentar APIs usando especificaciones OpenAPI en todos los servicios de Decentraland.

## Objetivos

Nuestro enfoque de documentación de API garantiza:

* **Estandarización** - Especificaciones OpenAPI consistentes en todos los servicios
* **Automatización** - Validación, empaquetado y despliegue mediante GitHub Actions
* **Centralización** - Toda la documentación de servicios publicada a través de GitBook
* **Propiedad** - La documentación vive en el repositorio de cada servicio
* **Accesibilidad** - Referencias de API amigables para contribuidores y actualizadas

***

## Estructura del repositorio

Cada repositorio de servicio DEBE incluir un `/docs` directorio con la siguiente estructura:

```bash
/docs
  openapi.yaml        # Fuente de verdad (OpenAPI 3.1)
  openapi.json        # Generado automáticamente en CI para Hugo/renderers
  index.html          # Documentación independiente generada automáticamente (opcional)
```

### Requisitos de archivos

#### `openapi.yaml`

* **DEBE** ser el archivo fuente canónico
* **DEBE** usar la especificación OpenAPI 3.1
* **PUEDE** tener un prefijo que identifique el servicio (p. ej., `worlds-openapi.yaml`)
* **PUEDE** dividirse en `components/` o `examples/` directorios si es necesario

#### `openapi.json`

* Generado automáticamente durante CI/CD
* Usado por Hugo y otros renderers
* No editar manualmente

#### `index.html`

* Documentación independiente generada automáticamente
* Construido usando Redocly
* Desplegado en GitHub Pages

***

## Estándares OpenAPI

Al escribir `openapi.yaml`, sigue estas convenciones para asegurar consistencia y claridad.

### Resumen del endpoint

**DEBE** refleja la ruta real del endpoint:

```yaml
# ✅ Bueno: Ruta de endpoint clara
paths:
  /world/{world_name}/about:
    get:
      summary: /world/{world_name}/about
      description: Recupera información sobre un world específico
      
# ❌ Malo: Resumen genérico
paths:
  /world/{world_name}/about:
    get:
      summary: Obtener info del world
```

### Operation ID

**DEBE** incluye el nombre del servicio para unicidad global:

```yaml
# ✅ Bueno: Operation ID con prefijo de servicio
operationId: worldsContentServer_getWorldAbout

# ✅ Bueno: Otro ejemplo
operationId: socialService_getFriends

# ❌ Malo: Genérico, podría entrar en conflicto
operationId: getAbout
```

**Convención de nombres**: `{serviceName}_{operationDescription}`

* Usa camelCase
* Sé descriptivo pero conciso
* Incluye el contexto del método HTTP cuando sea útil (p. ej., `createUser`, `deleteParcel`)

### Versionado

**DEBE** usa versionado semántico (`MAJOR.MINOR.PATCH`) en `info.version`:

```yaml
openapi: 3.1.0
info:
  title: Worlds Content Server API
  version: 1.2.0  # Versionado semántico
  description: API para gestionar Decentraland worlds
```

**Reglas para incrementar la versión**:

* **MAJOR**: Cambios incompatibles (cambios rompientes en la API)
* **MINOR**: Nueva funcionalidad (compatible hacia atrás)
* **PATCH**: Correcciones de bugs (compatible hacia atrás)

### Etiquetas y agrupación

**DEBE** usa tags para agrupar endpoints relacionados:

```yaml
tags:
  - name: Worlds
    description: Operaciones de gestión de worlds
  - name: Deployments
    description: Operaciones de despliegue de worlds
  - name: Health
    description: Endpoints de chequeo de salud

paths:
  /worlds:
    get:
      tags:
        - Worlds
      summary: /worlds
      operationId: worldsContentServer_listWorlds
      
  /worlds/{world_name}/about:
    get:
      tags:
        - Worlds
      summary: /worlds/{world_name}/about
      operationId: worldsContentServer_getWorldAbout
```

{% hint style="info" %}
Las operaciones se agrupan por tag en la navegación de GitBook. Agrupa endpoints relacionados bajo el mismo tag para una mejor organización.
{% endhint %}

### Ejemplo completo

```yaml
openapi: 3.1.0
info:
  title: Social Service API
  version: 2.1.0
  description: API para gestionar interacciones sociales en Decentraland
  contact:
    name: Decentraland Contributors
    url: https://decentraland.org

servers:
  - url: https://social.decentraland.org
    description: Servidor de producción
  - url: https://social.decentraland.zone
    description: Servidor de staging

tags:
  - name: Friends
    description: Gestión de amigos
  - name: Blocked Users
    description: Operaciones de bloqueo de usuarios

paths:
  /friends:
    get:
      tags:
        - Friends
      summary: /friends
      operationId: socialService_getFriends
      description: Devuelve la lista de amigos del usuario autenticado
      parameters:
        - name: limit
          in: query
          schema:
            type: integer
            default: 50
            maximum: 100
        - name: offset
          in: query
          schema:
            type: integer
            default: 0
      responses:
        '200':
          description: Respuesta exitosa
          content:
            application/json:
              schema:
                type: object
                properties:
                  friends:
                    type: array
                    items:
                      $ref: '#/components/schemas/Friend'
        '401':
          description: No autorizado

components:
  schemas:
    Friend:
      type: object
      required:
        - address
        - createdAt
      properties:
        address:
          type: string
          description: Dirección de Ethereum del amigo
        createdAt:
          type: string
          format: date-time
          description: Cuando se estableció la amistad
```

***

## Desarrollo local

### Previsualizar documentación localmente

Usa Redocly CLI para previsualizar tu documentación OpenAPI:

```bash
# Construir documentación HTML
yarn redocly build-docs docs/openapi.yaml -o docs/index.html

# Luego abre docs/index.html en tu navegador
```

### Agregar a package.json

Agrega un script de build por conveniencia:

```json
{
  "scripts": {
    "build:api": "redocly bundle docs/openapi.yaml -o docs/openapi.json --ext json && redocly build-docs docs/openapi.yaml -o docs/index.html",
    "preview:api": "redocly preview-docs docs/openapi.yaml"
  }
}
```

### Instalar Redocly CLI

```bash
# Usando npm
npm install -g @redocly/cli

# Usando yarn
yarn global add @redocly/cli
```

### Validar especificación OpenAPI

```bash
# Valida tu especificación
redocly lint docs/openapi.yaml

# Empaquetar y validar
redocly bundle docs/openapi.yaml
```

***

## Configuración de automatización

### Paso 1: Configurar secretos de GitBook

Para publicar especificaciones de API en GitBook, agrega estos secretos a tu repositorio:

**Settings → Secrets and variables → Actions → New repository secret**

| Nombre del secreto        | Descripción                         | Dónde encontrar                 |
| ------------------------- | ----------------------------------- | ------------------------------- |
| `GITBOOK_ORGANIZATION_ID` | El ID de tu organización en GitBook | GitBook Settings → Organization |
| `GITBOOK_TOKEN`           | Token de la API de GitBook          | GitBook Settings → API Tokens   |

{% hint style="warning" %}
Estos secretos DEBEN estar configurados para que el flujo de trabajo automatizado publique en GitBook.
{% endhint %}

### Paso 2: Agregar workflow de GitHub Actions

Crear `.github/workflows/build-api-docs.yml` en tu repositorio:

```yaml
name: build-app-docs

on:
  push:
    branches: [main]
    paths:
      - 'docs/**'
  pull_request:
    paths:
      - 'docs/**'

jobs:
  build:
    uses: decentraland/platform-actions/.github/workflows/apps-docs.yml@main
    with:
      api-spec-file: 'docs/openapi.yaml'
      output-file: 'docs/index.html'
      output-directory: './docs'
      api-spec-name: '{service-name}-api'  # p. ej., 'social-service-api'
      node-version: '20'
    secrets: inherit
```

**Parámetros**:

* `api-spec-file`: Ruta a tu especificación OpenAPI (usualmente `docs/openapi.yaml`)
* `output-file`: Dónde generar la documentación HTML
* `output-directory`: Directorio para los archivos de salida
* `api-spec-name`: Nombre único para tu especificación de API (usado en GitBook)
* `node-version`: Versión de Node.js a usar

**Este workflow hará**:

1. ✅ Validar la especificación OpenAPI
2. ✅ Empaquetar la especificación en un único archivo
3. ✅ Construir documentación HTML estática usando Redocly
4. ✅ Desplegar automáticamente en GitHub Pages
5. ✅ Publicar la especificación en GitBook (si los secretos están configurados)

### Paso 3: Habilitar GitHub Pages

Configura GitHub Pages en tu repositorio:

1. Ve a **Settings → Pages**
2. Bajo **Build and deployment**:
   * Establece **Source** a **GitHub Actions**
3. Asegúrate de que exista un environment llamado **github-pages**
4. Guardar configuraciones

Después de la primera ejecución exitosa del workflow, tu documentación estará disponible en:

* **Docs HTML**: `https://decentraland.github.io/<repo>/index.html`
* **Especificación OpenAPI**: `https://decentraland.github.io/<repo>/openapi.yaml`
* **JSON empaquetado**: `https://decentraland.github.io/<repo>/openapi.json`

{% hint style="success" %}
Estas URLs permanecen válidas mientras el repositorio exista y GitHub Pages esté habilitado.
{% endhint %}

***

## Agregar a GitBook

Una vez que tu documentación de API esté desplegada, agrégala a la documentación centralizada en GitBook.

### Adición manual (proceso actual)

1. Navega al espacio de GitBook
2. Ve a la **API Reference** sección
3. Haz clic en **Add API Reference**
4. Introduce los detalles de tu servicio:
   * **Name**: El nombre de tu servicio (p. ej., "Social Service")
   * **OpenAPI URL**: `https://decentraland.github.io/{repo-name}/openapi.yaml`
5. Guardar

### Funciones de integración de GitBook

GitBook hará automáticamente:

* Parsear tu especificación OpenAPI
* Generar documentación interactiva de la API
* Crear navegación de endpoints basada en tags
* Proveer funcionalidad de "Try it"
* Mantener la documentación sincronizada cuando actualices la especificación

***

## Flujo de configuración completo

### Configuración inicial

{% @mermaid/diagram content="graph TD
A\[Create /docs/openapi.yaml] --> B\[Add GitHub Actions workflow]
B --> C\[Configure GitBook secrets]
C --> D\[Enable GitHub Pages]
D --> E\[Push to main branch]
E --> F\[Workflow runs automatically]
F --> G\[Docs deployed to GitHub Pages]
G --> H\[Add to GitBook manually]" %}

### Actualizaciones continuas

{% @mermaid/diagram content="graph LR
A\[Update openapi.yaml] --> B\[Create PR]
B --> C\[Workflow validates]
C --> D\[Merge to main]
D --> E\[Auto-deploy to GitHub Pages]
E --> F\[GitBook syncs automatically]" %}

***

## Buenas prácticas

### Calidad de la documentación

* **Sé descriptivo**: Escribe resúmenes y descripciones claras
* **Proporciona ejemplos**: Incluye ejemplos de request/response
* **Documenta errores**: Describe todas las posibles respuestas de error
* **Usa components**: Reutiliza esquemas vía `$ref` para evitar duplicación
* **Agrega descripciones**: Cada parámetro, propiedad y respuesta debe tener una descripción

### Ejemplo con buenas prácticas

```yaml
paths:
  /users/{address}/friends:
    get:
      tags:
        - Friends
      summary: /users/{address}/friends
      operationId: socialService_getUserFriends
      description: |
        Recupera una lista paginada de amigos para el usuario especificado.
        Devuelve direcciones de amigos y metadatos incluyendo cuándo se estableció la amistad.
      parameters:
        - name: address
          in: path
          required: true
          description: Dirección de Ethereum del usuario (con prefijo 0x)
          schema:
            type: string
            pattern: '^0x[a-fA-F0-9]{40}$'
          example: '0x1234567890abcdef1234567890abcdef12345678'
        - name: limit
          in: query
          description: Número máximo de amigos a devolver (1-100)
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 50
        - name: offset
          in: query
          description: Número de amigos a omitir para paginación
          schema:
            type: integer
            minimum: 0
            default: 0
      responses:
        '200':
          description: Lista de amigos recuperada con éxito
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FriendsResponse'
              example:
                friends:
                  - address: '0xabcdef...'
                    createdAt: '2024-01-15T10:30:00Z'
                total: 42
                offset: 0
                limit: 50
        '400':
          description: Formato de dirección inválido
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: 'Formato de dirección inválido'
                code: 'INVALID_ADDRESS'
        '404':
          description: Usuario no encontrado
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
```

### Reutilización de esquemas

```yaml
components:
  schemas:
    Error:
      type: object
      required:
        - error
        - code
      properties:
        error:
          type: string
          description: Mensaje de error legible por humanos
        code:
          type: string
          description: Código de error legible por máquina
        details:
          type: object
          description: Contexto adicional del error
          
    PaginatedResponse:
      type: object
      required:
        - offset
        - limit
        - total
      properties:
        offset:
          type: integer
          description: Número de elementos omitidos
        limit:
          type: integer
          description: Máximo de elementos por página
        total:
          type: integer
          description: Número total de elementos disponibles
```

### Esquemas de seguridad

```yaml
components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: Token JWT obtenido desde el endpoint de autenticación

security:
  - BearerAuth: []
```

***

## Validaciones y controles de calidad

### Validación pre-commit

Agrega un hook pre-commit o una comprobación en CI:

```yaml
# .github/workflows/validate-api-spec.yml
name: Validate API Spec

on: [pull_request]

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '20'
      - run: npm install -g @redocly/cli
      - run: redocly lint docs/openapi.yaml
```

### Reglas comunes de validación

* Todas las paths tienen operation IDs
* Todas las operaciones tienen tags
* Todos los parámetros tienen descripciones
* Todas las respuestas están documentadas
* Se proporcionan ejemplos
* Los esquemas están referenciados correctamente

***

## Solución de problemas

### El workflow falla

**Problema**: El workflow de GitHub Actions falla

**Soluciones**:

* Revisa los logs del workflow por errores de validación
* Ejecuta `redocly lint docs/openapi.yaml` localmente
* Verifica las rutas de archivos en la configuración del workflow
* Asegúrate de que los secretos estén configurados correctamente

### GitHub Pages no funciona

**Problema**: Los docs no aparecen en la URL de GitHub Pages

**Soluciones**:

* Verifica que GitHub Pages esté habilitado en la configuración del repositorio
* Comprueba que el workflow se haya completado exitosamente
* Espera unos minutos para que GitHub Pages se actualice
* Verifica que el `github-pages` environment exista

### GitBook no se sincroniza

**Problema**: GitBook no muestra la documentación de API actualizada

**Soluciones**:

* Verifica que los secretos de GitBook sean correctos
* Comprueba que la URL OpenAPI sea accesible
* Forzar una actualización manual en GitBook
* Verifica que la especificación OpenAPI sea válida

***

## Migración desde documentación existente

Si tienes documentación de API existente:

1. **Exportar a OpenAPI**: Convertir la documentación existente al formato OpenAPI 3.1
2. **Validar**: Usar `redocly lint` para asegurar el cumplimiento
3. **Agregar workflow**: Configurar la automatización con GitHub Actions
4. **Probar**: Verificar que la documentación se compile y despliegue correctamente
5. **Actualizar enlaces**: Apuntar los enlaces de la documentación antigua a la nueva URL de GitHub Pages
6. **Archivar la documentación antigua**: Mantener la documentación antigua como referencia durante la transición

***

## Próximos pasos

* Revisar el [Well-Known Components](https://github.com/decentraland/docs/blob/main/contributor/contributor-guides/well-known-components/README.md) estándares para la implementación de la API
* Ver [Testing Standards](https://docs.decentraland.org/contributor/contributor-es/guias-para-colaboradores/testing-standards) para las pautas de pruebas de la API
* Consulta ejemplos de API existentes en el [API Reference](https://docs.decentraland.org) sección

## Related Standards

* [Gestión de dependencias](https://docs.decentraland.org/contributor/contributor-es/guias-para-colaboradores/dependency-management) - Gestión de dependencias npm y peerDependencies
* [Well-Known Components](https://github.com/decentraland/docs/blob/main/contributor/contributor-guides/well-known-components/README.md) - Arquitectura WKC para servicios
* [Testing Standards](https://docs.decentraland.org/contributor/contributor-es/guias-para-colaboradores/testing-standards) - Patrones de pruebas para servicios

## Recursos

* **OpenAPI Specification**: [spec.openapis.org](https://spec.openapis.org/oas/latest.html)
* **Redocly CLI**: [redocly.com/docs/cli](https://redocly.com/docs/cli/)
* **Integración de API de GitBook**: [docs.gitbook.com](https://docs.gitbook.com)
* **Repositorio de Platform Actions**: [github.com/decentraland/platform-actions](https://github.com/decentraland/platform-actions)
