9. Escribir
Una escritura no es un INSERT ni un UPDATE directo. El servicio abre la transacción real del ERP, la misma que usa la pantalla del maestro: se ejecutan las reglas de negocio, los scripts y las validaciones configuradas. Por eso un 400 puede traer mensajes de negocio en vez de un error técnico, y por eso un campo que la pantalla no expone no se puede escribir por la API.
| Operación | Recurso | Respuesta |
|---|---|---|
POST | /o_customers | 201 con la entidad creada y el header Location. |
PATCH | /o_customers('C0001') | 200 con la entidad actualizada. |
PUT | /o_customers('C0001') | 200. Ver la advertencia de abajo. |
DELETE | /o_customers('C0001') | 204 sin cuerpo. |
curl -s -X POST -H "X-API-Key: TU_API_KEY" -H "Content-Type: application/json" \
-d '{"code":"C0999","name":"Nuevo Cliente SA","city_code":"ROS"}' \
'https://TU-HOST/synergy-server/jwt-odata-key/o_customers'
PUT se comporta igual que PATCH: no resetea los campos omitidos. La especificación de OData dice que PUT reemplaza la entidad completa y deja en su valor por defecto todo lo que no venga en el cuerpo. En esta implementación no: tanto PUT como PATCH asignan únicamente las propiedades presentes en el JSON y dejan el resto como estaba. Si tu cliente usa PUT esperando un reemplazo, no lo vas a obtener. Recomendación: usá PATCH y mandá siempre explícito lo que querés cambiar.
Preferencias de respuesta
| Header | Efecto |
|---|---|
| (sin header) | Por defecto devuelve la entidad: 201 en create, 200 en update. El cuerpo se relee de la base, así que refleja lo que dejaron las reglas del ERP. |
Prefer: return=minimal | 204 sin cuerpo, con la URL de la entidad en el header OData-EntityId. Más barato si no necesitás el resultado. |
Prefer: return=representation | Explicita el comportamiento por defecto. |
Errores de escritura
Las validaciones del ERP vuelven como 400 ValidationFailed con los mensajes en details:
{
"error": {
"code": "ValidationFailed",
"message": "Business rule validation failed",
"details": [
{ "code": "", "message": "El CUIT ingresado no es válido" },
{ "code": "", "message": "La localidad ROS no pertenece a la provincia indicada" }
]
}
}
Otros casos frecuentes:
| Causa | Respuesta |
|---|---|
| Una propiedad del JSON no existe en la entidad | 400 ValidationFailed nombrando la propiedad |
| La propiedad existe pero la pantalla del maestro no la expone | 400 ValidationFailed: is not writable through entity set |
| Cuerpo vacío o JSON mal formado | 400 EmptyPayload / 400 InvalidPayload |
| La operación no está habilitada para tu cliente | 405 con el header Allow indicando qué métodos sí |
PATCH / DELETE sin clave en la URL | 400 KeyRequired |
No hay control de concurrencia. El servicio no emite ETag y ignora If-Match: no vas a recibir un 412. Dos procesos que escriban la misma entidad se sobreescriben, gana el último. Si necesitás detectar conflictos, tiene que resolverse del lado del ERP con una regla de negocio.
Lo que no se puede escribir
- Deep insert — crear el padre y sus hijos en un solo POST:
501 DeepInsertNotSupported. Hay que hacer un POST por entidad. - Escribir por una navegación —
PATCH /o_customers('C0001')/Localidad:501. - Escribir una propiedad sola —
PATCH /o_customers('C0001')/name:501. Usá unPATCHsobre la entidad con ese único campo. - Vincular o desvincular con
$ref—501. Se hace asignando la columna de la FK con unPATCHnormal. $batch—501 BatchNotSupported. Las escrituras van de a una; cada una es su propia transacción.