【问题标题】:Inject variables into JSON config file将变量注入 JSON 配置文件
【发布时间】:2018-07-04 19:25:57
【问题描述】:

我们有一个 AWS Lambda 函数,它可以为我们的工程师动态构建测试环境,以便通过 GitHub 拉取请求测试他们的代码。

这个 Lambda 函数是使用 GitHub webhooks 调用的,由此 Github 会发布为该特定产品配置测试环境所需的所有信息。

目前,AWS Lambda 函数被硬编码以解析 POST 数据并构建测试环境。然而,随着被测试产品范围的增加和测试环境的范围变得更加多样化,我们希望摆脱硬编码的方法;也是为了便于管理。

我想要做的是加载一个配置文件,最好是在 JSON 中,并将 GitHub POST 数据中的一些数据应用到配置文件中,本质上是将数据注入到 JSON 配置中。

我不知道如何处理这个问题。我在这里看到了一个问题,想要做类似的事情,但是在 Java 中: Inject dynamically generated data into JSON

最初我们的 Lambda 函数是用 Node.js 编写的,但我们已经开始转向 Go - 主要是因为这是一个有趣的新挑战。如果在 Node.js 中有解决方案,我会接受,但如果在 Go 中有可用的解决方案,那将是可取的。

编辑:

配置文件和 GitHub POST 数据有两种不同的结构。

GitHub POST 数据 (大量精简):

{
 "action": "opened",
  "number": 89,
  "pull_request": {
    "url": "https://api.github.com/repos/Owner/ExampleRepository/pulls/89",
    "head": {
      "repo": {
        "id": 123454678,
         "name": "ExampleRepository"
        }
      }
  }
}

示例配置文件 (也精简了):

{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description": [GitHub Post data].pull_request.url,
  "Resources": {
      "ElasticBeanstalk": {
         "Type": "AWS::ElasticBeanstalk::Environment",
         "Properties": {
             "ApplicationName": [GitHub Post data].pull_request.head.repo + [GitHub Post data].number,
             "Description": [GitHub Post data].pull_request.url
          }
     }
  }
}

配置文件和 GitHub POST 数据都比这复杂得多。此外,配置文件会多次引用 POST 数据的各个部分,有时需要连接多个值。

【问题讨论】:

  • 您是只想将 json 视为文本并对其进行模板化处理,还是要操作更复杂的数据结构?无论哪种方式,解决方案似乎都很简单,您尝试过什么?
  • 是的,我更愿意将 JSON 视为文本。除了能够在 JSON 配置文件中添加某种“链接”来引用来自 GitHub 的 JSON POST 数据之外,我不想做任何复杂的事情。在 Node.js 中,我尝试遍历 JSON 配置文件并执行查找和替换方法,或者将 JSON 配置文件作为模块动态加载并从 GitHub 传递 POST 数据;两者都很麻烦,而后者过于复杂。没有真正尝试过 Go 中的任何东西,因为我对它完全陌生,也不知道该语言能做什么。

标签: json node.js go config inject


【解决方案1】:

尝试对 JSON 文本进行文本操作很容易出错(考虑转义和 unicode 序列,例如这是有效的 JSON:{"a":"\"b"})。将 JSON 配置解组为 Go 值,对其执行修改,然后编组为 JSON,会更容易、更安全。

如果配置结构已知,则创建匹配的 Go 结构以对其进行精确建模。

如果配置结构未知或者您不想对其进行麻烦,您可以将其解组为interface{} 类型的值,然后对其进行修改。这将更加冗长,因为您必须为每个属性和索引执行类型断言。

为了减轻后者的痛苦,您可以使用 3rd 方库,例如 github.com/icza/dyno(披露:我是作者)。

要从 POST 请求中“合并”现有配置和数据,请查看以下答案:"Merge" fields two structs of same type

【讨论】:

  • JSON 结构是已知的,所以这不是什么大问题。如何使用结构将 GitHub POST 数据中的数据应用到 JSON 模板 - 假设 JSON 配置不是基于文本的,如果这样更容易的话。
  • @JSmith 看看这个答案:"Merge" fields two structs of same type
  • 这是假设 POST 数据和配置的结构是相同的,但事实并非如此。我已经尝试添加我正在处理的数据的示例,但我在 StackOverflow 上的格式方面遇到了困难。
  • @JSmith 只需在代码和普通文本之间添加一个空行以进行正确格式化。
【解决方案2】:

为什么不使用标准包? os 包具有 ExpandEnv 以使用环境变量值扩展给定字符串中的 ${VARNAME} 和 $VARNAME 样式子字符串。只需将值作为环境值传递,读取文件并执行以下操作:

replacedVars := os.ExpandEnv(fContents)

查看os.ExpandEnv docs

基本上,我会写如下内容:

package main

import (
    "fmt"
    "io/ioutil"
    "os"
)

func main() {
    fname = "foobar.json" // wherever this comes from
    buf, err := ioutil.ReadFile(fname)
    if err != nil {
        fmt.Printf("Failed to read file %s - %+v", fname, err)
        return
    }
    conf := os.ExpandEnv(string(buf))
    // do whatever you need to do with conf string...
}

【讨论】:

    【解决方案3】:

    感谢所有回复,每一个回复都帮助我进一步增加了我对 Go 的了解。

    对我来说解决这个问题的最佳方法是使用 text/template 库并将 JSON 配置创建为文本模板,这样我就可以轻松地应用来自 GitHub 发布请求的变量。

    https://golang.org/pkg/text/template/

    【讨论】:

    • 请查看本网站的帮助部分。您被要求不要离开谢谢 cmets 作为您自己问题的答案。表示赞赏的方式是投赞成票/反对票,或许还可以发表评论。
    猜你喜欢
    • 1970-01-01
    • 2016-01-07
    • 2013-12-12
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    • 1970-01-01
    • 2012-09-07
    • 1970-01-01
    相关资源
    最近更新 更多