草庐IT

go - 用Go编写的lambda API的设计

coder 2023-07-01 原文

我需要帮助设计用go编写的API。这就是文件结构:

database/
 database.go
middlewares/
 authentication.go
models/
 pageview
services/
 pageviews/
   create/
     main.go
   show/
     main.go
   serverless.yml

现在我只有页面浏览服务。
让我向您展示负责创建页面视图(services/pageview s/create/main.go)的处理程序中的内容:
package main

import (
    "context"

    "github.com/aws/aws-lambda-go/events"
    "github.com/aws/aws-lambda-go/lambda"
    "github.com/clickhound/api/models"
)

func Handler(ctx context.Context, request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
    var pageviews models.Pageview
    if err := pageviews.Create(request.Body); err != nil {
        return events.APIGatewayProxyResponse{}, err
    }

    return events.APIGatewayProxyResponse{
        StatusCode: 201,
    }, nil
}

func main() {
    lambda.Start(Handler)
}

如您所见,请求处理程序(或控制器)负责将资源的创建委托给模型,让我们看看pageview模型中的内容:
package models

import (
    "encoding/json"
)

type Pageview struct {
    ID       string
    Hostname string `gorm:"not null"`
}

func (p *Pageview) Create(data string) error {
    if err := json.Unmarshal([]byte(data), p); err != nil {
        return err
    }

    // TODO validate error here.
    db.Create(p)
    return nil
}

因此,模型负责:
取消标记请求正文
创建新资源
当我需要将数据返回到控制器时,这就开始变得混乱,假设我有一个Findpageview。这是请求处理程序(或控制器):
package main

import (
    "context"

    "github.com/aws/aws-lambda-go/events"
    "github.com/aws/aws-lambda-go/lambda"
    "github.com/clickhound/api/middlewares"
    "github.com/clickhound/api/models"
)

func Handler(ctx context.Context, request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
    var pageview models.Pageview
    data, err := pageview.Find(request.PathParameters["id"])
    if err != nil {
        return events.APIGatewayProxyResponse{}, err
    }

    return events.APIGatewayProxyResponse{
        StatusCode: 200,
        Body:       string(data),
    }, nil
}

func main() {
    lambda.Start(Handler))
}

模型的功能是:
func (p *Pageview) Find(id string) ([]byte, error) {
    p.ID = id

    // TODO validate error here.
    db.Find(p)
    return json.Marshal(p)
}

在这种情况下,模型负责:
查找资源
将资源封送到JSON
正如您所看到的,模型既负责持久性逻辑,也返回控制器完成其工作所需的响应——我感觉有些东西放错了地方,但为什么要这样做?
我将介绍身份验证,并且模型上的一些操作(如find pageview)应该仅限于当前用户。为了实现这一点,我将使用一个将当前用户注入模型名称空间的Find中间件:
package middlewares

import (
    "context"

    "github.com/aws/aws-lambda-go/events"
    "github.com/clickhound/api/models"
)

func Authentication(next MiddlewareSignature) MiddlewareSignature {
    return func(ctx context.Context, request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
        claims := request.RequestContext.Authorizer["claims"]

        if models.InjectUser(claims).RecordNotFound() {
            return events.APIGatewayProxyResponse{StatusCode: 401}, nil
        }

        return next(ctx, request)
    }
}

在用户模型中:
package models

import (
    "time"

    "github.com/jinzhu/gorm"
    "github.com/mitchellh/mapstructure"
)


type User struct {
    ID        string `gorm:"not null"`
    Email     string `gorm:"not null;unique"`
    CreatedAt time.Time
    UpdatedAt time.Time
}

func InjectUser(claims interface{}) *gorm.DB {
    if err := mapstructure.Decode(claims, user); err != nil {
        panic(err)
    }
    return db.Find(&user)
}

var user User

现在,任何需要执行仅限于当前用户的操作的请求处理程序(控制器),我都可以更改:
func main() {
    lambda.Start(middlewares.Authentication(Handler))
}

到:
func main() {
    lambda.Start(
        middlewares.Authentication(Handler),
    )
}

一些问题:
您对在模型的名称空间中注入用户有什么看法?
您认为使用请求处理程序(控制器)只调用正确的函数如何?
您对负责持久性逻辑、验证数据库操作、对请求/响应数据进行编组/解编组的模型有什么看法?

最佳答案

最好使用一些模块将业务逻辑与传输细节隔离开来。它只是两个不同的抽象层次,如果我们不混合它们,代码就会变得更干净。尽管如此,它应该是实用的,我们可以保留HTTP代码,因为它们现在是通用语言,并且如果您的业务逻辑返回500和400来处理不同类型的错误,也没有什么错。
如果我编写这段代码,那么这种分离将是控制器的主要目标。
业务逻辑层(模型)应该与建模业务域的强类型对象一起工作,而不需要了解HTTP或AWS lambda实现的详细信息。
要处理的控制器:
路由
API版本控制
序列化/反序列化,包括URL参数、头、AWS lambda特定字段等
模型:
接收并返回强类型对象和错误
验证输入(根据框架,这可以部分移动到控制器)
IO,包括为身份验证和业务事务按ID加载用户

关于go - 用Go编写的lambda API的设计,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53582834/

有关go - 用Go编写的lambda API的设计的更多相关文章

  1. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  2. ruby - 在 Ruby 中编写命令行实用程序 - 2

    我想用ruby​​编写一个小的命令行实用程序并将其作为gem分发。我知道安装后,Guard、Sass和Thor等某些gem可以从命令行自行运行。为了让gem像二进制文件一样可用,我需要在我的gemspec中指定什么。 最佳答案 Gem::Specification.newdo|s|...s.executable='name_of_executable'...endhttp://docs.rubygems.org/read/chapter/20 关于ruby-在Ruby中编写命令行实用程序

  3. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

    我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

  4. ruby - 用 Ruby 编写一个简单的网络服务器 - 2

    我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b

  5. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  6. 计算机毕业设计ssm+vue基本微信小程序的小学生兴趣延时班预约小程序 - 2

    项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU

  7. ruby-on-rails - 设计注册确认 - 2

    我在我的项目中有一个用户和一个管理员角色。我使用Devise创建了身份验证。在我的管理员角色中,我没有任何确认。在我的用户模型中,我有以下内容:devise:database_authenticatable,:confirmable,:recoverable,:rememberable,:trackable,:validatable,:timeoutable,:registerable#Setupaccessible(orprotected)attributesforyourmodelattr_accessible:email,:username,:prename,:surname,:

  8. ruby-on-rails - 如何为空白字段编写 rspec? [Rails3.1] - 2

    我使用rails3.1+rspec和factorygirl。我对必填字段(validates_presence_of)的验证工作正常。我如何让测试将该事实用作“成功”而不是“失败”规范是:describe"Addanindustrywithnoname"docontext"Unabletocreatearecordwhenthenameisblank"dosubjectdoind=Factory.create(:industry_name_blank)endit{shouldbe_invalid}endend但是我失败了:Failures:1)Addanindustrywithnona

  9. ruby-on-rails - 设计通过 reset_password_token 获取用户 - 2

    我正在尝试创建密码规则来设计可恢复的密码更改。我通过passwords_controller.rb做了一个父类(superclass),但我需要在应用规则之前检查用户角色,但我所拥有的只是reset_password_token。 最佳答案 假设您的模型是用户:User.with_reset_password_token(your_token_here)Source 关于ruby-on-rails-设计通过reset_password_token获取用户,我们在StackOverflow

  10. ruby-on-rails - 尝试为 Rails 中的用户名验证编写 REGEX - 2

    我正在尝试用Ruby(Rails)编写一个正则表达式,以便用户名的字符仅包含数字和字母(也没有空格)。我有这个正则表达式,/^[a-zA-Z0-9]+$/,但它似乎没有用,我在Rails中收到一个错误,说“The如果正则表达式使用多行anchor(^或$),这可能会带来安全风险。您是要使用\A和\z,还是忘记添加:multiline=>true选项?"我的user.rb模型中此实现的完整代码是:classUser我做错了什么以及如何修复此正则表达式,使其仅对数字和字母有效而不对空格有效?谢谢。 最佳答案 简短回答:使用/\A[a-z

随机推荐