Forge App: INVALID_TARGET_URL and 400 errors when calling Bitbucket API in headless endpoint

Clay Bailey
I'm New Here
I'm New Here
Those new to the Atlassian Community have posted less than three times. Give them a warm welcome!
October 4, 2024

I'm developing a headless Forge app (id is ari:cloud:ecosystem::app/e2584630-808f-4334-b7af-6ae832fdbacc) that serves as a serverless endpoint to interact with the Bitbucket API. The app's purpose is to update design tokens in a specific repository. It doesn't have a UI component; instead, it's designed to be triggered externally and perform operations directly on the repository.

Key characteristics of my app:

  1. It's a headless Forge app with no UI.
  2. It uses a web trigger to create an endpoint that can be called externally.
  3. Its main function is to update a JSON file containing design tokens in a Bitbucket repository.
  4. It needs to read the current file (if it exists), update its contents, and commit the changes back to the repository.

I'm encountering persistent issues with my Bitbucket API calls, receiving INVALID_TARGET_URL and 400 errors. Here's my current setup:

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

const WORKSPACE = 'my-workspace';
const REPO_SLUG = 'my-repo';
const BRANCH = 'main';
const FILE_PATH = 'input/design-tokens.json';

export const designTokensHandler = async (req, context) => {
  // ... (request parsing code) ...

  try {
    // Get the current file (if it exists)
    const getFileUrl = route`/2.0/repositories/${WORKSPACE}/${REPO_SLUG}/src/${BRANCH}/${FILE_PATH}`;
    let currentFile;
    try {
      const response = await api.asApp().requestBitbucket(getFileUrl);
      if (response.status === 200) {
        currentFile = await response.json();
      }
    } catch (error) {
      console.log('Error fetching current file:', error);
      if (error.response && error.response.status !== 404) throw error;
    }

    // Prepare the commit
    const message = commitMessage || 'Update design tokens';

    // Create or update the file
    const updateFileUrl = route`/2.0/repositories/${WORKSPACE}/${REPO_SLUG}/src`;
    const response = await api.asApp().requestBitbucket(
      updateFileUrl,
      {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          message: message,
          branch: BRANCH,
          files: [
            {
              path: FILE_PATH,
              contents: JSON.stringify(parsedTokens, null, 2)
            }
          ],
          ...(currentFile && { parents: [currentFile.commit.hash] })
        })
      }
    );

    if (!response.ok) {
      const errorBody = await response.text();
      throw new Error(`HTTP error! status: ${response.status}, body: ${errorBody}`);
    }

    // ... (success response handling) ...

  } catch (error) {
    console.error('Error updating design tokens:', error);
    // ... (error response handling) ...
  }
};

My manifest.yml includes:

modules:
  webtrigger:
    - key: design-tokens-trigger
      function: designTokensHandler

permissions:
  scopes:
    - read:repository:bitbucket
    - write:repository:bitbucket

I've tried:

  1. Hardcoding the URLs
  2. Using the route template literal
  3. Checking and double-checking permissions
  4. Verifying the Bitbucket API documentation

Despite these attempts, I'm still receiving errors. Initially, I got "Disallowing path manipulation attempt" errors. After addressing those by hardcoding the URLs, I'm now getting 400 Bad Request errors.

Questions:

  1. What am I missing in my Bitbucket API calls for this type of headless, serverless Forge app?
  2. Are there any known issues with Forge apps interacting with the Bitbucket API in this way?
  3. How can I debug this further? Are there any Forge-specific tools or logs I should be looking at for a headless app like this?
  4. Is there anything specific I need to consider when creating a headless, endpoint-only Forge app that interacts with Bitbucket?

Any help or guidance would be greatly appreciated. Thank you!

2 answers

1 vote
Aron Gombas _Midori_
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
October 7, 2024

@Clay Bailey You can't just call an arbitrary external URL from your Forge layer.

What you should examine here is Forge Remote, because it seems to me that it fits the architecture you are trying to build (Forge with an external AWS backend) very well.

1 vote
David Bakkers
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
October 4, 2024

Howdy @Clay Bailey 

Best to ask this type of question the the Developer's Community in the Forge section.

Make sure to add the following information to your question:

  1. Whether the problem happens when running the app from within BB cloud (after uploading it) as well as running it locally through the bridge
  2. If locally, what steps you've taken to update the bridge version and test it's running
  3. Whether the problems happens for all API endpoints or only specific ones
  4. If specific ones, which ones, and does the problem change if you make the call asUser() instead of asApp()
  5. What testing of the same request to the same endpoint you did with your API test tool.

Suggest an answer

Log in or Sign up to answer
DEPLOYMENT TYPE
CLOUD
PRODUCT PLAN
PREMIUM
PERMISSIONS LEVEL
Product Admin Site Admin
TAGS
AUG Leaders

Atlassian Community Events