grails 3:有没有办法在这个API示例中提取重复的样板代码?

时间:2017-07-16 19:08:59

标签: api grails3

我们必须在grails 3.3 web应用程序中实现大量JSON API调用。

不幸的是,每个方法的构建都是错误处理,目前我们在每个方法中复制这个代码是一个维护问题(如果我们改进错误处理,我们必须更新70多个方法)。有更少的重复错误代码有更好的方法吗?有些模式可以将错误检查代码提取到一个地方吗?

仅供参考我们使用超级简单有效的对象编组器以我们需要的方式呈现json。不幸的是,render(){...}模式忽略了对象marshallers,因此我们需要在这种情况下使用JSONBuilder。

正确的登录将提供以下内容:

{"result":"0","user":{"username":"bob","userId":"123"},"accounts":[{"balance":"0.00","currencyIso":"USD","id":1}]}

错误看起来像这样:

{"result":"9999","message":"exception in xxx"}

我们有很长的结果代码列表(大约70个),因此客户端确切地知道错误是什么(我们不会使用HTTP状态代码,因为他们根本不会映射)

class LoginCommand implements grails.validation.Validateable {
    String username
    String password
    static constraints = {
        username    nullable:false, blank: false, size: 3..32
        password    nullable:false, blank: false, size: 3..32
    }

}

class UserApiController {
 def login(LoginCommand cmd) {
    try {
        if (cmd.hasErrors()) {
            log.error("invalid parameters")
            render(status: 400, contentType: 'application/json') {
                    result 10
                    message "errors in parameters"
            return
            }
        } else {
            User user = User.findByUsernameAndPassword(cmd.username, cmd.password)
            def userAccounts = Account.findAllByUser(user)

            if (user == null) {
                render(status: 404, contentType: 'application/json') {
                    result 100
                    message "could not find user with that username and pass"
                }
            } else {

                def builder = new JSONBuilder()
                def json = builder.build {
                    result= "0"
                    user= {
                      username=user.username
                      userId=user.id
                    }
                    accounts=playerAccounts
                }
                render(status: 200, contentType: 'application/json', text: json)                
            } // else all good
        } // else params ok

    } catch (Exception e) {
        log.error("Caught Exception in UserApiController.login()", e)
        render(status: 500, contentType: 'application/json') {
                result 9999
                message e.toString()
        }
    }
}

我们简要介绍了json的观点,但我们认为这对我们没有帮助,增加了复杂性,因为我们的项目不是使用rest-api构建的,所以我们无法访问它。

1 个答案:

答案 0 :(得分:0)

可能对您有所帮助的几点说明:

  • 如果您希望多个应用程序重用整个登录功能,请考虑创建Grails插件。插件是Grails特定的JAR项目,可以托管可重用的文件,如控制器和服务。

http://docs.grails.org/latest/guide/plugins.html

  • 您应该设置一个全局错误处理程序,而不是在整个控制器方法中执行泛型try...catch()。参见:

Exception handling in Grails controllers

  • 如果您需要JSON视图,则可以将其安装在现有应用程序上,即使该应用程序不是使用REST配置文件构建的。如果要自定义输出,JSON视图非常有用,但您还希望在Controller和View之间分离关注点。

http://views.grails.org/latest/#_installation

  • 对于这个特定用例,您可能还想查看Spring Security Grails插件。

https://plugins.grails.org/q/spring-security

  • 要清理控制器代码,请考虑将业务逻辑提取到服务方法。您可以为输出创建标准化命令对象,也可以使用自定义RuntimeException子类型(MyLoginFailureException)来指示失败的登录信息,并传回原因和结果代码。