【问题标题】:firebase functions integration with xero-nodefirebase 功能与 xero-node 的集成
【发布时间】:2021-01-13 16:15:18
【问题描述】:

尝试创建一个由某些数据库或 onRequest 事件触发的 firebase 函数,该事件在 Xero 上创建付款以更好地管理收到的发票。

不确定我是否了解如何从 firebase 函数运行(如果可能的话)xero-node 库。

我一直在搞乱这两者,它似乎不像用秘密 ID 初始化对象和调用我期望的函数那么简单:

const xero = new XeroClient({
  clientId: '230823jff',
  clientSecret: 'sdfh39fhsdaf',
  redirectUris: [`http://localhost:3000/xero`],
  scopes: 'openid profile email accounting.transactions offline_access'.split(' '),
})

xero.accountingApi.getInvoices('tennetid093242')

看来我需要使用以下内容生成访问密钥(12 分钟后到期):

let consentUrl = await xero.buildConsentUrl()
res.redirect(consentUrl)

在邮递员中搞乱 api,这个流程感觉就像我让它变得比它应该的更复杂。

有没有办法我可以用管理员范围或其他东西来初始化它,而不必担心访问密钥...... 或者我应该在客户端使用 xero-node...(肯定不是)

有带有 xero-node 的 expressjs 版本,所以我是否可以通过将 redirectUri 设置为另一个 firebase 函数的地址来获取会话密钥来与 firebase onrequest 函数等效?


我正在慢慢地到达某个地方..

我的 firebase 函数如下所示:

const xero = new XeroClient({
  clientId: '123213123123',
  clientSecret: '123123123123',
  redirectUris: ['http://localhost:5001/example/us-central1/xeroAuthCode'],
  scopes: ['openid', 'profile', 'email', 'accounting.transactions', 'accounting.settings', 'offline_access']
})

exports.xeroInit = functions.https.onRequest(async (req, res) => {
  let consentUrl = await xero.buildConsentUrl()
  res.redirect(consentUrl)
})

exports.xeroAuthCode = functions.https.onRequest(async (req, res) => {
  let tokenSet = await xero.apiCallback(req.url)
  console.log(tokenSet)
})

我的想法是我调用 xeroInit 并将令牌发送到 xeroAuth 这似乎有效,因为控制台记录 req.url 给出:

/?code=c5105f6ce943....230a23fsadf&scope=openid%20profile%20email%20accounting.transactions%20accounting.settings&session_state=tFC6G9Go_zBguCjIpy8-9gl6-9SWLTlUmY5CXMq49es.3c42d9ca9e53285596193bf423f791f3

但我在尝试设置 apiCallback 时收到此错误

TypeError: Cannot read property 'callbackParams' of undefined

使用纯 express 应用程序进行测试,效果很好,我认为这是 firebase 函数模拟器的错误...

因为这与 express 一起使用,所以我在我的 firebase 函数中使用 express 并使用 request.url 调用 apiCallback 工作...... 当我让它完全适用于想要一起使用 firebase 和 xero-node 的其他人时,我会更新答案。

【问题讨论】:

标签: node.js firebase google-cloud-platform google-cloud-functions xero-api


【解决方案1】:

编辑: 啊,我认为您需要做的只是第二次使用初始化客户端:

await xero.initialize()

需要调用这个来在 XeroClient 上设置相关的 openid-client

buildConsentUrl 还在后台调用await xero.initialize(),因此由于您在初始线程中调用了它,因此它正确设置了客户端。由于 firebase 函数是孤立的,我认为您只需要调用 initialize() fn。



您需要让您希望通过 API 与之通信的 Xero 组织的用户通过整个 OAuth2.0 流程来生成 access_token。

我建议查看一个很棒的示例应用程序,它显示了整个流程:https://github.com/XeroAPI/xero-node-oauth2-app/blob/master/src/app.ts#L172


您的目标是帮助许多用户使用您的应用来读写他们的组织吗?或者您只是想为单个组织连接和自动化东西?

如果您尝试执行第二个操作,此视频展示了如何在 REST 客户端中生成初始 access_token 并将其插入到您的代码流中以不断刷新。 https://www.youtube.com/watch?v=Zcf_64yreVI

【讨论】:

  • 感谢您为我指明正确的方向!我有一个仪表板供所有公司人员查看需要采取行动的发票,但我只希望一个用户能够将付款过帐到 xero。 (单个组织自动执行一些操作以使用 webhook 等更改 firebase 记录等。)
  • 我已经更新了我的问题以代表我的进展,如果你愿意看一下;我将非常感激:@Serknight @
  • 在 firebase 回调函数中初始化 xero 给出了同样的错误。添加了我的发现的答案以及到目前为止我设法得到的工作。 (:
【解决方案2】:

非常感谢 SerKnight,他帮助我在 firebase 功能上进行了这项工作,以供将来参考,这是我正在工作的配置。

一些注意事项

  • 只是在 firebase 函数中调用 xero.initialize() 作为回调无论出于何种原因都不起作用,所以我使用 express 来处理初始设置。
  • 一旦我在数据库中获得了刷新令牌,我的连接函数就会发挥作用,因此我不需要在每次想要调用函数时都构建ConsentUrl。
  • 如果您愿意,可以继续使用 express 来调用您的函数。

确保您的 firebase 函数 url 完整地放入 xeros myapps 页面上的 OAuth 2.0 redirect URIs 中,正如您在我的示例中看到的那样。 localhost if using firebase emulators

const app = express()
app.use(cors())

let x_client_id = functions.config().xero.client_id
let x_client_sectet = functions.config().xero.client_secret

const xero = new XeroClient({
  clientId: x_client_id,
  clientSecret: x_client_sectet,
  redirectUris: ['http://localhost:5001/example/us-central1/xeroInit/callback'],
  scopes: ['openid', 'profile', 'email', 'accounting.transactions', 'accounting.settings', 'offline_access'],
  httpTimeout: 3000,
  state: 123
})

const connect = () =>
  new Promise(async (res, rej) => {
    let snapshot = await db.ref('xero-config').once('value')
    let tokenSet = snapshot.val()
    try {
      xero.initialize()
      const newTokenSet = await xero.refreshWithRefreshToken(x_client_id, x_client_sectet, tokenSet.refresh_token)
      db.ref('xero-config').set(newTokenSet)
      xero.setTokenSet(newTokenSet)
      res()
    } catch (error) {
      rej(error)
    }
  })

app.get('/connect', async (req, res) => {
  try {
    await connect()
    res.send('Connection established')
  } catch (error) {
    let consentUrl = await xero.buildConsentUrl()
    res.redirect(consentUrl)
  }
})
app.get('/callback', async (req, res) => {
  let TokenSet = await xero.apiCallback(req.url)
  db.ref('xero-config').set(TokenSet)
  res.send('Token updated ?')
})
exports.xeroInit = functions.https.onRequest(app)

exports.xeroOrganisation = functions.https.onRequest(async (req, res) => {
  await connect() //Doesn't handle errors and will break if inactive for 60 days but you get the idea
  await xero.updateTenants()
  res.json(xero.tenants[0])
})
  1. 使用http://localhost:5001/example/us-central1/xeroInit/connect 调用您的连接函数
  2. 确保在重定向后收到 token updated 消息
  3. 调用您的 xeroOrganisation 函数以确保一切正常(:

【讨论】:

    猜你喜欢
    • 2020-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-02
    • 2021-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多