在每个功能之前自动运行代码

时间:2018-06-15 20:54:09

标签: go

我想在许多函数的开头运行一些代码(授权检查),例如:

args: {
  name: {
    type: new GraphQLNonNull(GraphQLString),
  },
  school: {
    type: new GraphQLNonNull(GraphQLString),
  },
},

是否有一种优雅的方法可以避免在每个函数的开头执行相同的授权检查?

1 个答案:

答案 0 :(得分:4)

使用简单的包装器

由于所有方法(至少我都这么认为)具有相同的签名,因此您可以将所有冗余代码放在包装函数中,该函数将您需要的函数作为附加参数运行。包装器将首先检查错误,然后运行该功能。因此,您的方法只需要在内部包含相关代码,而无需先检查错误。

这是一个例子,我打电话给包装器wrap只是为了说清楚:

func (s *apiService) get(request Request) (Result, error) {
    //method logic
}

func (s *apiService) put(request Request) (Result, error) {
    //method logic
}

func wrap(f func (Request) (Result, error), request Request) (Result, error) {
    err := authorizationCheck(request)
    if err != nil {
        return nil, err
    }

    return f(request)
}

然后,在您的代码中稍后:

res, err := wrap(s.get, someRequest)

使用装饰器

与上面的内容非常类似,但更清晰:不是创建包装器,而是可以实现一个装饰器,返回一个函数,它包装你的方法并在调用它们之前进行错误检查。只有当所有方法都具有相同的签名时才能再次这样做,但它比使用包装器更强大,恕我直言更清晰。

这是一个例子,装饰者是decorate(依赖于我的原创性):

func (s *apiService) get(request Request) (Result, error) {
    //method logic
}

func (s *apiService) put(request Request) (Result, error) {
    //method logic
}

func decorate(f func(Request) (Result, error)) func(Request) (Result, error) {
    return func(r Request) (Result, error) {
        err := authorizationCheck(r)
        if err != nil {
            return nil, err
        }

        return f(r)
    }
}

然后,在您的代码中稍后:

res, err := decorate(s.get)(someRequest)

方法或普通函数?

无论您喜欢简单的包装器还是装饰器,如果需要,您也可以将它们设为apiService对象的方法(只需在其名称前添加(s *apiService)),确实没有太大区别,但如果您希望您的结构在任何地方使用包装器/装饰器而不是仅在该特定文件中,那么这将是首选选项。

相关电话会变为:

res, err := s.wrap(s.get, someRequest)

res, err := s.decorate(s.get)(someRequest)