Definí tus endpoints en un contrato
Dado un Usuario con la siguiente estructura:
{
"id": 1,
"name": "Leanne Graham",
"username": "Bret",
"email": "Sincere@april.biz",
"address": {
"street": "Kulas Light",
"suite": "Apt. 556",
"city": "Gwenborough",
"zipcode": "92998-3874",
"geo": {
"lat": "-37.3159",
"lng": "81.1496"
}
},
"phone": "1-770-736-8031 x56442",
"website": "hildegard.org",
"company": {
"name": "Romaguera-Crona",
"catchPhrase": "Multi-layered client-server neural-net",
"bs": "harness real-time e-markets"
},
"profilePictureUrl": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/1.png"
}
Queremos que nuestro backend exponga estos endpoints:
/users
lista todos los usuarios./users/{id}
obtiene un usuario por identificador.
OpenAPI specification
Una OpenAPI Specification cumple con la definición de contrato que di antes: Es un conjunto de afirmaciones que contiene valores de entrada válidos y su significado, valores de retorno válidos y su significado, y valores de error que pueden ocurrir y su significado.
Una OpenAPI Specification que representaría el comportamiento deseado se vería algo así:
openapi: 3.0.3
info:
title: users_manager API
description: An API for retrieving information from a users database.
version: 1.0.0
contact:
name: Pollito
url: https://pollito.dev
servers:
- url: 'http://localhost:8080'
description: dev
paths:
/users:
get:
tags:
- User
summary: List all users
operationId: findAll
responses:
'200':
description: List of all users
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/User'
default:
description: Error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/users/{id}:
get:
tags:
- User
summary: Get user by identifier
operationId: findById
parameters:
- description: User identifier
in: path
name: id
required: true
schema:
format: int64
type: integer
responses:
'200':
description: A user
content:
application/json:
schema:
$ref: '#/components/schemas/User'
default:
description: Error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
components:
schemas:
Address:
description: User address
properties:
city:
description: Address city
example: "Gwenborough"
type: string
geo:
$ref: '#/components/schemas/Geo'
street:
description: Address street
example: "Kulas Light"
type: string
suite:
description: Address suit
example: "Apt. 556"
type: string
zipcode:
description: Adress zipcode
example: "92998-3874"
type: string
type: object
Company:
description: User company
properties:
bs:
description: Company business
example: "harness real-time e-markets"
type: string
catchPhrase:
description: Company catch phrase
example: "Multi-layered client-server neural-net"
type: string
name:
description: Company name
example: "Romaguera-Crona"
type: string
type: object
Error:
properties:
detail:
description: Description of the problem.
example: No value present
type: string
instance:
description: The endpoint where the problem was encountered.
example: "/generate"
type: string
status:
description: http status code
example: 500
type: integer
title:
description: A short headline of the problem.
example: "NoSuchElementException"
type: string
timestamp:
description: ISO 8601 Date.
example: "2024-01-04T15:30:00Z"
type: string
trace:
description: opentelemetry TraceID, a unique identifier.
example: "0c6a41e22fe6478cc391908406ca9b8d"
type: string
type:
description: used to point the client to documentation where it is explained clearly what happened and why.
example: "about:blank"
type: string
type: object
Geo:
description: Address geolocation
properties:
lat:
description: Geolocation latitude
example: "-37.3159"
type: string
lng:
description: Geolocation longitude
example: "81.1496"
type: string
type: object
User:
properties:
address:
$ref: '#/components/schemas/Address'
company:
$ref: '#/components/schemas/Company'
email:
description: User email
example: "Sincere@april.biz"
type: string
id:
description: User id
example: 1
format: int64
type: integer
name:
description: User name
example: "Leanne Graham"
type: string
phone:
description: User phone
example: "1-770-736-8031 x56442"
type: string
profilePictureUrl:
description: User profile picture url
example: "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/1.png"
type: string
username:
description: User username
example: "Bret"
type: string
website:
description: User website
example: "hildegard.org"
type: string
Para una mejor visualización, podés copiar y pegar el archivo YAML en Swagger Editor o usar OpenAPI (Swagger) Editor en IntelliJ IDEA. Deberías poder ver algo así:

Rest y Restful
REST (Representational State Transfer) es un estilo arquitectónico definido por Roy Fielding, que enfatiza:
- Separación cliente-servidor.
- Ausencia de estado (Statelessness).
- Capacidad de caché (Cacheability).
- Sistema en capas (Layered system).
- Interfaz uniforme (recursos, representaciones).
- Código bajo demanda (Code-on-demand) (opcional).
Las API RESTful siguen estrictamente todas estas restricciones. Pero la realidad es esta: la mayoría de las API "REST" no son verdaderamente RESTful, y eso está bien.
Rest está bien
Las APIs verdaderamente RESTful requieren HATEOAS (Hypermedia as the Engine of Application State) — embeber links a recursos relacionados en las respuestas:
{
"id": 1,
"links": [
{ "rel": "self", "href": "/users/1" },
{ "rel": "orders", "href": "/users/1/orders" }
]
}
En la práctica, esto no sucede:
- Los equipos de frontend rara vez usan links embebidos.
- Agrega complejidad sin valor inmediato.
Un contrato OpenAPI ya te da el 80% de los beneficios de REST:
- URLs centradas en recursos (
/users/{id}
). - Métodos HTTP estándar (
GET
/POST
/PUT
/DELETE
). - Manejo claro de errores (códigos
4xx
/5xx
).
Por esas razones, vamos a construir APIs REST. A menos que estés construyendo sistemas impulsados por hipermedia, REST está bien. Enfocate en:
- Contratos consistentes.
- Manejo predecible de errores.
- Documentación que humanos y máquinas puedan usar.
A medida que tu API evolucione, podés agregar funcionalidades RESTful más adelante si es necesario.
Recurso de aprendizaje recomendado
Te recomiendo mucho el video de High-Performance Programming "Rest API - Best Practices - Design".