# Documenting the API

## Principles

- The documentation is generated by [swaggo/swag](https://github.com/swaggo/swag) from comments in the API code.

- Documentation is written using [Declarative Comments Format](https://github.com/swaggo/swag#declarative-comments-format).

- The documentation is generated in the `./api/v1` folder as `docs.go`.

- [echo-swagger](https://github.com/swaggo/echo-swagger) is used to integrate with Echo framework and serve the documentation with [Swagger-UI](https://swagger.io/tools/swagger-ui/) at `http://memos.host:5230/api/index.html`

## Updating the documentation

1. Update or add API-related comments in the code. Make sure to follow the [Declarative Comments Format](https://github.com/swaggo/swag#declarative-comments-format):

   ```go
   // signIn godoc
   //
   //  @Summary    Sign-in to memos.
   //  @Tags       auth
   //  @Accept     json
   //  @Produce    json
   //  @Param      body    body        SignIn      true    "Sign-in object"
   //  @Success    200     {object}    store.User  "User information"
   //  @Failure    400     {object}    nil         "Malformatted signin request"
   //  @Failure    401     {object}    nil         "Password login is deactivated | Incorrect login credentials, please try again"
   //  @Failure    403     {object}    nil         "User has been archived with username {username}"
   //  @Failure    500     {object}    nil         "Failed to find system setting | Failed to unmarshal system setting | Incorrect login credentials, please try again | Failed to generate tokens | Failed to create activity"
   //  @Router     /api/v1/auth/signin [POST]
   func (s *APIV1Service) signIn(c echo.Context) error {
   ...
   ```

   > Sample from [api/v1/auth.go](https://github.com/usememos/memos/tree/main/api/v1/auth.go)
   > You can check existing comments at [api/v1](https://github.com/usememos/memos/tree/main/api/v1)

2. Run one of the following provided scripts:

   - Linux: `./scripts/gen-api-v1-docs.sh` (remember to `chmod +x` the script first)
   - Windows: `./scripts/gen-api-v1-docs.ps1`

   > The scripts will install swag if needed (via go install), then run `swag fmt` and `swag init` commands.

3. That's it! The documentation is updated. You can check it at `http://memos.host:5230/api/index.html`

### Extra tips

- If you reference a custom Go struct from outside the API file, use a relative definition, like `store.IdentityProvider`. This works because `./` is passed to swag at `--dir` argument. If swag can't resolve the reference, it will fail.

- If the API grows or you need to reference some type from another location, remember to update ./scripts/gen-api-v1-docs.cfg file with the new paths.

- It's possible to list multiple errors for the same code using enum-like structs, that will show a proper, spec-conformant model with all entries at Swagger-UI. The drawback is that this approach requires a major refactoring and will add a lot of boilerplate code, as there are inconsistencies between API methods error responses.

  ```go
  type signInInternalServerError string

  const signInErrorFailedToFindSystemSetting signInInternalServerError = "Failed to find system setting"
  const signInErrorFailedToUnmarshalSystemSetting signInInternalServerError = "Failed to unmarshal system setting"
  const signInErrorIncorrectLoginCredentials signInInternalServerError = "Incorrect login credentials, please try again"
  const signInErrorFailedToGenerateTokens signInInternalServerError = "Failed to generate tokens"
  const signInErrorFailedToCreateActivity signInInternalServerError = "Failed to create activity"

  type signInUnauthorized string

  const signInErrorPasswordLoginDeactivated signInUnauthorized = "Password login is deactivated"
  const signInErrorIncorrectCredentials signInUnauthorized = "Incorrect login credentials, please try again"

  // signIn godoc
  //
  //  @Summary    Sign-in to memos.
  //  @Tags       auth
  //  @Accept     json
  //  @Produce    json
  //  @Param      body    body        SignIn      true    "Sign-in object"
  //  @Success    200     {object}    store.User  "User information"
  //  @Failure    400     {object}    nil         "Malformatted signin request"
  //  @Failure    401     {object}    signInUnauthorized
  //  @Failure    403     {object}    nil "User has been archived with username {username}"
  //  @Failure    500     {object}    signInInternalServerError
  //  @Router     /api/v1/auth/signin [POST]
  func (s *APIV1Service) signIn(c echo.Context) error {
      ...
  ```

### Step-by-step (no scripts)

#### Required tools

```bash
# Swag v1.8.12 or newer
# Also updates swag if needed
$ go install github.com/swaggo/swag/cmd/swag@latest
```

If `$HOME/go/bin` is not in your `PATH`, you can call `swag` directly at `$HOME/go/bin/swag`.

#### Generate the documentation

1. Run `swag fmt` to format the comments

   ```bash
   swag fmt --dir ./api/v1 && go fmt
   ```

2. Run `swag init` to generate the documentation

   ```bash
   cd <project-root>
   swag init --output ./api/v1 --generalInfo ./api/v1/v1.go --dir ./,./api/v1
   ```

> If the API gets a new version, you'll need to add the file system path to swag's `--dir` parameter.
