Documentos

El siguiente artículo podría considerarse una segunda parte espiritual de Script en Bash y cURL para hacer comprensiva una API. En este caso, se trata de un ejemplo sencillo en Markdown de cómo documentar una API orientado a desarrolladores. Lo utilizo como base para documentar en mis proyectos donde no uso, no puedo, no debo, usar OpenAPI o Swagger.

Trabajamos con una API REST que sirve tres recursos: Client, User y Role. Algunos endpoints tienen parámetros y otros no. Los métodos permitidos son GET, POST, PUT y DELETE. Los campos de las respuestas son ficticios y se han simplificado para su comprensión. No todas las rutas siguen una estructura CRUD (o si sientes más empatía por el frontend, BREAD).

# API

## Client

### `/api/v1/clients/`

GET - List all clients

#### Parameters

Nothing

#### Request body

```json
{}
```

#### Response

```json
[
    {
        "id": 1,
        "alias": "Client 1",
        "name": "Client 1 description",
        "logo": {
            "dark": "http://localhost:8000/media/clients/1/logo_dark.png",
            "light": "http://localhost:8000/media/clients/1/logo_light.png"
        },
    },
    {
        "id": 2,
        "alias": "Client 2",
        "name": "Client 2 description",
        "logo": {
            "dark": "http://localhost:8000/media/clients/2/logo_dark.png",
            "light": "http://localhost:8000/media/clients/2/logo_light.png"
        },
    }
]
```

### `/api/v1/clients/{id}/`

GET - Retrieve a client

#### Parameters

- `id` - The client id

#### Request body

```json
{}
```

#### Response

```json
{
    "id": 1,
    "alias": "Client 1",
    "name": "Client 1 description",
    "logo": {
        "dark": "http://localhost:8000/media/clients/1/logo_dark.png",
        "light": "http://localhost:8000/media/clients/1/logo_light.png"
    },
}
```

## Users

### `/api/v1/users/`

GET - List users

#### Parameters

- `query` - The search query by `email`, `first name` or `last name`. Default is `""`.
- `page` - The page number. Default is `1`.
- `perPage` - The number of items per page. Default is `10`.
- `orderBy` - The field to order by. Default is `email`. Possible values are `email`, `first name`, `last name`, `is active` and `created at`.
- `order` - The order. Default is `asc`. Possible values are `asc` and `desc`.

#### Request body

```json
{}
```

#### Response

```json
{
    "page": 1,
    "total": 12,
    "perPage": 10,
    "lastPage": 2,
    "results": [
        {
            "id": 1,
            "email": "foo@boo.com",
            "firstName": "Foo",
            "lastName": "Boo",
            "isActive": true,
            "roleId": 1,
            "createdAt": "2024-11-29T14:41:35.342Z", // ISO 8601
        },
    ]
}
```

### `/api/v1/users/{id}/`

GET - Retrieve a user

#### Parameters

- `id` - The user id

#### Request body

```json
{}
```

#### Response

```json
{
    "id": 1,
    "email": "foo@boo.com",
    "firstName": "Foo",
    "lastName": "Boo",
    "isActive": true,
    "createdAt": "2024-11-29T14:41:35.342Z", // ISO 8601
}
```

### `/api/v1/users/{id}/`

POST - Create a user

#### Parameters

Nothing

#### Request body

```json
{
    "email": "foo@boo.com",
    "password": "password",
    "firstName": "Foo",
    "lastName": "Boo",
    "isActive": true,
    "roleId": 1
}
```

#### Response

```json
{
    "id": 1,
    "email": "foo@boo.com",
    "firstName": "Foo",
    "lastName": "Boo",
    "isActive": true,
    "roleId": 1,
    "createdAt": "2024-11-29T14:41:35.342Z", // ISO 8601
}
```

### `/api/v1/users/{id}/`

PUT - Update a user

#### Parameters

- `id` - The user id

#### Request body

```json
{
    "email": "foo@boo.com",
    "firstName": "Foo",
    "lastName": "Boo",
    "isActive": true,
    "roleId": 1
}
```

#### Response

```json
{
    "id": 1,
    "email": "foo@boo.com",
    "firstName": "Foo",
    "lastName": "Boo",
    "isActive": true,
    "roleId": 1,
    "createdAt": "2024-11-29T14:41:35.342Z", // ISO 8601
}
```

### `/api/v1/users/{id}/`

DELETE - Delete a user

#### Parameters

- `id` - The user id

#### Request body

```json
{}
```

#### Response

```json
{}
```

### `/api/v1/users/{id}/password/`

PUT - Update a user password

#### Parameters

- `id` - The user id

#### Request body

```json
{
    "password": "password"
}
```

#### Response

```json
{
    "id": 1,
    "email": "foo@boo.com",
    "firstName": "Foo",
    "lastName": "Boo",
    "isActive": true,
    "roleId": 1,
    "createdAt": "2024-11-29T14:41:35.342Z", // ISO 8601
}
```

### `/api/v1/users/{id}/enabled/`

PUT - Set user enabled

#### Parameters

- `id` - The user id

#### Request body

```json
{
    "isActive": true
}
```

#### Response

```json
{
    "id": 1,
    "email": "foo@boo.com",
    "firstName": "Foo",
    "lastName": "Boo",
    "isActive": true,
    "roleId": 1,
    "createdAt": "2024-11-29T14:41:35.342Z", // ISO 8601
}
```

## Roles

### `/api/v1/roles/`

GET - List all roles

#### Parameters

Nothing

#### Request body

```json
{}
```

#### Response

```json
[
    {
        "id": 1,
        "name": "admin",
        "permissions": [
            {
                "id": 1,
                "name": "manage-users"
            },
            {
                "id": 2,
                "name": "statistics"
            },
            {
                "id": 3,
                "name": "view"
            }
        ]
    },
    {
        "id": 2,
        "name": "guest",
        "permissions": [
            {
                "id": 3,
                "name": "view"
            }
        ]
    }
]
```

Me gustaría destacar algunos puntos:

  • Se ha utilizado Markdown para la documentación, pero se podría utilizar cualquier otro formato como Org, Asciidoc, etc.
  • Los cuerpos son en JSON, lo cual es muy común en APIs REST. Sin embargo se podrían usar formularios, binarios, etc.
  • Las fechas cumplen con el estándar ISO 8601. Las 5 reglas para las fechas y las APIs son:
    1. Usa ISO-8601 para las fechas.
    2. Acepta cualquier zona horaria.
    3. Guarda las fechas en UTC.
    4. Devuelve las fechas en UTC.
    5. No uses tiempos si no son necesarios.
  • No se han incluido ejemplos de errores, códigos de estado, etc. ¿Quieres incluirlos? ¡Adelante! Sin embargo te recomiendo realizar antes las pruebas unitarias.
  • No hay documentación de autenticación o autorización. Sería apropiado añadir una sección para ello, como las rutas de login, logout, refresco de token, tiempos de expiración, etc.
  • También sería buena idea incluir una sección con headers necesarios, como Content-Type, Accept o Authorization.

Aún queda más trabajo por delante. Sin embargo, hay que empezar con buen pie y con la máxima calidad posible. ¡Ánimo!

Fuente The 5 rules of API dates and times