GoでClean ArchitectureでのAPIを実装したときにハマったInterfaceの呼び出し方

# はじめに
今回はGoとClean Architecutureの復習を兼ねて、ゼロからAPIを実装したときに詰まった部分を備忘のためにここに記載します。Clean Architectureならびに利用したフレームワークのbeego自体については、あまりふれないので参考文献をご覧ください。

# 詰まった部分
Interface層であるControllerで、構造体を作成する際にどうやってInterface(継承)をわたせばいいのかわかりませんでした。
具体的には、関数`NewStatusController`に渡す引数`appConfigInterface`の構造体と具体的な値です。
渡すべき引数は、作成したInterface(継承)だと思っていたのですが、Interface(継承)を渡すということに、直感的に「?」が生まれました。

```Go:status.go
package controllers

import (
	"yamamon/flathand-bookmark/interfaces/inside"
	"yamamon/flathand-bookmark/usecase"
)

var statusController *StatusController

type StatusController struct {
	BaseController
	Interactor usecase.ConfigInteractor
}

func NewStatusController(appConfigInterface inside.AppConfig) *StatusController {
	return &StatusController{
		Interactor:     usecase.ConfigInteractor{
			ConfigRepository: &inside.ConfigRepository{
				AppConfig: appConfigInterface,
			},
		},
	}
}

// @router /_me [get]
func (controller *StatusController) Get() {
	appConfig := controller.Interactor.ShowAppConfig()
	controller.ServeResponseJSON(appConfig)
}
```

# appConfigInterfaceの構造体と値
`appConfigInterface`の構造体については、やはりInterface(継承)でしたが、具体的な値については`Interface(継承)を実装した構造体自身の値(ポインタ)`でした。
具体的には、関数`NewAppConfig`で定義されているものです。



```Go:config.go(継承)
package inside

import "yamamon/flathand-bookmark/domain"

type AppConfig interface {
	GetAppConfig() domain.AppConfig
}


```

```Go:config.go(実装)
package inside

import (
	"os"
	"yamamon/flathand-bookmark/domain"
)

var (
	environment  string
)

const (
	LocalEnvironment = "local"
)

type AppConfig struct {
	Environment string
	ServiceName string
}

func NewAppConfig() *AppConfig {
	return &AppConfig{
		Environment: newEnvironment(),
		ServiceName: newServiceName(),
	}
}

func (a *AppConfig) GetAppConfig() domain.AppConfig {
	config := domain.AppConfig{
		Environment: a.Environment,
		ServiceName: a.ServiceName,
	}
	return config
}

func newEnvironment() string {
	environment = os.Getenv("ENVIRONMENT")
	if environment == "" {
		return LocalEnvironment
	}
	return environment
}

func newServiceName() string {
	return "flathand-bookmark"
}
```

# 付録
上記では、部分的なコードしか記載しなかったので、以下にディレクトリ構成とあわせてコードを記載しておきます。誰かの助けになれば幸いです。

## ディレクトリ構成
```
├── domain
│   └── status.go
├── infrastructure
│   └── inside
│     　└── config.go
├── interfaces
│   ├── controllers
│   │   ├── base.go
│   │   └── status.go
│   └── inside
│       ├── config.go
│       └── config_repository.go
├── main.go
├── routers
│   ├── commentsRouter_interfaces_controllers.go
│   └── router.go
└── usecase
    ├── config_interactor.go
    └── config_repository.go
```

## コード
**Entities層**

```Go:domain/status.go
package domain

type AppConfig struct {
	Environment string `json:"environment"`
	ServiceName string `json:"serviceName" required:"true"`
}
```
**Frameworks & Drivers層**

```Go:infrastructure/inside/config.go
package inside

import (
	"os"
	"yamamon/flathand-bookmark/domain"
)

var (
	environment  string
)

const (
	LocalEnvironment = "local"
)

type AppConfig struct {
	Environment string
	ServiceName string
}

func NewAppConfig() *AppConfig {
	return &AppConfig{
		Environment: newEnvironment(),
		ServiceName: newServiceName(),
	}
}

func (a *AppConfig) GetAppConfig() domain.AppConfig {
	config := domain.AppConfig{
		Environment: a.Environment,
		ServiceName: a.ServiceName,
	}
	return config
}

func newEnvironment() string {
	environment = os.Getenv("ENVIRONMENT")
	if environment == "" {
		return LocalEnvironment
	}
	return environment
}

func newServiceName() string {
	return "flathand-bookmark"
}

```
routersに関しては、本来の役割からはframework&Device層ですが、infrastructureディレクトリとは分けています。

```Go:routers/router.go

import (
	"github.com/astaxie/beego"
	"yamamon/flathand-bookmark/infrastructure/inside"
	"yamamon/flathand-bookmark/interfaces/controllers"
)

func init() {
	ns := beego.NewNamespace("/v1",
		beego.NSNamespace("/statuses",
			beego.NSInclude(
				controllers.NewStatusController(inside.NewAppConfig()),
			),
		),
	)
	beego.AddNamespace(ns)
}
```

**interface層**

```Go:interfaces/controllers/base.go
package controllers

import (
	"fmt"
	"github.com/astaxie/beego"
)

type BaseController struct {
	beego.Controller
}

type Error struct {
	ErrorMessage string
}

func (controller *BaseController) ServeResponseJSON(response interface{}) {
	controller.Data["json"] = response
	beego.Info(fmt.Sprintf("response: %+v", response))
	controller.ServeJSON()
}

func (controller *BaseController) ServeErrorJSON(message string, statusCode int) {
	response := Error{ErrorMessage: message}
	controller.Data["json"] = response
	controller.Ctx.Output.SetStatus(statusCode)
	beego.Info(fmt.Sprintf("error: %+v, status: %+v", response, statusCode))
	controller.ServeJSON()
}
```
```Go:intefaces/controllers/status.go
package controllers

import (
	"yamamon/flathand-bookmark/interfaces/inside"
	"yamamon/flathand-bookmark/usecase"
)

var statusController *StatusController

type StatusController struct {
	BaseController
	Interactor usecase.ConfigInteractor
}

func NewStatusController(appConfigInterface inside.AppConfig) *StatusController {
	return &StatusController{
		Interactor:     usecase.ConfigInteractor{
			ConfigRepository: &inside.ConfigRepository{
				AppConfig: appConfigInterface,
			},
		},
	}
}

// @router /_me [get]
func (controller *StatusController) Get() {
	appConfig := controller.Interactor.ShowAppConfig()
	controller.ServeResponseJSON(appConfig)
}
```
```Go:interfaces/inside/config.go
package inside

import "yamamon/flathand-bookmark/domain"

type AppConfig interface {
	GetAppConfig() domain.AppConfig
}
```
```Go:interfaces/inside/config_repository.go
package inside

import (
	"yamamon/flathand-bookmark/domain"
)

type ConfigRepository struct {
	AppConfig
}

func (repository *ConfigRepository) ShowAppConfig() domain.AppConfig {
	return repository.AppConfig.GetAppConfig()
}
```
**usecase層**

```Go:usecase/config_interactor.go
package usecase

import (
	"yamamon/flathand-bookmark/domain"
)

type ConfigInteractor struct {
	ConfigRepository ConfigRepository
}

func(interactor *ConfigInteractor) ShowAppConfig() domain.AppConfig {
	return interactor.ConfigRepository.ShowAppConfig()
}
```
```Go:config_repository.go
package usecase

import "yamamon/flathand-bookmark/domain"

type ConfigRepository interface {
	ShowAppConfig() domain.AppConfig
}
```
**その他**

```Go:main.go
package main

import (
	_ "yamamon/flathand-bookmark/routers"
	"github.com/astaxie/beego"
)

func main() {
	if beego.BConfig.RunMode == "dev" {
		beego.BConfig.WebConfig.DirectoryIndex = true
		beego.BConfig.WebConfig.StaticDir["/swagger"] = "swagger"
	}
	beego.Run()
}
```


# 参考文献
- [Clean ArchitectureでAPI Serverを構築してみる](https://qiita.com/hirotakan/items/698c1f5773a3cca6193e)
- [初心者に送りたいinterfaceの使い方[Golang]](https://medium.com/since-i-want-to-start-blog-that-looks-like-men-do/%E5%88%9D%E5%BF%83%E8%80%85%E3%81%AB%E9%80%81%E3%82%8A%E3%81%9F%E3%81%84interface%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9-golang-48eba361c3b4)

# さいごに
これが僕の初めての投稿になります。記載内容や文章などにも多々不備があると思います。コメントいただけますと、本記事はもちろんのこと、後学のためにもなりますので、よろしくお願い致します。