Skip to content

Differentiate between success and error for empty responses #2291

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
1 task
cbodin opened this issue May 5, 2025 · 0 comments
Open
1 task

Differentiate between success and error for empty responses #2291

cbodin opened this issue May 5, 2025 · 0 comments
Labels
bug Something isn't working openapi-fetch Relevant to the openapi-fetch library

Comments

@cbodin
Copy link

cbodin commented May 5, 2025

openapi-fetch version

0.13.7

Description

It's currently impossible to differentiate between success and error if both responses contain no body.

Consider the following OpenAPI document:

{
  "openapi": "3.0.1",
  "info": {
    "title": "API",
    "version": "1.0.0"
  },
  "paths": {
    "/resource/{id}": {
      "post": {
        "tags": [
          "API"
        ],
        "operationId": "ResourceById:intPost",
        "responses": {
          "404": {
            "description": "Not Found"
          },
          "204": {
            "description": "No Content"
          }
        }
      }
    }
  },
  "components": { }
}

If the POST succeeds, a 204 with no body is returned. If the resource with the specified ID is not found, a 404 with no body is returned.

The data and error in the response from this endpoint are always undefined so the response status would need to be checked.

This makes checking for success/error inconsistent between different endpoints.

A more complete example with a few different endpoints where a 400 Bad Request contains a error response:

const { POST, GET, DELETE } = createClient<paths>();

async function getResource(id: number) {
  const { data, response } = await GET("/resource/{id}", {
    params: { path: { id } },
  });

  if (data) {
    return data;
  }

  if (response.status === 404) {
    throw new NotFoundError();
  }

  throw new InternalServerError(response.headers.get("request-id"));
}

async function updateResource(id: number) {
  const { error, response } = await POST("/resource/{id}", {
    params: { path: { id } },
  });

  if (response.status === 204) {
    return;
  }

  if (response.status === 404) {
    throw new NotFoundError();
  }

  if (error && response.status === 400) {
    throw new BadRequestError(error);
  }

  throw new InternalServerError(response.headers.get("request-id"));
}

async function deleteResource(id: number) {
  const { response } = await DELETE("/resource/{id}", {
    params: { path: { id } },
  });

  if (response.status === 204) {
    return;
  }

  if (response.status === 404) {
    throw new NotFoundError();
  }

  throw new InternalServerError(response.headers.get("request-id"));
}

Reproduction

Configure the client and check the types:

export interface paths {
  "/resource/{id}": {
    parameters: {
      query?: never;
      header?: never;
      path?: never;
      cookie?: never;
    };
    get?: never;
    put?: never;
    post: operations["ResourceById:intPost"];
    delete?: never;
    options?: never;
    head?: never;
    patch?: never;
    trace?: never;
  };
}
export type webhooks = Record<string, never>;
export interface components {
  schemas: never;
  responses: never;
  parameters: never;
  requestBodies: never;
  headers: never;
  pathItems: never;
}
export type $defs = Record<string, never>;
export interface operations {
  "ResourceById:intPost": {
    parameters: {
      query?: never;
      header?: never;
      path: {
        id: number;
      };
      cookie?: never;
    };
    requestBody?: never;
    responses: {
      /** @description No Content */
      204: {
        headers: {
          [name: string]: unknown;
        };
        content?: never;
      };
      /** @description Not Found */
      404: {
        headers: {
          [name: string]: unknown;
        };
        content?: never;
      };
    };
  };
}


const { POST } = createClient<paths>();

const { data, error } = await POST("/resource/{id}", {
  params: { path: { id: 123 } },
});

Expected result

Responses with no content should probably be returned as null instead of undefined, as they are indeed defined but empty.

Checking for successful responses will be as easy as comparing with undefined:

const isSuccess = data !== undefined;

Extra

@cbodin cbodin added bug Something isn't working openapi-fetch Relevant to the openapi-fetch library labels May 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working openapi-fetch Relevant to the openapi-fetch library
Projects
None yet
Development

No branches or pull requests

1 participant