ぼやきからのアイディア？DeclarativeなGolang API Framework

CodeGenに疲れた。
コードからドキュメント起こしてほしい。

Swaggoは確かにあるんだけど、ドキュメントコメントで書いちゃったら、コメントと実装の乖離が起きるじゃんって話で、Swagger別に書くのとあんま差分ない。
強いて言えば、SwaggerのYAMLと実装ほど距離が空いてない、てくらい？

## こんなふうに書きたい

```go
package api

import (
	"kyoh86/declarest/decl"
	"kyoh86/declarest/declhelper"
)

func NewTaskService() decl.Service {
	s := decl.Service{
		BaseOptions: []decl.Option{
			decl.OptionProducer(declhelper.JSONFormatter),
			decl.OptionAcceptor(declhelper.JSONFormatter),
			decl.OptionDefaultError(declhelper.JSONError),
		},
	}
	s.Get("/projects/{projectId}/tasks", ListTasks)
	s.Post("/projects/{projectId}/tasks", RegisterTask,
		decl.OptionAcceptor(declhelper.MultipartFormatter),
	)
	return s
}

// ListTasks : Fetch tasks from a project.
// @Tag tasks
// @Error 400 model.ValidationError
func ListTasks(param struct {
	// A project ID which tasks belong to.
	ProjectID string `name:"projectId" from:"path" required:"true"`
	// Target statuses.
	Status []TaskStatus `from:"query" required:"true" format:"csv" default:"undone,doing"`
}) ([]model.Task, error) {
	// implement
}

// TaskStatus describes status of a task.
type TaskStatus string

const (
	TaskStatusUndone = TaskStatus("undone")
	TaskStatusDoing  = TaskStatus("doing")
	TaskStatusDone   = TaskStatus("done")
)

// RegisterTask : Register a new task.
// @Tag tasks
// @Error 400 model.ValidationError
func RegisterTask(param struct {
	// A project ID which tasks belong to.
	ProjectID string `from:"path" required:"true"`
	// A task to register.
	Task Task `from:"body" required:"true"`
	// Icon to attach to the task.
	Icon declhelper.Binary `from:"body"`
}) error {
	// implement
}
```

## こんなん生成してほしい

```yaml
openapi: 3.0.0

paths:
  # paths オブジェクト
  /projects/{projectId}/tasks:
    get: # GET
      operationId: ListTasks
      summary: Fetch tasks from a project.
      tags:
        - tasks
      description: Fetch tasks from a project.
      parameters:
        - name: projectId
          in: path
          description: A project ID which tasks belong to.
          required: true
          schema:
            type: string
        - name: status
          in: query
          description: Target statuses.
          schema:
            type: array
            items:
              $ref: '#/components/schemas/TaskStatus'

      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Task'
        '400':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'
        default:
          $ref: '#/components/responses/JSONError'

    post: # POST
      operationId: RegisterTask
      summary: Register a new task
      tags:
        - tasks
      description: Register a new task
      parameters:
        - name: projectId
          in: path
          description: A project ID which tasks belong to.
          required: true
          schema:
            type: string
      requestBody:
        description: user to create
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                task:
                  $ref: '#/components/schemas/Task'
                icon:
                  type: string
                  format: binary
            encoding:
              task: application/json
              icon: image/png

      responses:
        '201':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Task'
        '400':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'
        default:
          $ref: '#/components/responses/JSONError'

components:
  schemas:
    # 割愛
  responses:
    # 割愛
```