Failed to make API requests to Bitbucket via @forge/api

Hi, I am having an issue when calling requestBitbucket as following

PROXY_ERR: Forge platform failed to process runtime HTTP request - 400 - INVALID_TARGET_URL
at handleProxyResponseErrors (webpack://bitbucket-dynamic-pipelines-provider/node_modules/.pnpm/@forge+api@4.1.2_webpack-bundle-analyzer@4.10.2/node_modules/@forge/api/out/api/fetch.js:85:1)
at <anonymous> (webpack://bitbucket-dynamic-pipelines-provider/node_modules/.pnpm/@forge+api@4.1.2_webpack-bundle-analyzer@4.10.2/node_modules/@forge/api/out/api/fetch.js:30:1)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
<my stack call>
at async Object.main (webpack://bitbucket-dynamic-pipelines-provider/src/index.js:51:24)
at async /mnt/wrapper/wrapper_40.cjs:2:583143 {
status: 400,
errorCode: 'INVALID_TARGET_URL'
}

Here is the code

const url = assumeTrustedRoute(
    `${base}/pipelines?page=1&pagelen=20&sort=-created_on&target.branch=master&status=PASSED&status=SUCCESSFUL&trigger_type=PUSH`,
  );

  const result = await (await App.asApp().requestBitbucket(url)).json();
  return result?.values ?? [];

Here is the resolved url by @forge/api that is given to fetch: https://bitbucket/2.0/repositories/<mysite>/<myrepo>/pipelines?page=1&pagelen=20&sort=-created_on&target.branch=master&status=PASSED&status=SUCCESSFUL&trigger_type=PUSH

I presume that https://bitbucket will be later resolved into an URL by Forge Proxy

Hi @BoZhang, I’ve created a new thread as instructed. Thank you for having a look.
As per your comment.

Unfortunately it’s not the issue. I can be 100% sure that the variables <mysite> and <myrepo> are correct as I am developing this Forge app for our internal usage. Moreover, I still can make the call with curl (basic authenticated, bitbucket replaced with api.bitbucket.org) successfully

I’ve also tried resolver.define before but the dynamic pipeline immediately failed and it’s reported as Selected Dynamic Pipelines provider Forge app is malformed and can't be invoked.

My appId is 9cea5b71-26f0-442e-8646-4ff63a4b655f. Appreciated!

Hi @BrianPham, I had a look at our logs and it seems like there was an issue with the workspace Id that you are passing in. Can you let me know the id that you are passing in (you can just give me the first 4 and last 4 characters of the ID if you don’t want to publish your entire workspaceId).

Ooh, are we talking about UUIDs :open_mouth:? I am passing slugs to the call at the moment, first and last 4 characters would expose the most of it :sweat_smile: You can let me know if you need the UUID’s instead. Let’s me try changing to my site’s UUID first.

Nonetheless, the document says This can either be the workspace ID (slug) or the workspace UUID surrounded by curly-braces, for example {workspace UUID}., wonder why the slug does not work.

Thank you for looking into it

Hi, yes the worskpace Id should be a 128 bit UUID, it should be in the same format as your appId. I can DM you the first 4 and last 4 digits of what workspace Id should be for your requests, are you able to confirm it’s the one that you are using?
By the way, are you hard coding the workspaceId in your code or are you using the workspace Id being passed in the context parameter of your resolver function?

1 Like

Ooh, that’s new :smile:. No worries for the workspace ID, I’ll ask my workspace admin. Do I need the curly braces for it?

I am currently using a slug (the one in the URL) for the call, not even an UUID, which works perfectly with curl :thinking:

For the latter question, yes I am hard coding it as this will only be used for my organisation. Tried to use the resolver function before but did not have any lucks.

Yeah, you need to have braces around it. It’s best to use the value that is provided within the argument of the resolver function, like:

resolver.define("fetchRepository", async ({ context }) => {
  const repositoryId = context.extension.repository.uuid;
  // blah blah
});

Tried to use the resolver function before but did not have any lucks

What was the error that you ran into when you tried this? was it the same error? are you able to add a console log to figure out what’s being passed to you? this method should work.

Yeah I totally agree but there was no error when I tried implementing the resolver thing, because the pipeline could not even invoke the provider:
Selected Dynamic Pipelines provider Forge app is malformed and can't be invoked.

Are you able to share a code snippet or a traceId?

There was no traceId as the Forge app was not even invoked. And unfortunately I did not commit the related changes for it but deployed directly. As far as I can remember it could be these:

// api.mjs
resolver.define("getPipelines", () => {
  const url = assumeTrustedRoute(
    `${base}/pipelines?page=1&pagelen=20&sort=-created_on&target.branch=master&status=PASSED&status=SUCCESSFUL&trigger_type=PUSH`,
  );

  const result = await (await App.asApp().requestBitbucket(url)).json();
  return result?.values ?? [];
})
// index.js
import './api.mjs';
// blah.mjs
import { invoke } from '@forge/bridge';

await invoke('getPipelines')

How are you constructing base?

Can you please try change your code to

import api, { route } from "@forge/api";
import Resolver from "@forge/resolver";

const resolver = new Resolver();

resolver.define("getPipelines", async ({ context }) => {
  const workspaceId = context.workspaceId;
  const repositoryId = context.extension.repository.uuid;

  console.log(`Fetching repository ${workspaceId}/${repositoryId}`)

  const res = await api
    .asApp()
    .requestBitbucket(route`/2.0/repositories/${workspaceId}/${repositoryId}/pipelines?page=1&pagelen=20&sort=-created_on&target.branch=master&status=PASSED&status=SUCCESSFUL&trigger_type=PUSH`);

  const result = await res.json();
  return result?.values ?? [];
});

This

const base = `/2.0/repositories/${workspace}/${repo}`;

@BoZhang I’ve changed the code as you requested, no luck found

It looks like there was an issue with constructing the resolver, did you make sure to install the @forge/resolver module and import it?
To help with debugging, are you able to start up a tunnel (using command forge tunnel) which spin up your app locally and receive invocations.

Yes I installed and imported correctly using pnpm (can it be a problem?).
Well, I do not have the permission needed so I can not install the development environment version :sweat_smile:

By the way, I’ve correctly figured out my org’s UUID (it matches the masked UUID you sent me earlier), replaced the variable with it, but something weird happened: the Forge app stopped without throwing any errors after calling node-fetch

I am not too sure what you mean by stopped? are you seeing the invocation continue at the api.asApp().requestBitbucket() step until the function times out? do you have a traceId for a request like this?

Ah sorry, it’s me overlooking the error log, had to be because I wasn’t refreshing. The calls were succeeded and the error was my logic’s

Ah right, no worries, is it all working for you now?

Yes, fortunately! Thank you for your help!

1 Like