Data Types
La especificación de OpenAPI intenta quedarse lo más cerca posible del JSON Schema pero no es 100%.
Vamos a devolver algún valor para nuestra llamada get a /v1/customers. El contenido será un array y los items de ese array serán del tipo string.
Un schema en APIs, especialmente en especificaciones como OpenAPI, es una definición del formato y de las reglas de los datos que serán enviados o recibidos. Sirve como un contrato que define cómo los datos deben ser estructurados, cuáles son los tipos esperados, y las validaciones que deben ser aplicadas.
Vamos a correr un poquito y después volver a caminar.
paths:
/v1/customers:
get:
responses:
'200':
description: List of Customers
content:
application/json: # Estamos indicando que estará en formato JSON
schema: # Aquí estamos definiendo cuál será el formato de datos.
type: array
items:
description: Customer Name
type: string
minLength: 2
maxLength: 100

Antes de proseguir vamos a entender lo que podemos tener en content.
Content
El application/json es esencialmente una indicación formal del formato de los datos intercambiados, permitiendo que el cliente y el servidor entiendan cómo procesar la información. Se dio énfasis a este objeto pues es el más común, pero podríamos tener otros formatos:
-
application/xml<customer>
<name>John Doe</name>
<age>30</age>
</customer> -
application/yamlotext/yaml: Para datos en formato YAML.name: John Doe
age: 30 -
application/x-ndjson: Para JSON en formato de líneas separadas (Newline Delimited JSON).{"name": "John Doe", "age": 30}
{"name": "Jane Smith", "age": 25} -
application/x-www-form-urlencoded: Usado en formularios HTML para enviar datos en formato de pares clave-valor.name=John+Doe&age=30 -
text/plain: Para texto simple sin formateo.Hello, World! -
text/csv: Para datos tabulares en formato CSV (valores separados por comas).name,age
John Doe,30
Jane Smith,25 -
image/jpeg,image/png,image/gif: Usados para transferir imágenes. -
application/octet-stream: Para transferencia de archivos binarios genéricos como .exe o .zip.
Vea lo que tenemos en https://datatracker.ietf.org/doc/html/rfc6838 para conocer más los posibles aceptados. Allá encontrarás categorías como:
- application
- audio
- image
- text
- video
- otros
Existe una negociación entre el cliente y el servidor para que entiendan lo que van a intercambiar de información tanto en el request como en el response. Es perfectamente posible enviar datos en un formato y recibir en otro.
No te atengas al ejemplo, solo ve que es posible.
paths:
/v1/createcustomer:
post:
summary: "Create a new customer"
requestBody:
content:
application/json: # Envío de datos en formato JSON
schema:
type: object
properties:
name:
type: string
email:
type: string
responses:
'200':
description: "Customer created successfully"
content:
application/yaml: # Respuesta en formato YAML
schema:
type: object
properties:
name:
type: string
email:
type: string

Generalmente esperamos que un schema sea objeto pues dentro de un objeto podemos la propiedad con varios parámetros posibilitando el crecimiento. Podríamos definir solamente como un tipo específico en vez de objeto (vamos a explorar más abajo), pero colocar esto dentro del objeto nos dará mayor margen para cambios. Usar siempre objects nos trae:
- Flexibilidad y Extensibilidad: Puedes agregar nuevas propiedades en el futuro sin romper la compatibilidad con consumidores existentes. Comienzas con un campo name y después agregas email, birthdate, etc., sin cambiar la estructura principal.
- Escalabilidad: Puedes organizar mejor datos complejos, agregando sub-objetos o arrays si es necesario.
- Claridad y Lectura: Un objeto es más intuitivo para desarrolladores, pues refleja mejor las estructuras del mundo real (entidades con atributos).
- Mantenimiento: Si un campo es removido o alterado, los consumidores pueden ajustar sus implementaciones de manera más predecible.
Tipos Primitivos
Vimos allá palabras como object y string. En el caso arriba tenemos uno de response del tipo objeto con los parámetros internos name del tipo string y email también del tipo string.
Podemos usar para declarar el type del propio schema, los types de las properties de los objetos, etc,
Podríamos esperar en un request solamente el número a pesar de lo que acabo de enseñar arriba sobre el uso de objetos.
application/json:
schema:
type: integer
example: 42 # El ejemplo funciona como parte de la documentación para ayudar a entender mejor el dato esperado.
La especificación OpenAPI ofrece muchas opciones para describir tus tipos, pero también muchas opciones para describirlos de forma suelta. Es una buena práctica elegir los tipos con precisión (usando los formatos definidos por OpenAPI) para mejorar la documentación, evitar ambigüedad para los usuarios finales y en caso de estar usando algún generador de código evitará problemas.
La especificación de OpenAPI acepta la mayoría de los datos primitivos que ya se usan en otros lenguajes que probablemente ya conoces.
string
Es un type bien flexible usado para representar muchas cosas.
- Puede ser usado para representar otros tipos
("true", "100", "{\\"some\\": \\"object\\"}"). - Soporta una serie de formatos que sobreponen restricciones al tipo de datos representados siendo útil para mapear a tipos en varios lenguajes.
- Muchos formatos pueden ser usados, como email, uuid, uri, hostname, ipv4, ipv6, etc. Una tabla con ejemplos:
| Type | Formato | Explicación | Ejemplo |
|---|---|---|---|
| string | date | Respetando las normas de la RFC3339 para formateo de date | "2022-01-30" |
| string | date-time | Respetando las normas de la RFC3339 para formateo de date-time | "2019-10-12T07:20:50.52Z" |
| string | password | Avisa que posee datos sensibles | "mySecretWord1234" |
| string | byte | Datos codificados en base64 | "U3BlYWtlYXN5IG1ha2VzIHdvcmtpbmcgd2l0aCBBUElzIGZ1biE=" |
| string | binary | Usado para representar secuencia binaria | "01010101110001" |
## Sin formateo, esperando una string simple
application/json:
schema:
type: string
example: "¡No tenemos ningún tipo de formato!"
## Con formateo, esperando una string con un date-time
application/json:
schema:
type: string
format: date
example: "2022-01-30"
El ejemplo ayudará al usuario a entender lo que se espera del campo.

Podemos utilizar expresiones regulares (regex) en una string para validar datos en vez de format. El format prácticamente son regex ya listos, pero en casos específicos usamos el pattern.
application/json:
schema:
type: string
pattern: ^[a-zA-Z0-9_]*$ # Acepta letras minúsculas, mayúsculas, números y _
Algunas validaciones pueden ser hechas usando string.
-minLength: Define el largo mínimo para una string -maxLength: Define el largo máximo para una string -enum: Especifica un conjunto de valores aceptados
integer/number
Un número puede ser de varios formatos así como una string. Definir el formato de un number es especificar lo que estamos esperando de aquel número.
Si vamos a trabajar con enteros usamos el tipo integer pudiendo variar cuánto ese número puede ser grande. Para eso definimos el formato de ese número para int32 o int64.
Lo mismo tenemos con el number. Si definimos un type number estamos esperando trabajar con números decimales (punto flotante) y no un número entero. Para eso especificamos que el formato debe ser float o double.
No es obligatorio definir el format para integer o number. La definición sirve para restricción. Definir un integer sin formato esperamos cualquier tamaño de número, int32 o int64 lo mismo valiendo para number, pudiendo recibir un float(32 bits) o un double (float con 64 bits).
- integer
- int32
- int64
- number
- float
- double
Se recomienda que seas explícito con el formato de tu tipo de número y siempre completes el atributo format.
Algunas validaciones pueden ser hechas sobre esos valores.
- minimum
- maximum
- exclusiveMinimum
- exclusiveMaximum
- multipleOf
schema:
type: integer
format: int32
# El valor debe ser mayor o igual al número especificado.
minimum: 10 # 10 es permitido o sea es el <=
example: 15
schema:
type: integer
format: int32
# El valor debe ser mayor o igual al número especificado.
minimum: 10 # 10 NO es permitido pues exclusive exclusiveMinimum es true remover el =, siendo permitido solamente > (mayor)
exclusiveMinimum: true
example: 15
schema:
type: number
format: float
# Esperamos valores entre 0 y 1. 0.89 pasa, 1.2 no pasa.
minimum: 0
maximum: 1 # Definiendo un número máximo
schema:
type: number
format: double
# Menor que 100, No pudiendo ser igual.
maximum: 100
exclusiveMaximum: true
schema:
type: integer
format: int64
multipleOf: 5
boolean
Es el de siempre, solo permite true o false no aceptando cero o uno.
schema:
type: boolean
# default puede ser usado para cualquier tipo en caso de no ser proporcionado el valor ese será asumido.
default: false
array
Un array es una lista de cosas items del mismo tipo. Obligatoriamente necesitamos definir lo que será un item del array.
# array de string
schema:
type: array
items:
type: string
# array de objeto. Cada objeto del array tendrá un nombre y edad
schema:
type: array
items:
type: object
properties:
name:
type: string
age:
type: integer
También podemos hacer validaciones en los arrays.
- minItems:
- maxItems
- uniqueItems
schema:
type: array
items:
type: number
format: float
minItems: 1
schema:
type: array
items:
type: string
maxItems: 10
# Tiene que poseer exactamente 3 items.
schema:
type: array
items:
type: boolean
minItems: 3
maxItems: 3
# No acepta items duplicados en el array.
schema:
type: array
items:
type: string
uniqueItems: true
objects
Es el tipo de objeto más flexible. Permite diccionarios y objetos de forma libre, junto con una serie de atributos para controlar la validación.
Para resumir esto, un objeto puede contener otros objetos dentro (anidados), tipos simples, arrays, y cualquier otra cosa que quieras.
schema:
type: object
properties:
name:
type: string
age:
type: integer
format: int32
active:
type: boolean
address: # Objeto dentro del objeto
type: object
properties:
street:
type: string
city:
type: string
state:
type: string
country:
type: string
zip:
type: string
children: # Array dentro del objeto
type: array
items:
type: string
description: List of children's names
Estaríamos esperando algo así si fuera en json.
{
"name": "David Puziol",
"age": 30,
"active": true,
"address": {
"street": "123 Main St",
"city": "Vila Velha",
"state": "ES",
"county": "Brazil",
"zip": "62701"
},
"children": ["Marina", "Catarina"]
}
Claro que podríamos tener validaciones en cada uno de los campos de cada uno de los objetos y arrays lo que tornaría el ejemplo extenso.
Objetos con propiedades tienen acceso a algunos atributos adicionales que permiten que los objetos sean validados de varias maneras:
required
La clave required se usa para indicar qué propiedades de un objeto son obligatorias.
Esas propiedades deben ser incluidas en el objeto cuando enviados en una solicitud (en el caso de requestBody) o cuando esperado en una respuesta (en el caso de response).
Estamos diciendo que un objeto puede ser complejo suficiente pero no necesitamos recibir o enviar todos los campos.
Vamos a pensar que en un método POST para registrar un usuario necesitamos lo mínimo necesario será nombre y edad pero dirección también sería interesante en caso de ser pasado.
schema:
type: object
required:
- name
- age
properties:
name:
type: string
age:
type: integer
address: #(Opcional)
type: string
Ejemplo de uso: Definir un objeto donde el name y el age son propiedades obligatorias, mientras el address es opcional.
Podemos usar el required tanto en el request como en el response. En la entrada generalmente entendemos el motivo, pero en la respuesta es un poco más difícil. ¿No sería interesante devolver todos los campos siempre?
A veces no sabemos si el valor fue definido por el sistema o por el usuario anteriormente, principalmente si es un valor default. Otro detalle es que el rendimiento del sistema que podría ser afectado. No estamos aquí para juzgar lo que es o no mejor hacer, sino lo que es posible hacer.
readOnly (Una propiedad que solo está disponible en una respuesta)
Una propiedad que solo está disponible en una respuesta (response), es decir, no debe ser incluida en una solicitud (request).
Ejemplo de uso: Una propiedad como un ID que es generado en el servidor y no puede ser enviado por el cliente, pero es retornado en la respuesta.
schema:
type: object
properties:
id:
type: string
readOnly: true
name:
type: string
Generalmente esto se usa cuando hacemos reaprovechamiento de schemas haciendo reusabilidad de código. Creamos un schema que puede ser usado en el request y en el response al mismo tiempo pero tiene campos que son usados en uno y en otro.
Solo para ilustrar hasta llegar el momento correcto de aprender esto. Usamos una referencia para el schema.
#...
paths:
/users:
post:
summary: Crear un nuevo usuario
description: Crea un nuevo usuario y retorna el `id` generado por el sistema.
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/User'
responses:
'201':
description: Usuario creado con éxito
content:
application/json:
schema:
$ref: '#/components/schemas/User'
components:
schemas:
User:
type: object
properties:
id:
type: string
readOnly: true
description: ID generado automáticamente para el usuario
name:
type: string
description: Nombre del usuario
required:
- name
writeOnly (Una propiedad que solo está disponible en una solicitud)
Una propiedad que solo está disponible en una solicitud (request), es decir, no debe ser incluida en una response (Respuesta).
Ejemplo de uso: Contraseñas u otras informaciones sensibles que no deben ser retornadas después del envío.
schema:
type: object
required:
- password
- email
properties:
password: #clave
type: string
writeOnly: true
email:
type: string
Los Objetos pueden ser usados para representar diccionarios o mapas, colecciones de clave valor. Las claves (keys) generalmente son del tipo string, y los valores (values) pueden ser de cualquier tipo que pueda ser descrito por la especificación OpenAPI, como string, integer, array, boolean, entre otros.
- Claves (keys): Son siempre del tipo string, es decir, el nombre de la clave es una string.
- Valores (values): Pueden ser de cualquier tipo que OpenAPI permita, como números, strings, arrays, objetos anidados, etc.
El tipo de objeto también puede ser usado para describir diccionarios/mapas/etc. que usan strings para claves y soportan cualquier tipo de valor que puede ser descrito por la especificación OpenAPI.
schema:
type: object
# Name existirá y aún será required
properties:
name:
type: string # Must match type of additionalProperties
required:
- name
# otros además de name pueden existir desde que sean strings
additionalProperties:
type: string
# AMBOS CASOS ABAJO PERMITIRÍA QUE FUERA CUALQUIER COSA.
# additionalProperties: true
# additionalProperties: {
minProperties: 1 # Avisa que tendrá otra propiedad además del name.
Otras validaciones pueden ser hechas, independiente de usar additionalProperties o no.
- minProperties: El número mínimo de propiedades permitidas en el objeto.
- maxProperties: El número máximo de propiedades permitidas en el objeto.
Enums
Se usa para definir un conjunto fijo de valores válidos, pero el cliente o sistema debe elegir solo uno de esos valores. En otras palabras: Enum es elección única cuando se usa solo, no múltiple.
Vamos directamente al ejemplo ya utilizando los components ir familiarizándose.
paths:
/v1/customers:
get:
responses:
200:
description: List of Customers
content:
application/json:
schema:
# Usado para ilustrar propiedades de string
maxItems: 100
minItems: 1
type: array
description: List of Customers
items: # aquí vamos a usar la referencia, sería lo mismo que hacer un include de todo aquí dentro.
$ref: '#/components/schemas/inline_response_200'
/v1/beers:
get:
responses:
200:
description: List of Beers
404:
description: No Beers Found
components:
schemas:
v1customers_address:
type: object
properties:
line1:
type: string
example: 123 main
city:
type: string
example: St Pete
stateCode:
# Una vez que fijamos los valores usando el enum esto sería redundante
# Definir el máximo y el mínimo podrían quedar por una cuestión informativa solamente.
maxLength: 2
minLength: 2
type: string
description: 2 Letter State Code
## Elección única como ejemplo
enum:
- AL
- AK
- AZ
- AR
- CA
zipCode:
type: string
example: "33701"
inline_response_200:
type: object
properties:
id:
type: string
format: uuid
firstName:
maxLength: 100
minLength: 2
type: string
example: John
lastName:
maxLength: 100
minLength: 2
type: string
example: Thompson
address:
$ref: '#/components/schemas/v1customers_address'
description: customer object
¿Cómo Simular Elección Múltiple en OpenAPI?
Si quieres permitir múltiples valores, puedes usar el tipo array combinado con enum para definir los valores válidos dentro del array:
type: array
items:
type: string
enum:
- red
- green
- blue
Comportamiento esperado:
Permite enviar un array conteniendo uno o más valores válidos.
- Valores válidos:
- ["red"]
- ["red", "green"] -["green", "blue"]
- Valores inválidos:
- ["red", "yellow"] (porque yellow no está en el enum)
- "red, green" (porque no es un array, sino una string única).