Purrx

Structured output: JSON you can actually parse

Stop regex-ing prose. Use responseMimeType and responseSchema to make Gemini return JSON that matches a shape your code can rely on.

10 min+30 XPHands-on

Paragraphs of text are hard for a program to use. As soon as an AI feature is more than a chat window, your code needs specific fields. Writing "please reply in JSON" in the prompt works most of the time. The rest of the time, the model wraps the JSON in markdown, adds a friendly sentence first, or invents a field.

Ask the API, not the model

Gemini can guarantee the shape for you. Set responseMimeType to application/json and give it a responseSchema (a describing the fields you want). Now valid JSON of that shape is the only thing the model can write. This is enforced while it writes, not checked afterwards.

the shape of it
await gemini.generateContent({
  contents: "Extract the task details: 'Ship the auth fix by Friday, high priority.'",
  config: {
    responseMimeType: "application/json",
    responseSchema: {
      type: "OBJECT",
      properties: {
        task:     { type: "STRING" },
        priority: { type: "STRING", enum: ["low", "medium", "high"] },
        dueDay:   { type: "STRING" },
      },
      required: ["task", "priority"],
    },
  },
});

Two details trip people up:

  • Types are upper-case: STRING, NUMBER, BOOLEAN, OBJECT, ARRAY.
  • The JSON still arrives as a string in parts[0].text, so you still call JSON.parse yourself.

Everything else about the response stays the same.

Going deeper — how schema enforcement actually works

The API isn't asking politely and checking afterwards. It uses : at each step, the model may only pick tokens that could still lead to output that matches your schema. Having just emitted {, a quote is permissible and the letter x is not.

This is why the guarantee is strong — invalid JSON is not merely unlikely, it is unreachable — and it is also why a very elaborate schema can degrade answer quality. Every constraint removes options the model might otherwise have used to express itself. Ask for the fields you need, not every field you can imagine.

Why enum is the most valuable line here

A free-text field lets the model vary: "high", "High", "urgent", "P1". All reasonable, all different, and all breaking your switch statement. An limits the field to a fixed list. Whenever your code makes a decision based on a value, use an enum for it.

Practical notes

  • Name fields descriptively. The key names are part of the prompt: dueDay extracts better than d.
  • Mark only what you truly need as required. Forcing a field the source text doesn't contain invites invention.
  • Still wrap the parse in try/catch. If the answer gets cut off (for example by MAX_TOKENS), the JSON is incomplete and JSON.parse will throw.
  • Lower the temperature. Extraction is not a creative task.

Key takeaways

  • Use responseMimeType plus responseSchema to guarantee valid JSON instead of asking for it nicely.
  • Use an enum wherever your code makes a decision based on a value.
  • A schema guarantees the shape, not that the values are true. Still check them.

Sign in to run the exercise

Reading is free. Writing code here needs an account so we have somewhere to keep your Gemini key and the +30 XP you are about to earn.