{ }
GET
OpenAPI · REST API · File Handling · Dokumentation
Datei-Uploads und Downloads sauber in OpenAPI beschreiben
format: binary, multipart/form-data und Content-Disposition richtig einsetzen

OpenAPI-Spezifikationen für Datei-Operationen enthalten häufig Fehler: falsch verwendetes format, fehlende encoding-Objekte und undokumentierte Response-Header für Downloads. Dieser Artikel zeigt, wie Uploads und Downloads in OpenAPI 3.1 präzise modelliert werden — so dass Client-Generatoren korrekten Code produzieren und Integratoren keine Überraschungen erleben.

14 Min. Lesezeit format: binary · multipart/form-data · encoding · Content-Disposition OpenAPI 3.1 · YAML · Swagger UI · Client-Generierung

1. OpenAPI und binäre Daten: Grundlagen

OpenAPI beschreibt HTTP-Schnittstellen, und HTTP kann beliebige Binärdaten transportieren. Die Spezifikation muss daher einen Weg bieten, zwischen einfachen Textwerten, base64-kodierten Binärdaten und rohen Dateiinhalten zu unterscheiden. In OpenAPI 3.x wird das über das format-Feld im Schema gelöst: string ist der Basistyp, format: binary und format: byte sind zwei unterschiedliche Interpretationen. Wer den Unterschied nicht kennt, dokumentiert Datei-Endpoints falsch — mit der Folge, dass generierte Clients unbrauchbaren Code produzieren und manuelle Integratoren die falsche Kodierung wählen.

Der zweite Grundlagenaspekt: OpenAPI beschreibt Datei-Uploads und Downloads asymmetrisch. Beim Upload beschreibt man den requestBody mit dem korrekten Content-Type und Schema. Beim Download beschreibt man die responses-Einträge mit dem Content-Type der zurückgegebenen Datei und dem Schema der Binärdaten. Beide Seiten erfordern unterschiedliche YAML-Strukturen, und genau hier entstehen die meisten Dokumentationsfehler in der Praxis: Entwickler kopieren Upload-Strukturen für Downloads oder verwechseln, wo das schema-Objekt platziert werden muss.

2. format: binary vs. format: byte — der kritische Unterschied

format: byte beschreibt base64-kodierte Binärdaten, die als normaler JSON-String übertragen werden. Das ist sinnvoll, wenn eine kleine Binärdatei (z.B. ein kleines Bild oder ein Zertifikat) als Teil eines JSON-Objekts übertragen werden soll. Der Client kodiert die Binärdaten in Base64, bettet den String in das JSON ein und sendet Content-Type: application/json. Die Datei wird beim Empfang dekodiert. Diese Methode erhöht die Payload-Größe um ca. 33% durch die Base64-Kodierung.

format: binary hingegen beschreibt rohe Binärdaten, die nicht JSON-enkodiert werden. Dieser Format-Hinweis wird ausschließlich im Kontext von multipart/form-data oder application/octet-stream verwendet. Client-Generatoren interpretieren format: binary als Signal, die Datei als Datei-Part zu senden, nicht als String. Wer format: binary innerhalb eines normalen JSON-Schemas ohne multipart-Context verwendet, erzeugt eine inkonsistente Spezifikation: JSON kann keine Binärdaten direkt enthalten, und Tools werden uneinheitlich damit umgehen.


# openapi/schemas/file-schemas.yaml
components:
  schemas:
    # WRONG: binary inside regular JSON request — JSON cannot contain raw binary
    BadUploadRequest:
      type: object
      properties:
        file:
          type: string
          format: binary  # incorrect: binary outside multipart context
        name:
          type: string

    # CORRECT: base64 encoding for embedding binary in JSON
    EmbeddedFileRequest:
      type: object
      required: [fileData, filename]
      properties:
        fileData:
          type: string
          format: byte       # base64-encoded, suitable inside JSON
          description: Base64-encoded file content (max 1 MB due to size overhead)
        filename:
          type: string
          description: Original filename for storage
        mimeType:
          type: string
          description: MIME type of the encoded file

    # CORRECT: binary used in multipart/form-data context (see requestBody)
    DocumentUploadResponse:
      type: object
      properties:
        id:
          type: string
          format: uuid
        url:
          type: string
          format: uri
        size:
          type: integer
          description: File size in bytes

3. multipart/form-data vollständig modellieren

Ein vollständig modellierter multipart/form-data-Endpoint in OpenAPI 3.1 verwendet das requestBody-Objekt mit einem content-Schlüssel für den MIME-Type multipart/form-data. Das schema-Objekt darunter beschreibt alle Formularfelder als normales JSON-Schema — Textfelder als type: string, numerische Felder als type: integer, und Datei-Felder als type: string, format: binary. Das required-Array auf Schema-Ebene gibt an, welche Felder zwingend vorhanden sein müssen. Diese Struktur ist der einzige Weg, Upload-Endpoints so zu beschreiben, dass Swagger UI ein funktionsfähiges Testformular generiert und OpenAPI-Client-Generatoren korrekte Multipart-Requests produzieren.

Ein häufiger Fehler ist das Weglassen des required-Arrays im Schema — ohne es sind alle Felder optional, und Integratoren erfahren erst zur Laufzeit, welche Felder tatsächlich Pflicht sind. Ein zweiter Fehler: Wenn die API mehrere verschiedene Datei-Typen akzeptiert (z.B. Bild oder PDF, aber nicht beides gleichzeitig), wird das über oneOf auf Schema-Ebene modelliert, nicht durch separate Endpoints. OpenAPI 3.1 hat hier volle JSON-Schema-Unterstützung und erlaubt oneOf, anyOf und discriminator auch in requestBody-Schemata.


# openapi/paths/upload-complete.yaml
/api/v1/documents:
  post:
    operationId: uploadDocument
    summary: Upload document with metadata
    requestBody:
      required: true
      content:
        multipart/form-data:
          schema:
            type: object
            required:
              - file
              - title
            properties:
              file:
                type: string
                format: binary
                description: Document file (PDF or image, max 20 MB)
              title:
                type: string
                minLength: 3
                maxLength: 200
                description: Human-readable document title
              tags:
                type: array
                items:
                  type: string
                maxItems: 10
                description: Optional classification tags
              expiresAt:
                type: string
                format: date
                description: Optional expiry date (ISO 8601)
          encoding:
            file:
              contentType: application/pdf, image/jpeg, image/png, image/webp
    responses:
      '201':
        description: Document created
        headers:
          Location:
            schema:
              type: string
              format: uri
            description: URL of the newly created document resource
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Document'

4. Das encoding-Objekt für gemischte Content-Types

Das encoding-Objekt im requestBody erlaubt es, für einzelne Felder eines Multipart-Requests den Content-Type zu spezifizieren. Das ist besonders wichtig für das Datei-Feld: Wenn die API nur PDFs akzeptiert, sollte encoding.file.contentType: application/pdf stehen, damit Tools und Integratoren wissen, dass andere Typen abgelehnt werden. Wenn zusätzlich Header für einzelne Parts gesetzt werden sollen — etwa ein spezifischer Zeichensatz für ein Textfeld — können diese im encoding.field.headers-Objekt definiert werden.

Ein fortgeschrittenes Szenario: Ein Multipart-Request enthält einen Binär-Part und einen JSON-Part. Ohne explizites encoding-Objekt ist unklar, wie der JSON-Part kodiert wird. Mit encoding.metadata.contentType: application/json wird definiert, dass dieses Feld im Multipart-Body selbst als JSON-String kodiert ist. Der empfangende Server muss diesen Part dann als JSON parsen. Dieses Muster ermöglicht strukturierte Metadaten zusammen mit Binärdaten in einem einzigen Netzwerk-Roundtrip — ohne die Metadaten als separate Formularfelder zu flachen Strings serialisieren zu müssen.

5. Download-Endpoints korrekt beschreiben

Download-Endpoints geben binäre Daten zurück, was in OpenAPI über die responses-Sektion beschrieben wird. Der korrekte Content-Type für generische Datei-Downloads ist application/octet-stream. Wenn die API immer einen spezifischen Typ zurückgibt (z.B. immer PDF), sollte application/pdf verwendet werden — das ist präziser und erlaubt dem Client, den korrekten Decoder zu wählen. Das Schema des Response-Bodys ist in beiden Fällen {type: string, format: binary}. Diese Kombination signalisiert OpenAPI-Tools, dass der Response-Body rohe Binärdaten enthält.

Eine wichtige Ergänzung für Download-Endpoints: Wenn die API sowohl JSON-Metadaten als auch den Binärinhalt liefern kann (z.B. über Accept-Header), müssen beide Content-Types unter content beschrieben werden. content: application/json: schema: DocumentMetadata für die Metadaten-Variante und content: application/pdf: schema: {type: string, format: binary} für die Binär-Variante. Swagger UI zeigt dann beide Varianten an und Integratoren wissen, dass sie über den Accept-Header zwischen JSON und Binär wählen können.

6. Content-Disposition und Dateinamen im Response-Header

Der Content-Disposition-Header steuert, ob der Browser eine Datei inline anzeigt oder als Download speichert. Content-Disposition: attachment; filename="bericht-2026-05.pdf" löst einen Download-Dialog aus. Content-Disposition: inline zeigt die Datei im Browser an, wenn der Content-Type unterstützt wird. In OpenAPI wird dieser Header im headers-Objekt der Response beschrieben. Das Schema des Headers ist ein String mit einem regulären Ausdruck als pattern, der die erlaubte Syntax des Headerwertes beschreibt. Da der Dateiname variabel ist, reicht ein einfaches description-Feld mit einem Beispielwert oft aus.

Ein wichtiges Detail für internationale Dateinamen: Der einfache filename-Parameter unterstützt keine Nicht-ASCII-Zeichen. Für Dateinamen mit Umlauten oder anderen Sonderzeichen muss filename* nach RFC 5987 verwendet werden: Content-Disposition: attachment; filename*=UTF-8''Bericht%202026-05.pdf. APIs, die Dateien mit benutzerseitigen Originalnamen zurückgeben müssen, sollten beide Parameter setzen: filename als ASCII-Fallback und filename* für die korrekte Darstellung in modernen Clients. In der OpenAPI-Dokumentation sollte dieses Verhalten explizit in der Header-Beschreibung erklärt werden.


# openapi/paths/download.yaml
/api/v1/documents/{id}/download:
  get:
    operationId: downloadDocument
    summary: Download a document by ID
    parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
    responses:
      '200':
        description: Document content
        headers:
          Content-Disposition:
            description: >
              Attachment with original filename.
              Uses filename* (RFC 5987) for non-ASCII names.
              Example: attachment; filename*=UTF-8''Bericht%202026.pdf
            schema:
              type: string
          Content-Length:
            schema:
              type: integer
            description: File size in bytes
          ETag:
            schema:
              type: string
            description: Unique file version identifier for caching
        content:
          application/pdf:
            schema:
              type: string
              format: binary
          application/octet-stream:
            schema:
              type: string
              format: binary
      '404':
        $ref: '#/components/responses/NotFound'

7. Mehrere Dateien in einem Request beschreiben

Wenn eine API mehrere Dateien in einem einzigen Request akzeptiert, gibt es in OpenAPI zwei Modellierungsansätze. Der erste: Ein Formularfeld als Array definieren — type: array, items: {type: string, format: binary}. Das entspricht dem HTML-Pattern <input type="file" multiple> und sendet mehrere Parts mit demselben Feldnamen. Der zweite Ansatz: Separate Feldnamen für jede Datei — primaryDocument: {type: string, format: binary} und attachments: {type: string, format: binary}. Dieser Ansatz ermöglicht unterschiedliche Validierungsregeln pro Datei-Slot.

Das maxItems-Constraint auf dem Array-Feld beschränkt die Anzahl der hochladbaren Dateien in der Dokumentation. Auf der Serverseite muss diese Beschränkung separat implementiert werden — OpenAPI-Constraints sind rein dokumentarisch und werden nicht automatisch durchgesetzt. Ein häufiger Fehler: Wenn der Server nur eine Datei pro Request akzeptiert, wird das Array-Muster trotzdem verwendet, weil items: {type: string, format: binary} «offensichtlich richtig» wirkt. Das sollte ein reguläres Einzel-Feld sein, kein Array — Integratoren wählen sonst unnötig komplexe Client-Implementierungen.

8. Client-Generierung mit format: binary

OpenAPI-Client-Generatoren wie openapi-generator und swagger-codegen verarbeiten format: binary unterschiedlich je nach Zielsprache. In TypeScript wird ein Feld mit format: binary als Blob | File generiert. In Python als IO[bytes]. In Java als File-Objekt. Diese Typen erlauben es dem Client, Dateisystem-Objekte direkt zu übergeben, ohne manuelle Kodierung. Wenn das Schema fehlerhaft ist — z.B. format: binary fehlt oder durch format: byte ersetzt wurde — generiert der Client einen string-Parameter, und der Integrator muss die Datei manuell base64-kodieren.

Für Symfony-Backends empfiehlt sich, die generierte Client-Bibliothek regelmäßig zu testen: die generierte TypeScript-Client-Methode sollte direkt ein File-Objekt aus dem Browser-FileReader akzeptieren. Wenn das nicht der Fall ist, liegt ein Fehler in der OpenAPI-Spezifikation vor. Ein praktischer Test: Den Swagger UI für den eigenen Endpoint öffnen und das Datei-Upload-Feld testen. Swagger UI generiert aus einer korrekten Spezifikation ein natürliches Datei-Auswahlfeld. Erscheint stattdessen ein Texteingabefeld, fehlt format: binary oder der Context ist falsch.

Szenario Content-Type Schema Hinweis
Datei-Upload multipart/form-data format: binary Datei als Part, nicht base64
Kleines Bild in JSON application/json format: byte base64, +33% Größe
Generischer Download application/octet-stream format: binary Rohe Binärdaten im Body
PDF-Download application/pdf format: binary Spezifischer MIME bevorzugt
Mehrere Dateien multipart/form-data array, items: binary Gleicher Feldname, mehrere Parts

Mironsoft

OpenAPI-Dokumentation, REST API Design und Client-Generierung

OpenAPI-Spezifikationen, die Client-Generatoren wirklich nutzen können?

Wir prüfen und korrigieren OpenAPI-Spezifikationen für Datei-Endpoints, dokumentieren Upload- und Download-Varianten vollständig und validieren die generierten Clients gegen die Implementierung.

Spezifikations-Review

OpenAPI-Dokument auf Fehler bei format, encoding und Response-Headern prüfen

Client-Generierung

TypeScript- und PHP-Clients aus OpenAPI generieren und gegen die API validieren

Dokumentation

Vollständige Upload- und Download-Endpoints mit allen Fehlerfällen dokumentieren

10. Zusammenfassung

Datei-Uploads und Downloads in OpenAPI 3.1 korrekt zu beschreiben erfordert das Verständnis weniger, aber kritischer Unterschiede: format: binary für rohe Binärdaten im Multipart-Kontext, format: byte für base64-kodierte Daten in JSON. Das encoding-Objekt präzisiert, welche MIME-Types für einzelne Formular-Parts akzeptiert werden. Download-Endpoints beschreiben die Response mit dem spezifischsten verfügbaren MIME-Type und dem Content-Disposition-Header in der headers-Sektion. Für internationale Dateinamen müssen sowohl filename als auch filename* (RFC 5987) gesetzt werden.

Der praktische Test für eine korrekte Spezifikation: Swagger UI zeigt für Upload-Felder ein natürliches Datei-Auswahlfeld, und ein generierter TypeScript-Client akzeptiert ein File-Objekt direkt als Parameter. Wenn ein Texteingabefeld erscheint oder der Client einen string-Parameter erwartet, liegt ein Fehler in der Spezifikation vor. Die hier gezeigten YAML-Strukturen sind der direkte Weg zu einer OpenAPI-Dokumentation, die sowohl für Integratoren als auch für Code-Generatoren produktiv nutzbar ist.

Datei-Uploads und Downloads in OpenAPI — Das Wichtigste auf einen Blick

format: binary vs. byte

binary = rohe Binärdaten in multipart/form-data. byte = base64-kodiert in JSON. Verwechslung erzeugt falsche Client-Code-Generierung.

encoding-Objekt

Definiert Content-Type pro Multipart-Part. Ermöglicht JSON-Metadaten neben Binärdaten im selben Request.

Download-Response

application/pdf (oder octet-stream) + schema: {type: string, format: binary}. Content-Disposition im headers-Objekt dokumentieren.

Validierungstest

Swagger UI zeigt Datei-Auswahlfeld. Generierter Client akzeptiert File/Blob-Objekt. Textfeld = Fehler in der Spezifikation.

11. FAQ: Datei-Uploads und Downloads in OpenAPI beschreiben

1format: binary vs. format: byte?
binary = rohe Binärdaten in multipart. byte = base64 in JSON. Verwechslung erzeugt falschen Client-Code aus Generator-Tools.
2Upload korrekt in OpenAPI beschreiben?
requestBody mit multipart/form-data. Dateifeld: type: string, format: binary. encoding-Objekt für erlaubten Content-Type pro Part.
3Download-Endpoint in OpenAPI beschreiben?
Response mit application/pdf (oder octet-stream) und schema: {type: string, format: binary}. Content-Disposition im headers-Objekt.
4Was macht das encoding-Objekt?
Definiert Content-Type pro Multipart-Part. Ermöglicht JSON-Metadaten neben Binärdaten im gleichen Request — klar für Integratoren dokumentiert.
5Swagger UI zeigt Textfeld statt Datei-Auswahl?
format: binary fehlt oder Content-Type ist nicht multipart/form-data. Korrekte Kombination erzeugt automatisch ein Datei-Auswahlfeld.
6Content-Disposition dokumentieren?
Im headers-Objekt der Response. Schema: type: string. Description mit Beispielwert. filename* für Umlaute nach RFC 5987 erwähnen.
7Mehrere Dateien in einem Request?
type: array, items: {type: string, format: binary} für Array-Feld. Oder separate Felder mit unterschiedlichen Namen wenn verschiedene Validierungsregeln nötig.
8Was generiert openapi-generator für format: binary?
TypeScript: Blob | File. Python: IO[bytes]. Java: File-Objekt. Direkte Übergabe ohne manuelle Kodierung möglich.
9Verschiedene Download-Formate beschreiben?
Mehrere Content-Types unter content in der Response: JSON für Metadaten, PDF für Binärinhalt. Wahl über Accept-Header.
10Dateinamen mit Umlauten im Content-Disposition?
filename*=UTF-8''Dateiname.pdf nach RFC 5987. Dazu filename= als ASCII-Fallback. Beide im selben Header, in der OpenAPI-Description erklären.