diff --git a/src/cli.ts b/src/cli.ts index 614a02e..2e88e50 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -2,7 +2,7 @@ import path from "path"; import yargs from "yargs"; -import axios, { AxiosRequestConfig, AxiosResponse } from "axios"; +import axios, { AxiosError, AxiosRequestConfig, AxiosResponse } from "axios"; import { ConfigLocator } from "./config"; import { ProfileStore, Profile } from "./profile-store"; @@ -244,8 +244,19 @@ async function runApiCommand( ...(hasBody ? { data: payload.data } : {}), }; - const response = await httpClient.request(requestConfig); - stdout(`${JSON.stringify(response.data, null, 2)}\n`); + try { + const response = await httpClient.request(requestConfig); + stdout(`${JSON.stringify(response.data, null, 2)}\n`); + } catch (err) { + if (err instanceof AxiosError && err.response?.data !== undefined) { + const body = + typeof err.response.data === "string" + ? err.response.data + : JSON.stringify(err.response.data, null, 2); + throw new Error(`${err.message}\n${body}`); + } + throw err; + } } function parseBodyFlagValue(value: string): unknown { diff --git a/tests/cli.test.ts b/tests/cli.test.ts index 26af889..5206d75 100644 --- a/tests/cli.test.ts +++ b/tests/cli.test.ts @@ -2,6 +2,7 @@ import { ConfigLocator } from "../src/config"; import { ProfileStore } from "../src/profile-store"; import { OpenapiLoader } from "../src/openapi-loader"; import { run, HttpClient } from "../src/cli"; +import { AxiosError } from "axios"; import { VERSION } from "../src/version"; interface MemoryFsEntry { @@ -750,6 +751,34 @@ describe("cli", () => { ).rejects.toThrow("Invalid JSON body value"); }); + it("includes the response body in the error message on failed requests", async () => { + const { profileStore, openapiLoader } = createPostApiDeps(); + + const failingHttpClient: HttpClient = { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + request: async (config: any) => { + const response = { status: 400, statusText: "Bad Request", headers: {}, config, data: { message: "invalid input" } }; + throw new AxiosError("Request failed with status code 400", "ERR_BAD_REQUEST", config, {}, response); + }, + }; + + await expect( + run( + [ + "org_slug_repo_slug_ci_workflows_workflow_name_trigger", + "--org_slug", "myorg", + "--repo_slug", "myrepo", + "--workflow_name", "deploy", + "--input", '{"values":[{"name":"FOO","value":"bar"}]}', + ], + { cwd, profileStore, openapiLoader, httpClient: failingHttpClient, stdout: () => {} } + ) + ).rejects.toThrow(`Request failed with status code 400 +{ + "message": "invalid input" +}`); + }); + it("builds JSON request body from declared OAS3 requestBody properties", async () => { const localDir = `${cwd}/.ocli`; const profilesPath = `${localDir}/profiles.ini`;