Genace

generation API JSON content type: separate request format from error parsing

Content type is part of an HTTP contract, but it does not prove that the body is valid JSON. A generation client should declare what it sends and inspect what it receives. A reverse proxy can return an HTML error page before the API handler runs, so assuming that every response supports response.json() hides the original failure behind a parsing exception.

Send a serialized object explicitly

For a generation POST, use the JSON media type and serialize the body once. Do not pass a JavaScript object directly as Fetch’s body or confuse a form submission with a JSON document. The example constructs a request only; executing it creates paid work and should remain behind your application’s authorization boundary.

export function imageRequestOptions(key, prompt) {
  return {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${key}`,
      'Content-Type': 'application/json',
      Accept: 'application/json',
    },
    redirect: 'error',
    body: JSON.stringify({ model: 'nano-banana', prompt, n: 1 }),
  };
}

The public image route calls its request JSON parser and produces INVALID_JSON when parsing fails. It does not define a comprehensive global request-size promise or a strict media-type rejection policy in that handler. If your own proxy requires JSON and returns 415 for unsupported formats, describe that as your application’s contract.

Normalize media types without discarding evidence

Read the response Content-Type header, separate parameters such as charset, and retain the HTTP status. A missing or unexpected header deserves a controlled diagnostic branch. A response claiming JSON can still be malformed, so handle parsing failure independently from media-type classification.

For a client dedicated to this API, accepting application/json is sufficient for the documented JSON responses. If you build a more general parser that supports structured suffix types such as application/problem+json, specify that policy deliberately and do not assume those bodies have Genace’s error envelope.

Preserve the generation lifecycle

A valid JSON response can describe acceptance, request rejection, or a job snapshot. After HTTP 202, save the top-level job_id. After a submission failure with HTTP 502 and UPSTREAM_SUBMISSION_FAILED, inspect error.job_id if present. A GET snapshot uses id and may report failed even when HTTP status is successful.

Do not use the response media type to decide whether another generation is needed. HTML from an intermediary may mean the request never reached the handler, but it can also conceal a response after work began. Keep an uncertain submission branch whenever acceptance cannot be established from the available evidence.

Test format mistakes locally

Create fixtures for valid accepted JSON, malformed JSON with a JSON header, HTML with HTTP 502, and an empty response. Test incoming requests with a supported media type, an unsupported form type, and invalid syntax against your own proxy. Assert the resulting error preserves status and never includes the Authorization header.

Also check that a malformed successful body does not produce an accepted toast with an undefined job ID. The absence of a usable identifier is a recovery problem, not permission to repeat a paid POST automatically.

Related guides explain single body consumption, error schema validation, and input validation.

Continue with code and integration

Where these facts come from