【问题标题】:Is there real documentation for @google-cloud/iot API?@google-cloud/iot API 有真实的文档吗?
【发布时间】:2021-12-02 11:43:48
【问题描述】:

JavaScript 模块“@google-cloud/iot”似乎与此处 (https://googleapis.dev/nodejs/iot/latest/index.html) 的文档不太相似。

例如,函数client.sendCommandToDevice() 被记录为返回类型SendCommandToDeviceResponse,而它实际上返回接口和未定义的复杂交集。我可以在模块内的命名空间嵌套中找到正确的类型,但即使这样我也无法从结果中获取我需要的数据。例如,...Response 类型有一个静态函数“toJSON()”,它接受一个响应并返回 JSON——但它不会接受实际的响应对象,我找不到任何方法来转换实际的响应对象将响应对象转换为预期的类型。

这不是唯一的此类错误。这可能是在没有检查它是否真的可以在 TypeScript 中使用的情况下将旧的 JavaScript API 过度仓促转换为 TypeScript 的产物吗?是否有一些关于旧 JavaScript API 的文档可供我比较?

这是一个代码 sn-p(转译前):

// node 14.17.3, TypeScript 4.4.4, iot 2.5.1

import iot from "@google-cloud/iot";
// Yes, I did the credentials thing...
const client = new iot.v1.DeviceManagerClient();

function generateRequest(id: string, data: any) {
    const formattedName = client.devicePath("myproject", "us-central1", "myregistry", id);
    const binData = Buffer.from(JSON.stringify(data)).toString("base64");

    return {
        ok: true,
        name: formattedName,
        binData: binData,
    };
}

async function run() {
    const project = await client.getProjectId();
    const parent = client.locationPath(project, 'us-central1');

    const deviceId = "d99999995";
    const data = { get: [ "program" ] };
    const request = generateRequest(deviceId, data);

    let r = await client.sendCommandToDevice(request);
    // what is r here???

    /* Same issue with, e.g.:
    client.updateDevice();
    client.modifyCloudToDeviceConfig()
    */
    return {
        ok: true,
        result: r,
    };
}

run().catch((err) => { console.error(err); });

【问题讨论】:

  • 你的问题是一个没有细节的好例子。提供您遇到的问题的示例。包括库、节点、tsc 等重要项目的版本。如果我们可以简单地复制并粘贴您的示例,然后利用我们的经验来帮助您解决问题,那么得到一个好的答案会容易得多。
  • 感谢您的回音——我不确定您在寻找什么样的细节。专门命名的函数(sendCommandToDevice,以及其他类似 updateDevice 和 modifyCloudToDeviceConfig)被记录为返回特定类型,但它们没有。我想调用该类型的文档函数,但我不能,因为返回不是其中之一。什么不清楚?
  • 通过提供带有详细信息的示例代码,我不必猜测您编写了哪些代码、要包含哪个版本的库、要安装哪个版本的工具来复制您的问题。阅读此链接:stackoverflow.com/help/minimal-reproducible-example
  • 如果我正确阅读了文档... googleapis.dev/nodejs/iot/latest/… ... sendCommandToDevice 的调用返回的是 不是 SendCommandToDeviceResponse 而是一个 JavaScript Promise,当解决时... 解析为 SendCommandToDeviceResponse。
  • 嗯,是的,这是一个承诺——我知道那部分。它解析为未记录的复杂联合类型。我已经添加了代码。我只想知道通话是否成功;该信息在记录的返回类型中,但我不知道如何从实际返回中获取它。

标签: node.js typescript google-cloud-platform google-api google-cloud-iot


【解决方案1】:

即时反馈:您对评论者的回复表明您明显感到沮丧。我认为可以合理地假设人们不会花时间回答你的问题来让你感到沮丧。我不愿回复,也不想被责备,但我想像他们一样努力帮助你......

该库的文档看起来是正确的,但我既不是 TypeScript 也不是 JavaScript 专家。我对 GCP 及其服务和编写客户端代码非常熟悉。

Google 一直在改进其服务,以反映其内部对 gRPC 的广泛使用。在我看来,这种向更多 gRPC 原生服务的转变正在渗入其 SDK(即 protobuf 消息的优势),我觉得这很令人困惑,尤其是因为我还没有看到它得到充分解释。

@google-cloud/iot 的情况下,这些方法确实引用了protobuf 消息。所以,你的 sendCommandToDevice 方法有一个签名,它接受一个 SendCommandToDeviceRequest 并返回一个 Promised SendCommandToDeviceResponse

正如我所说,我不熟悉 TypeScript,但在 JavaScript(原文如此)中,我想知道您是否必须使用 SendCommandToDeviceRequest 构造函数来创建您的请求:

function generateRequest(id, data) {
    const formattedName = client.devicePath("myproject", "us-central1", "myregistry", id);
    const binaryData = Buffer.from(JSON.stringify(data)).toString("base64");

    return {
        name: formattedName,
        binaryData: binaryData,
    };
}

const rqst = new iot.protos.google.cloud.iot.v1.SendCommandToDeviceRequest(
  generateRequest(deviceId, data)
);

注意该属性是binaryData 而不是binData

那么,既然是await'ed,我想你的回复类型应该是SendCommandToDeviceResponse

const resp = await client.sendCommandToDevice(rqst);

@Ash_max 在 cmets 中引用了此类型。虽然构造函数列在页面顶部,但页面下方是toJSON()。所以你应该能够:

console.log(`response: ${resp.toJSON()}`);

也许JSON.stringify(resp.toJSON())

我今天没有时间尝试这个,但我明天会尝试重现您的体验并更新此线程。

更新

我创建了一个 GCP 项目、注册表和设备。

我运行了上面列出的 Node.JS 代码,返回类型令人困惑;我得到了一个包含 3 个对象的数组,其中第一个看起来是一个原型,但不支持 toJSON,我也无法得到它 toString()

所以,我查看了APIs Explorer 并根据它sendCommandToDevice(我认为这是确定的),成功时响应正文将为空。

一头雾水,我写了等价的Golang程序:

package main

import (
    "context"
    b64 "encoding/base64"
    "fmt"
    "log"
    "os"

    "google.golang.org/api/cloudiot/v1"
)

func main() {
    ctx := context.Background()
    client, err := cloudiot.NewService(ctx)
    if err != nil {
        log.Fatal(err)
    }

    rqst := &cloudiot.SendCommandToDeviceRequest{
        BinaryData: b64.StdEncoding.EncodeToString([]byte("Hello Freddie")),
    }

    name := fmt.Sprintf("projects/%s/locations/%s/registries/%s/devices/%s",
        os.Getenv("PROJECT"),
        os.Getenv("REGION"),
        os.Getenv("REGISTRY"),
        os.Getenv("DEVICE"),
    )

    devices := client.Projects.Locations.Registries.Devices
    resp, err := devices.SendCommandToDevice(name, rqst).Do()
    if err != nil {
        log.Fatal(err)
    }

    log.Printf("%+v", resp)
}

它的resp 绝对是SendCommandToDeviceResponse 类型,并且包含ServerResponse,其中包括HTTPStatusCode

&{
  ServerResponse:{
    HTTPStatusCode:200
    Header:map[
      Cache-Control:[private]
      Content-Type:[application/json; charset=UTF-8]
      Date:[Wed, 20 Oct 2021 00:20:00 GMT]
      Server:[ESF] Vary:[Origin X-Origin Referer]
      X-Content-Type-Options:[nosniff]
      X-Frame-Options:[SAMEORIGIN]
      X-Xss-Protection:[0]
    ]
  }
}

因此,JavaScript (Node.JS|TypeScript) 代码应该以某种方式 (!) 也能够从 SendCommandToDeviceResponse 中获取 ServerResponse

文档似乎是正确的。

【讨论】:

  • 非常感谢您抽出宝贵的时间做出回应——我并不是要把我的挫败感发泄到那些可能会有所帮助的人身上。您上面的代码几乎正是我一直在尝试做的,但失败了,因为 JavaScript API 根本不会返回它记录的返回值,显然 Golang API 会这样做。我将尝试关闭所有 TypeScript 并使用旧的无类型 API 来查看是否至少可以让我获取数据。如果它有助于我到达那里,我什至可以接受你的回答。与此同时,我已经提交了一份正式的错误报告。
  • 不客气。谢谢!我怀疑存在问题,但我从该方法中得到了响应,我只是无法正确解码。可能(!)有一个技巧。我没有收到呼叫错误,我的 Golang 客户端设备正在接收命令。请在此处包含对 issuetracker 的引用。我想知道其他人是否能够解释如何做相当于 Golang 的resp.ServerResponse
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-11-18
  • 2013-09-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-20
相关资源
最近更新 更多