{"id":13174,"date":"2022-05-03T09:49:42","date_gmt":"2022-05-03T16:49:42","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=13174"},"modified":"2023-05-22T08:01:08","modified_gmt":"2023-05-22T15:01:08","slug":"couchbase-kotlin-api-released","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/es\/couchbase-kotlin-api-released\/","title":{"rendered":"Dise\u00f1o de la API Kotlin de Couchbase\u00a0"},"content":{"rendered":"<p><span style=\"font-weight: 400\">Me complace anunciar el lanzamiento de la versi\u00f3n 1.0 del SDK de Couchbase Kotlin. La verdad es que estoy encantado. Este proyecto ha sido un trabajo de amor. Despu\u00e9s de trabajar con Java durante d\u00e9cadas, tengo un nuevo lenguaje favorito.<\/span><\/p>\n<p><span style=\"font-weight: 400\">En este art\u00edculo, dir\u00e9 algunas cosas buenas sobre Kotlin, y luego mostrar\u00e9 c\u00f3mo usar el SDK de Couchbase Kotlin para conectarse a la base de datos como servicio de Capella. Finalmente, compartir\u00e9 algunas decisiones de dise\u00f1o que dieron forma a la API p\u00fablica del SDK. Espero que te quedes para esta \u00faltima parte, especialmente si est\u00e1s dise\u00f1ando la API de tu propia librer\u00eda Kotlin.<\/span><\/p>\n<h2><span style=\"font-weight: 400\">\u00bfPor qu\u00e9 Kotlin?<\/span><\/h2>\n<p><span style=\"font-weight: 400\">Kotlin cambi\u00f3 nuestra forma de pensar sobre la programaci\u00f3n as\u00edncrona en la JVM. Las coroutines y las funciones de suspensi\u00f3n de Kotlin son la prueba de que la programaci\u00f3n reactiva podr\u00eda ser un pelda\u00f1o hacia algo mejor, algo que no requiera sacrificar c\u00f3digo legible en el altar de la escalabilidad. Kotlin ha demostrado que hay una forma mejor de escribir c\u00f3digo as\u00edncrono de alto rendimiento, y no necesitamos esperar a las fibras y continuaciones del Proyecto Loom.<\/span><\/p>\n<h2><span style=\"font-weight: 400\">Capella + Kotlin<\/span><\/h2>\n<p><a href=\"https:\/\/cloud.couchbase.com\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400\">Couchbase Capella<\/span><\/a><span style=\"font-weight: 400\"> es la base de datos como servicio (DBaaS) para Couchbase Server. Es una tecnolog\u00eda s\u00f3lida, y cuando me registr\u00e9 para una prueba gratuita hace unas semanas, el proceso fue completamente indoloro.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Digamos que usted tiene un cluster de prueba Capella y ha a\u00f1adido su IP a la lista de permitidos, y ha creado un usuario de base de datos que puede leer el pre-instalado <em>viaje-muestra<\/em> cubo. A continuaci\u00f3n te explicamos c\u00f3mo conectarte a tu cl\u00faster utilizando el SDK de Kotlin:\u00a0<\/span><\/p>\n<pre class=\"decode-attributes:false lang:kotlin decode:true\"> \u00a0\u00a0\u00a0val address = \"--your-cluster--.cloud.couchbase.com\"\r\n\u00a0\u00a0\u00a0\u00a0val cluster = Cluster.connect(\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0connectionString = \"couchbases:\/\/$address\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0username = \"harpo\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0password = \"swordfish\",\r\n\u00a0\u00a0\u00a0\u00a0)<\/pre>\n<p><span style=\"font-weight: 400\">Una vez que tenga un objeto Cluster, puede ejecutar una consulta N1QL:<\/span><\/p>\n<pre class=\"decode-attributes:false lang:kotlin decode:true\"> \u00a0\u00a0\u00a0val queryResult = cluster\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.query(\"SELECT * FROM `travel-sample` LIMIT 3\")\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.execute()\r\n\u00a0\u00a0\u00a0\u00a0queryResult.rows.forEach { println(it) }\r\n\u00a0\u00a0\u00a0\u00a0println(queryResult.metadata)<\/pre>\n<p><span style=\"font-weight: 400\">O consiga una referencia a una Colecci\u00f3n y lea un documento espec\u00edfico:<\/span><\/p>\n<pre class=\"decode-attributes:false lang:kotlin decode:true\"> \u00a0\u00a0\u00a0val collection = cluster\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.bucket(\"travel-sample\")\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.defaultCollection()\r\n\r\n\u00a0\u00a0\u00a0\u00a0val getResult = collection.get(\"airline_10\")\r\n\u00a0\u00a0\u00a0\u00a0println(getResult)\r\n\u00a0\u00a0\u00a0\u00a0println(getResult.contentAs&lt;Map&lt;String, Any?&gt;&gt;())<\/pre>\n<p><span style=\"font-weight: 400\">La versi\u00f3n completa de este ejemplo se incluye en el archivo <\/span><a href=\"https:\/\/docs.couchbase.com\/kotlin-sdk\/current\/hello-world\/overview.html\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400\">Documentaci\u00f3n del SDK de Kotlin<\/span><\/a><span style=\"font-weight: 400\">junto con varios otros.<\/span><\/p>\n<h2><span style=\"font-weight: 400\">Decisiones de dise\u00f1o de la API del SDK<\/span><\/h2>\n<p><span style=\"font-weight: 400\">El resto de este art\u00edculo est\u00e1 dedicado a compartir algunas notas sobre las decisiones que tomamos al dise\u00f1ar la API p\u00fablica del SDK Kotlin de Couchbase. En algunos casos, comparar\u00e9 el SDK de Kotlin con su hermano mayor, el SDK de Java.<\/span><\/p>\n<h3><span style=\"font-weight: 400\">Extensi\u00f3n frente a SDK independiente<\/span><\/h3>\n<p><span style=\"font-weight: 400\">El SDK de Couchbase Kotlin depende del mismo <em>core-io<\/em> como el SDK de Java, pero no depende de \u00e9ste.<\/span><\/p>\n<h4><span style=\"font-weight: 400\">Alternativas rechazadas<\/span><\/h4>\n<p><span style=\"font-weight: 400\">Nos planteamos dar soporte a Kotlin proporcionando funciones de extensi\u00f3n para las clases del SDK de Java. Por desgracia, algunas decisiones de dise\u00f1o que tomamos para el SDK de Java no se trasladaron bien a Kotlin y no se pudieron compensar solo con funciones de extensi\u00f3n.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Tambi\u00e9n consideramos la posibilidad de proporcionar una envoltura nativa completa de la API de Kotlin que simplemente delegara en el SDK de Java, pero nos preocupaba que tener dos versiones de todas las clases (una para Kotlin y otra para Java) resultara confuso para los usuarios.<\/span><\/p>\n<h3><span style=\"font-weight: 400\">\u00a1Suspender o reventar!<\/span><\/h3>\n<p><span style=\"font-weight: 400\">El SDK de Kotlin no proporciona una API de bloqueo; los m\u00e9todos que realizan E\/S de red son todos <em>suspender<\/em> funciones.<\/span><\/p>\n<h4><span style=\"font-weight: 400\">Alternativas rechazadas<\/span><\/h4>\n<p><span style=\"font-weight: 400\">Consideramos la posibilidad de a\u00f1adir variantes \"bloqueantes\" de Cluster, Bucket, Scope, Collection, etc., pero parece algo que los usuarios pueden hacer por s\u00ed mismos con muy poco esfuerzo, simplemente envolviendo las llamadas a las funciones de suspensi\u00f3n con <em>runBlocking<\/em>.<\/span><\/p>\n<h3><span style=\"font-weight: 400\">Par\u00e1metros opcionales<\/span><\/h3>\n<p><span style=\"font-weight: 400\">Como Java no tiene par\u00e1metros opcionales, el SDK Java de Couchbase los emula con un \"bloque de opciones\" construido usando el patr\u00f3n constructor.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400\">En el siguiente ejemplo, <em>withExpiry<\/em>\u00a0es un par\u00e1metro booleano opcional cuyo valor por defecto es false. Los fragmentos de c\u00f3digo muestran un sitio de llamada en el que el desarrollador desea pasar true en su lugar.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Java:<\/span><\/p>\n<pre class=\"decode-attributes:false lang:java decode:true\"> \u00a0\u00a0\u00a0GetOptions options = GetOptions.getOptions().withExpiry(true);\r\n\u00a0\u00a0\u00a0\u00a0collection.get(documentId, options);<\/pre>\n<p><span style=\"font-weight: 400\">El SDK de Kotlin aprovecha el soporte nativo de Kotlin para par\u00e1metros por defecto:<\/span><\/p>\n<p><span style=\"font-weight: 400\">Kotlin:<\/span><\/p>\n<pre class=\"decode-attributes:false lang:kotlin decode:true\">\u00a0\u00a0\u00a0\u00a0collection.get(documentId, withExpiry = true)<\/pre>\n<h4><span style=\"font-weight: 400\">Alternativas rechazadas<\/span><\/h4>\n<p><span style=\"font-weight: 400\">Tambi\u00e9n consideramos la posibilidad de utilizar bloques de opciones espec\u00edficos de m\u00e9todo para Kotlin, que habr\u00edan tenido un aspecto similar:<\/span><\/p>\n<pre class=\"decode-attributes:false lang:kotlin decode:true\">\u00a0\u00a0\u00a0\u00a0collection.get(documentId, GetOptions(withExpiry = true))<\/pre>\n<p><span style=\"font-weight: 400\">Se rechaz\u00f3 porque era engorroso para los usuarios y dif\u00edcil de mantener para los desarrolladores del SDK (considere el impacto de a\u00f1adir una nueva opci\u00f3n com\u00fan a todos los m\u00e9todos).<\/span><\/p>\n<p><span style=\"font-weight: 400\">Tambi\u00e9n consideramos la posibilidad de utilizar un lambda\/mini-DSL para las opciones, que habr\u00eda sido algo as\u00ed:<\/span><\/p>\n<pre class=\"decode-attributes:false lang:kotlin decode:true\"> \u00a0\u00a0\u00a0collection.get(documentId) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0withExpiry = true\r\n\u00a0\u00a0\u00a0\u00a0}<\/pre>\n<p><span style=\"font-weight: 400\">Esta era la m\u00e1s tentadora de las alternativas rechazadas porque habr\u00eda sido excelente para la compatibilidad binaria (las firmas de los m\u00e9todos no cambiar\u00edan al a\u00f1adir nuevos par\u00e1metros opcionales). Tambi\u00e9n \"se siente como Kotlin\". Fue rechazada porque:<\/span><\/p>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">La finalizaci\u00f3n de c\u00f3digo IDE no ofrec\u00eda el mismo nivel de orientaci\u00f3n para los DSL que para los par\u00e1metros de m\u00e9todo (aunque es probable que los IDE mejoren con el tiempo).<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Quer\u00edamos reservar el \u00faltimo par\u00e1metro lambda para otros fines.<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h3><span style=\"font-weight: 400\">Par\u00e1metros comunes<\/span><\/h3>\n<p><span style=\"font-weight: 400\">Algunos par\u00e1metros opcionales son comunes a muchos m\u00e9todos de la API del SDK de Couchbase. Algunos ejemplos son la duraci\u00f3n del tiempo de espera, la estrategia de reintento y el intervalo de rastreo.<\/span><\/p>\n<p><span style=\"font-weight: 400\">En Java, estas opciones comunes son propiedades de una clase base CommonOptions a la que extienden todos los bloques de opciones espec\u00edficos de los m\u00e9todos; para el usuario, no se ven diferentes de otros par\u00e1metros:<\/span><\/p>\n<p><span style=\"font-weight: 400\">Java:<\/span><\/p>\n<pre class=\"lang:java decode:true\">   GetOptions options = GetOptions.getOptions()\r\n        .withExpiry(true)\r\n        .timeout(Duration.ofSeconds(10));\r\n    collection.get(documentId, options);<\/pre>\n<p><span style=\"font-weight: 400\">En Kotlin, adoptamos un enfoque diferente que equilibra la comodidad de los par\u00e1metros por defecto con algunas concesiones pragm\u00e1ticas para la mantenibilidad y la compatibilidad binaria. Los par\u00e1metros comunes est\u00e1n representados por un bloque de opciones llamado <em>CommonOptions<\/em>. Los m\u00e9todos aceptan un par\u00e1metro opcional cuyo valor por defecto es un <em>CommonOptions<\/em> que representa las opciones por defecto. Anular las opciones predeterminadas tiene el siguiente aspecto:<\/span><\/p>\n<p><span style=\"font-weight: 400\">Kotlin:<\/span><\/p>\n<pre class=\"decode-attributes:false lang:kotlin decode:true\"> \u00a0\u00a0\u00a0collection.get(\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0documentId,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0common = CommonOptions(timeout = 10.seconds),\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0withExpiry = true,\r\n\u00a0\u00a0\u00a0\u00a0)<\/pre>\n<h4>Alternativas rechazadas<\/h4>\n<p><span style=\"font-weight: 400\">Hemos considerado tratar las opciones comunes como par\u00e1metros normales, as\u00ed:<\/span><\/p>\n<pre class=\"decode-attributes:false lang:kotlin decode:true\"> \u00a0\u00a0\u00a0collection.get(\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0documentId,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0timeout = 10.seconds,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0withExpiry = true,\r\n\u00a0\u00a0\u00a0\u00a0)<\/pre>\n<p><span style=\"font-weight: 400\">Aunque esto ser\u00eda agradable para los usuarios, se rechaz\u00f3 porque a\u00f1adir o eliminar un par\u00e1metro com\u00fan requerir\u00eda cambiar la firma de casi todos los m\u00e9todos p\u00fablicos de la base de c\u00f3digo, lo que har\u00eda que mantener la compatibilidad binaria fuera una tarea ardua. Estudiamos la posibilidad de automatizar este proceso mediante la generaci\u00f3n de c\u00f3digo, pero la complejidad de este enfoque parec\u00eda superar su valor.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Al final, optamos por utilizar el <em>CommonOptions<\/em> como una especie de mamparo de la API para aislar los problemas de mantenimiento relacionados con las opciones comunes.<\/span><\/p>\n<h3><span style=\"font-weight: 400\">Compatibilidad binaria<\/span><\/h3>\n<p><span style=\"font-weight: 400\">Estas decisiones sobre los par\u00e1metros comunes y opcionales tienen las siguientes implicaciones para la compatibilidad binaria:<\/span><\/p>\n<p style=\"padding-left: 40px\"><span style=\"font-weight: 400\">A\u00f1adir un par\u00e1metro opcional a un m\u00e9todo rompe la compatibilidad binaria s\u00f3lo para ese m\u00e9todo. La compatibilidad puede restaurarse a\u00f1adiendo un m\u00e9todo con la firma antigua, anotado como <em>Deprecated(level=HIDDEN)<\/em>. El resultado es que el impacto del mantenimiento se a\u00edsla en un \u00fanico m\u00e9todo, y los cambios en el c\u00f3digo para mantener la compatibilidad tienen un alcance igualmente restringido.<\/span><\/p>\n<p style=\"padding-left: 40px\"><span style=\"font-weight: 400\">La adici\u00f3n de un par\u00e1metro com\u00fan rompe la compatibilidad binaria s\u00f3lo para el <em>CommonOptions<\/em> clase. La compatibilidad puede restaurarse a\u00f1adiendo un constructor con la firma antigua, anotado como <em>Deprecated(level=HIDDEN)<\/em>. Significativamente, no tenemos que cambiar la firma de los m\u00e9todos que toman <em>CommonOptions<\/em> como par\u00e1metro.<\/span><\/p>\n<h3><span style=\"font-weight: 400\">Par\u00e1metros mutuamente excluyentes<\/span><\/h3>\n<p><span style=\"font-weight: 400\">A veces, un m\u00e9todo puede tener dos formas distintas de especificar el valor de un par\u00e1metro. Por ejemplo, varios m\u00e9todos toman un <em>caducidad<\/em>\u00a0que puede especificarse como <em>Duraci\u00f3n<\/em> o un <em>Instant\u00e1nea<\/em>. En la API de Java, nada te impide escribir este c\u00f3digo:<\/span><\/p>\n<pre class=\"decode-attributes:false lang:kotlin decode:true\"> \u00a0\u00a0\u00a0UpsertOptions options = UpsertOptions.upsertOptions()\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.expiry(Instant.now().plus(Duration.ofMinutes(15)))\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.expiry(Duration.ofMinutes(10));\r\n\u00a0\u00a0\u00a0\u00a0collection.upsert(\"foo\", \"bar\", options);<\/pre>\n<p><span style=\"font-weight: 400\">Estas dos formas de especificar la caducidad son mutuamente excluyentes, pero Java le permite escribir el c\u00f3digo de todos modos. Si hay una comprobaci\u00f3n de validez, tiene que ocurrir en tiempo de ejecuci\u00f3n. (En este ejemplo concreto, la segunda llamada a <em>caducidad<\/em>\u00a0borra el valor establecido por la llamada anterior).<\/span><\/p>\n<p><span style=\"font-weight: 400\">En Kotlin el m\u00e9todo upsert tiene un \u00fanico par\u00e1metro de caducidad de tipo <em>Caducidad<\/em>donde <em>Caducidad<\/em>\u00a0es una clase sellada:<\/span><\/p>\n<pre class=\"decode-attributes:false lang:kotlin decode:true\">\u00a0\u00a0\u00a0\u00a0collection.upsert(\"foo\", \"bar\", expiry = Expiry.of(10.minutes))<\/pre>\n<p><span style=\"font-weight: 400\">o<\/span><\/p>\n<pre class=\"decode-attributes:false lang:kotlin decode:true\"> \u00a0\u00a0\u00a0val instant = Instant.now().plus(Duration.ofMinutes(15))\r\n\u00a0\u00a0\u00a0\u00a0collection.upsert(\"foo\", \"bar\", expiry = Expiry.of(instant))<\/pre>\n<p><span style=\"font-weight: 400\">Este patr\u00f3n se aplica en toda la API; las opciones mutuamente excluyentes siempre se representan como un \u00fanico par\u00e1metro que toma una instancia de una clase sellada cuyas instancias representan las diferentes formas de especificar el valor.<\/span><\/p>\n<h3><span style=\"font-weight: 400\">Resultados del streaming<\/span><\/h3>\n<p><span style=\"font-weight: 400\">Los servicios Couchbase Query, Analytics, View y Full-Text Search pueden devolver conjuntos de resultados muy grandes. Con el fin de procesar estos resultados de manera eficiente sin agotar el mont\u00f3n, los m\u00e9todos de consulta para estos servicios devuelven sus resultados como un flujo Kotlin.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Ofrecemos dos <em>ejecutar<\/em> en este flujo. Uno de los m\u00e9todos almacena las filas de resultados en memoria antes de devolver el conjunto de resultados completo (s\u00f3lo se utiliza cuando se sabe que el conjunto de resultados es peque\u00f1o). El otro m\u00e9todo permite al usuario proporcionar una lambda para aplicar a cada fila de resultados a medida que se recibe del servidor. Ambas versiones aprovechan el control de contrapresi\u00f3n\/flujo proporcionado por la biblioteca core-io.<\/span><\/p>\n<h4><span style=\"font-weight: 400\">Alternativas rechazadas<\/span><\/h4>\n<p><span style=\"font-weight: 400\">Consideramos la posibilidad de exponer los objetos del Proyecto Reactor Flux\/Mono utilizados por el <em>core-io<\/em> pero hemos decidido que despu\u00e9s de probar las coroutines no echamos de menos Reactor en absoluto, y creemos que la mayor\u00eda de los usuarios opinar\u00e1n lo mismo.<\/span><\/p>\n<h3><span style=\"font-weight: 400\">DSL frente a constructor jer\u00e1rquico<\/span><\/h3>\n<p><span style=\"font-weight: 400\">Los SDKs de Couchbase tienen muchas opciones de configuraci\u00f3n agrupadas en categor\u00edas separadas. Para los SDKs de JVM, estas opciones son propiedades del m\u00f3dulo <em>ClusterEnvironment<\/em>. En Java, estas opciones se configuran mediante una directiva <em>ClusterEnvironment<\/em> constructor. He aqu\u00ed un ejemplo en Java que desactiva la compresi\u00f3n, DNS SRV y el interruptor de servicio Key\/Value:<\/span><\/p>\n<pre class=\"decode-attributes:false lang:kotlin decode:true\"> \u00a0\u00a0\u00a0ClusterEnvironment env = ClusterEnvironment.builder()\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.ioConfig(IoConfig\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.enableDnsSrv(false)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.kvCircuitBreakerConfig(CircuitBreakerConfig\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.enabled(false)))\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.compressionConfig(CompressionConfig\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.enable(false))\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.build();<\/pre>\n<p><span style=\"font-weight: 400\">La API de Kotlin aprovecha el soporte DSL de Kotlin, permitiendo expresar la misma configuraci\u00f3n como:<\/span><\/p>\n<pre class=\"decode-attributes:false lang:kotlin decode:true\"> \u00a0\u00a0\u00a0val env = ClusterEnvironment.builder {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0io {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0enableDnsSrv = false\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0kvCircuitBreaker { enabled = false }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0compression { enable = false }\r\n\u00a0\u00a0\u00a0\u00a0}<\/pre>\n<p><span style=\"font-weight: 400\">La API de Kotlin tambi\u00e9n permite configurar el entorno en l\u00ednea con el m\u00e9todo connect:<\/span><\/p>\n<pre class=\"decode-attributes:false lang:kotlin decode:true\"> \u00a0\u00a0\u00a0val cluster = Cluster.connect(host, username, password) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0io {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0enableDnsSrv = false\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0}<\/pre>\n<p><span style=\"font-weight: 400\">Los usuarios que prefieran el constructor de entornos de cl\u00faster tradicional al DSL pueden seguir utilizando el constructor si lo desean.<\/span><\/p>\n<h4><span style=\"font-weight: 400\">Alternativas rechazadas<\/span><\/h4>\n<p><span style=\"font-weight: 400\">Tambi\u00e9n podr\u00edamos haber utilizado clases de datos en lugar de un DSL:<\/span><\/p>\n<pre class=\"decode-attributes:false lang:kotlin decode:true\"> \u00a0\u00a0\u00a0val env = ClusterEnvironment(\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0io = IoConfig(\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0enableDnsSrv = false,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0kvCircuitBreaker = CircuitBreakerConfig(enabled = false),\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0),\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0compression = CompressionConfig(enable = false),\r\n\u00a0\u00a0\u00a0\u00a0)<\/pre>\n<p><span style=\"font-weight: 400\">Eso habr\u00eda estado bien, pero el DSL es m\u00e1s conciso y da la sensaci\u00f3n de que estamos jugando con los puntos fuertes de Kotlin.<\/span><\/p>\n<h2><span style=\"font-weight: 400\">Resumen<\/span><\/h2>\n<p><span style=\"font-weight: 400\">Hemos puesto mucho cuidado en el dise\u00f1o de la API p\u00fablica del SDK Kotlin de Couchbase. No puedo prometer que lo hayamos hecho todo bien, pero espero que el resultado se sienta como algo que respeta los modismos y las mejores pr\u00e1cticas de Kotlin.<\/span><\/p>\n<p><span style=\"font-weight: 400\">El SDK de Couchbase Kotlin est\u00e1 finalmente listo para su uso en producci\u00f3n, ya sea que est\u00e9 utilizando el Capella DBaaS o la gesti\u00f3n de su propio cl\u00faster de Couchbase Server. Todo lo que no est\u00e9 anotado como <em>vol\u00e1til<\/em> o <em>no comprometido<\/em> ya forma parte oficialmente de la API p\u00fablica estable. Un enorme <strong>Gracias.<\/strong>\u00a0a todos los miembros de la comunidad que nos han hecho llegar sus comentarios.<\/span><\/p>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li><span style=\"font-weight: 400\">M\u00e1s informaci\u00f3n en <a href=\"https:\/\/docs.couchbase.com\/kotlin-sdk\/current\/hello-world\/overview.html\" target=\"_blank\" rel=\"noopener\">Documentaci\u00f3n de Couchbase Kotlin SDK<\/a>.<\/span><\/li>\n<li><span style=\"font-weight: 400\">\u00bfTiene alguna pregunta o comentario? Encu\u00e9ntrenos en el:<\/span>\n<ul>\n<li><span style=\"font-weight: 400\">el <\/span><a href=\"https:\/\/www.couchbase.com\/blog\/es\/forums\/c\/kotlin-sdk\/40\/\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400\">Foro Couchbase<\/span><\/a><\/li>\n<li><span style=\"font-weight: 400\">el <\/span><a href=\"https:\/\/www.couchbase.com\/blog\/es\/couchbase-on-discord\/\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400\">Servidor Couchbase Discord<\/span><\/a><span style=\"font-weight: 400\">o<\/span><\/li>\n<li><span style=\"font-weight: 400\">el canal #couchbase en el <\/span><a href=\"https:\/\/kotlinlang.org\/community\/\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400\">Espacio de trabajo Slack de Kotlin<\/span><\/a><span style=\"font-weight: 400\">.<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>","protected":false},"excerpt":{"rendered":"<p>I\u2019m pleased to announce the GA release of Couchbase Kotlin SDK version 1.0. In truth, I\u2019m over the moon. This project has been a labor of love. After working with Java for decades, I have a new favorite language. In [&hellip;]<\/p>","protected":false},"author":14341,"featured_media":13175,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1814,1816,9593,2201],"tags":[9337,1439,1349],"ppma_author":[9070],"class_list":["post-13174","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-application-design","category-couchbase-server","category-kotlin","category-tools-sdks","tag-application-development","tag-asynchronous","tag-development"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.0 (Yoast SEO v26.0) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Designing the Couchbase Kotlin API\u00a0 - The Couchbase Blog<\/title>\n<meta name=\"description\" content=\"The Couchbase Kotlin SDK is ready to use in production, whether you\u2019re using the Capella DBaaS or managing your own Couchbase Server cluster.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/es\/couchbase-kotlin-api-released\/\" \/>\n<meta property=\"og:locale\" content=\"es_MX\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Designing the Couchbase Kotlin API\u00a0\" \/>\n<meta property=\"og:description\" content=\"The Couchbase Kotlin SDK is ready to use in production, whether you\u2019re using the Capella DBaaS or managing your own Couchbase Server cluster.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/es\/couchbase-kotlin-api-released\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:author\" content=\"https:\/\/duckduckgo.com\/?q=delete+facebook\" \/>\n<meta property=\"article:published_time\" content=\"2022-05-03T16:49:42+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-05-22T15:01:08+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2022\/05\/kotlin-sdk-couchbase-released-scaled.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"2560\" \/>\n\t<meta property=\"og:image:height\" content=\"1707\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"David Nault\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@orzobat\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"David Nault\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-kotlin-api-released\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-kotlin-api-released\/\"},\"author\":{\"name\":\"David Nault\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/ec7e18bcee3337b77367560e6aeb75ef\"},\"headline\":\"Designing the Couchbase Kotlin API\u00a0\",\"datePublished\":\"2022-05-03T16:49:42+00:00\",\"dateModified\":\"2023-05-22T15:01:08+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-kotlin-api-released\/\"},\"wordCount\":1624,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-kotlin-api-released\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/05\/kotlin-sdk-couchbase-released-scaled.jpg\",\"keywords\":[\"application development\",\"asynchronous\",\"Development\"],\"articleSection\":[\"Application Design\",\"Couchbase Server\",\"Kotlin\",\"Tools &amp; SDKs\"],\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/couchbase-kotlin-api-released\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-kotlin-api-released\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/couchbase-kotlin-api-released\/\",\"name\":\"Designing the Couchbase Kotlin API\u00a0 - The Couchbase Blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-kotlin-api-released\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-kotlin-api-released\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/05\/kotlin-sdk-couchbase-released-scaled.jpg\",\"datePublished\":\"2022-05-03T16:49:42+00:00\",\"dateModified\":\"2023-05-22T15:01:08+00:00\",\"description\":\"The Couchbase Kotlin SDK is ready to use in production, whether you\u2019re using the Capella DBaaS or managing your own Couchbase Server cluster.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-kotlin-api-released\/#breadcrumb\"},\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/couchbase-kotlin-api-released\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-kotlin-api-released\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/05\/kotlin-sdk-couchbase-released-scaled.jpg\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/05\/kotlin-sdk-couchbase-released-scaled.jpg\",\"width\":2560,\"height\":1707,\"caption\":\"Designing a Kotlin SDK for Couchbase\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-kotlin-api-released\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Designing the Couchbase Kotlin API\u00a0\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"es\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/ec7e18bcee3337b77367560e6aeb75ef\",\"name\":\"David Nault\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/fbceda752a7ba278f83b24641d607212\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/9be1cd3e3c55df4d11b191172d382965de29da3a98d341167b33a8ad00546057?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/9be1cd3e3c55df4d11b191172d382965de29da3a98d341167b33a8ad00546057?s=96&d=mm&r=g\",\"caption\":\"David Nault\"},\"description\":\"David Nault is a Database Connector Developer for Couchbase. He spent the greater part of two decades writing back end web services in Java, and thinks JSON-RPC is really cool. He lives in California.\",\"sameAs\":[\"https:\/\/github.com\/dnault\",\"https:\/\/duckduckgo.com\/?q=delete+facebook\",\"https:\/\/x.com\/orzobat\"],\"url\":\"https:\/\/www.couchbase.com\/blog\/es\/author\/dnault\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Designing the Couchbase Kotlin API\u00a0 - The Couchbase Blog","description":"El SDK de Couchbase Kotlin est\u00e1 listo para su uso en producci\u00f3n, tanto si utilizas Capella DBaaS como si gestionas tu propio cl\u00faster de Couchbase Server.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/es\/couchbase-kotlin-api-released\/","og_locale":"es_MX","og_type":"article","og_title":"Designing the Couchbase Kotlin API\u00a0","og_description":"The Couchbase Kotlin SDK is ready to use in production, whether you\u2019re using the Capella DBaaS or managing your own Couchbase Server cluster.","og_url":"https:\/\/www.couchbase.com\/blog\/es\/couchbase-kotlin-api-released\/","og_site_name":"The Couchbase Blog","article_author":"https:\/\/duckduckgo.com\/?q=delete+facebook","article_published_time":"2022-05-03T16:49:42+00:00","article_modified_time":"2023-05-22T15:01:08+00:00","og_image":[{"width":2560,"height":1707,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2022\/05\/kotlin-sdk-couchbase-released-scaled.jpg","type":"image\/jpeg"}],"author":"David Nault","twitter_card":"summary_large_image","twitter_creator":"@orzobat","twitter_misc":{"Written by":"David Nault","Est. reading time":"8 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/couchbase-kotlin-api-released\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-kotlin-api-released\/"},"author":{"name":"David Nault","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/ec7e18bcee3337b77367560e6aeb75ef"},"headline":"Designing the Couchbase Kotlin API\u00a0","datePublished":"2022-05-03T16:49:42+00:00","dateModified":"2023-05-22T15:01:08+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-kotlin-api-released\/"},"wordCount":1624,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-kotlin-api-released\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/05\/kotlin-sdk-couchbase-released-scaled.jpg","keywords":["application development","asynchronous","Development"],"articleSection":["Application Design","Couchbase Server","Kotlin","Tools &amp; SDKs"],"inLanguage":"es","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/couchbase-kotlin-api-released\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/couchbase-kotlin-api-released\/","url":"https:\/\/www.couchbase.com\/blog\/couchbase-kotlin-api-released\/","name":"Designing the Couchbase Kotlin API\u00a0 - The Couchbase Blog","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-kotlin-api-released\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-kotlin-api-released\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/05\/kotlin-sdk-couchbase-released-scaled.jpg","datePublished":"2022-05-03T16:49:42+00:00","dateModified":"2023-05-22T15:01:08+00:00","description":"El SDK de Couchbase Kotlin est\u00e1 listo para su uso en producci\u00f3n, tanto si utilizas Capella DBaaS como si gestionas tu propio cl\u00faster de Couchbase Server.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-kotlin-api-released\/#breadcrumb"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/couchbase-kotlin-api-released\/"]}]},{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/couchbase-kotlin-api-released\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/05\/kotlin-sdk-couchbase-released-scaled.jpg","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/05\/kotlin-sdk-couchbase-released-scaled.jpg","width":2560,"height":1707,"caption":"Designing a Kotlin SDK for Couchbase"},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/couchbase-kotlin-api-released\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Designing the Couchbase Kotlin API\u00a0"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"El blog de Couchbase","description":"Couchbase, la base de datos NoSQL","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"es"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"El blog de Couchbase","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/ec7e18bcee3337b77367560e6aeb75ef","name":"David Nault","image":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/fbceda752a7ba278f83b24641d607212","url":"https:\/\/secure.gravatar.com\/avatar\/9be1cd3e3c55df4d11b191172d382965de29da3a98d341167b33a8ad00546057?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/9be1cd3e3c55df4d11b191172d382965de29da3a98d341167b33a8ad00546057?s=96&d=mm&r=g","caption":"David Nault"},"description":"David Nault is a Database Connector Developer for Couchbase. He spent the greater part of two decades writing back end web services in Java, and thinks JSON-RPC is really cool. He lives in California.","sameAs":["https:\/\/github.com\/dnault","https:\/\/duckduckgo.com\/?q=delete+facebook","https:\/\/x.com\/orzobat"],"url":"https:\/\/www.couchbase.com\/blog\/es\/author\/dnault\/"}]}},"authors":[{"term_id":9070,"user_id":14341,"is_guest":0,"slug":"dnault","display_name":"David Nault","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/9be1cd3e3c55df4d11b191172d382965de29da3a98d341167b33a8ad00546057?s=96&d=mm&r=g","author_category":"","last_name":"Nault","first_name":"David","job_title":"","user_url":"https:\/\/github.com\/dnault","description":"David Nault escribe c\u00f3digo en Couchbase, donde trabaja en el equipo SDK &amp; Connectors."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/13174","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/users\/14341"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/comments?post=13174"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/13174\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/media\/13175"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/media?parent=13174"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/categories?post=13174"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/tags?post=13174"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/ppma_author?post=13174"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}