Creando un API REST en Java (parte 1)

Creando un API REST en Java (parte 1)

Sin lugar a duda, los servicios REST ya se han convertido en la principal tecnología para construir servicios, superando con creces a los servicios SOAP o comúnmente conocidos como Web Services. A pesar de que REST ya es visiblemente la tendencia en el desarrollo de servicios, sigue existiendo una gran discusión acerca de si SOAP es mejor que REST o al revés, sin embargo, no quiera tocar este tema ahora, pues no es el tema central de este artículo, para eso he creado el artículo “SOA vs REST” donde discutimos sobre estas dos tecnologías y sus ventajas y desventajas.

NOTA: Este artículo es parte de un tutorial completo para crear API REST con JAX-RS, si quieres ver el índice completo entra aquí.

Antes de comenzar, te cuento que puedes descargar el código completo en https://github.com/oscarjb1/blog-tutorial-jaxrs/tree/master/M%C3%A9todos%20HTTP/api

Configurando el proyecto

Dicho este, pasemos ahora si a implementar un API REST con Java, para esto, será indispensable crear un proyecto de tipo WEB en tu IDE favorito, en este caso, vamos a crear un “Dynamic web project” en Eclipse, para esto nos dirigimos a file -> new -> Other en el menú superior:

Seleccionamos la opción Dynamic web Project y presionamos Next para iniciar con la configuración de la aplicación:

Una vez aquí, escribimos “api” como nombre del proyecto y seleccionamos nuestro servidor de aplicaciones de preferencia, en nuestro caso, utilizamos Wildfly 11 pero podrías utilizar cualquier otro que tengas disponible. Finalmente, presionamos “Finish” para concluir con la creación del proyecto. El siguiente paso será convertir nuestro proyecto a un proyecto Maven, con la finalidad de administrar más fácilmente nuestras librerías. Para ello, nos posicionaremos sobre el proyecto creado y presionaremos “click derecho“ para abrir las opciones del proyecto, estando allí, nos dirigimos a configure -> convert to Maven Project, tras presionar esto, saldrá una ventana para configurar el proyecto, a lo que simplemente daremos finalizar.

Tras realizar los pasos anteriores deberás ver el proyecto tal y como se ve en la imagen anterior. Podrás observar una pequeña “M” en el ícono del proyecto, señal de que se trata de un proyecto Maven.

El siguiente paso es configurar las librerías de JavaEE y Wildfly con la finalidad de que estén disponibles en nuestro proyecto, por lo que tendremos que ir al archivo pom.xml y agregar las siguientes dos librerías:

<dependency> 
    <groupId>javax</groupId> 
    <artifactId>javaee-api</artifactId> 
    <version>7.0</version> 
    <scope>provided</scope> 
    <type>jar</type> 
</dependency> 
<dependency> 
    <groupId>org.wildfly.core</groupId> 
    <artifactId>wildfly-server</artifactId> 
    <version>2.2.0.Final</version> 
    <scope>provided</scope> 
</dependency>

Guardamos los cambios y tendremos que esperar un momento hasta que Eclipse descarga todas las dependencias necesarias, para esto, verás un indicador de progreso en la parte inferior derecha de Eclipse. Una vez que ha finalizado, estamos listos para empezar a desarrollar.

Iniciando el desarrollo

Lo primero que debemos de hacer para iniciar nuestra API REST es indicarle el Path base desde el cual estará respondiendo nuestra API. Este path corresponde a la URL a partir de la cual se expondrá nuestros servicios. Para lograr esto, será necesario crear una clase que extienda de “Application”, esta clase puede llamarse como sea y puede colocarse en cualquier paquete, lo único importante es que extienda de Application y defina la anotación @ApplicationPath. En nuestro caso crearemos la clase RestApplication en el package api.

package api; 

import javax.ws.rs.ApplicationPath; 
import javax.ws.rs.core.Application; 

@ApplicationPath("/") 
public class RestApplication extends Application { 
}

Como podemos ver, hemos definido “/” como URL base, es decir que los servicios responderán a partir de la raíz del proyecto, pero tu podrías remplazarla por la URL base que más te guste, como por ejemplo “/api” o “/services”.

El siguiente paso será crear nuestro primer servicio, para lo cual deberemos crear una nueva clase, en este caso, crearemos la clase HelloWorldRest en el mismo paquete:

package api; 
import javax.ws.rs.Consumes; 
import javax.ws.rs.GET; 
import javax.ws.rs.Path; 
import javax.ws.rs.Produces; 
import javax.ws.rs.core.MediaType; 
import javax.ws.rs.core.Response; 

@Path("/helloworld") 
@Produces(MediaType.APPLICATION_JSON) 
@Consumes(MediaType.APPLICATION_JSON) 
public class HelloWorldRest {               

    @GET  
    public Response sayHello() {     
        return Response.ok("Hello World desde el API REST",MediaType.APPLICATION_JSON).build();   
    } 
}

Como podrás observar, esta es una clase común y corriente pero que tiene algunas anotaciones, las cuales serán reconocidas por el servidor de aplicaciones para finalmente exponer el servicio, analicemos para que esta cada una de ellas.

La anotación @Path indica la URL en la cual responderá este servicio, cabe mencionar que esta anotación se puede poner a nivel de clase y método, en este caso, al estar a nivel de clase, afecta a todos los servicios que definamos, pero eso lo vamos a analizar más adelante.

Las siguientes dos anotaciones son para indicar que tipo de mensaje esperamos como entrada (consumes) y que tipo de mensaje vamos a responder (produces). En este caso, estamos indicando que esperamos JSON como entrada y que vamos a responder igualmente con JSON.

Finalmente, siguen los métodos, una clase puede tener más de un método, y cada método se puede exponer como un servicio independiente, sin embargo, en esta primera introducción empezaremos con uno. La anotación @GET le indica al servidor de aplicaciones que el método responde por el método GET únicamente. Adicional tenemos anotaciones para los demás métodos, como @POST, @PUT, @DELETE, etc. pero estos los estaremos analizando más adelante.

Podrás observar que el método responde con un tipo llamado Response, esta es una clase de utilidad que nos proporciona el API de JAX-RS para convertir fácilmente un objeto en un JSON en nuestro caso. Esta clase nos proporciona el método ok, el cual nos crea una respuesta con status 200, es decir, respuesta exitosa, la cual recibe el mensaje que queremos responder y el tipo de datos del mensaje, en nuestro caso JSON.

Probando nuestro Hello World

En este punto hemos terminado nuestro primer servicio, por lo que solo resta desplegarlo y probarlo. Para desplegarlo, basta con presionar el click derecho sobre el proyecto y presionar Run As -> Run on Server, presionar siguiente y finalizar.

Si la aplicación desplego correctamente, podremos probar el servicio en la URL http://localhost:8080/api-0.0.1-SNAPSHOT/helloworld, esta URL la podrás ejecutar directamente sobre el navegador:

En este punto te estarás preguntando como es que se generó esta URL, por lo que explico a continuación:

La URL se forma con la siguiente formula: <server_path>:<port>/<app_context>/<app_path>/<service_path>

La sección <server_path> y <port> corresponde al host del servidor y el puerto en el cual responde, esto corresponde a Wildfly.

La sección <app_context> corresponde a la URL base que nos asigna el servidor de aplicaciones cuando desplegamos.

La sección <app_path> fue la que definimos en la anotación @ApplicationPath. En nuestro caso, al definirla como “/” quiere decir que responderá a partir de la raíz del proyecto.

Finalmente, <service_path> corresponde a la URL definida en la anotación @Path, la cual se definió como “helloworld”.

Te invito a que veas mi curso Mastering API REST con Spring Boot

Conclusiones

Hasta este punto hemos aprendido a crear un proyecto web y configurarlo para que responda a nuestras solicitudes como un API REST, por lo que en la siguiente sección de esta guía aprenderemos a utilizar los demás métodos (POST, DELETE, PUT) y aprenderemos a configurar nuestras URL para responder a URL más complejas, por lo que te invito a que te suscribas a mi blog para hacerte llegar las actualizaciones.

60 thoughts to “Creando un API REST en Java (parte 1)”

  1. Esta bueno el artículo …, la gente debe analizar que en si los servicios web basados en SOAP y/ basados en REST, como parte de una arquitectura son buenos. Así mismo, diferenciar los enfoques que se tengan considerando el auge de los MicroServicios que en si son un tipo especial de servicios dentro de una arquitectura SOA, a nivel del inventario de servicios respectivamente.

    Como que me salí un poco del tema, jejeje el ejemplo está bien pero me hubiese gustado mejor verlo basado en un enfoque Topdown (definiendo tu contrato técnico apoyándote en: WADL, SWAGGER, RAML, etc), esto debido a que este enfoque es más mantenible a nivel de ambas partes: (Service Providers y Service Consumers), así la aplicación de estándares, principios, patrones y buenas practicas se pueden aplicar desde el Diseño respectivamente .

    Saludos Oscar.

    1. Lo que dices tiene sentido, desarrollar los servicios de Arriba abajo. En este articulo solo quise describir la forma de utilizar la tecnología, es por eso que no menciono nada de eso, pero me apunto el comentario para una segunda entrada.

      saludos.

  2. Que tal, estoy probando lo de las api y ya hice los pasos que muestras pero me aparece erro 404 probar la aplicacion..

    calse 1…….
    package prueba;

    import javax.ws.rs.ApplicationPath;
    import javax.ws.rs.core.Application;

    @ApplicationPath(“/”)
    public class HolaMundo extends Application {
    }

    Clase 2……
    package prueba;

    import javax.ws.rs.Consumes;
    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    import javax.ws.rs.Produces;
    import javax.ws.rs.core.MediaType;
    import javax.ws.rs.core.Response;

    @Path(“/hola”)
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    public class HolamundoRest {
    //@Path(“/hola”)
    @GET
    public Response sayHello() {
    return Response.ok(“Hello World desde el API REST”, MediaType.APPLICATION_JSON).build();
    }
    }

    esta es la direccion que me da eclipse al probar el servicio
    http://localhost:8080/prueba/

    y me imagino que debo agregarle hola
    http://localhost:8080/prueba/hola

    pero ya he visto todo y probado todo y aun no me funciona, podrias ayudarme??

    1. Hola Saul, la URL debe iniciar con el Context de la aplicación, el context es la URL que le antepone el servidor a cada aplicación desplegada, despues de eso, viene la url del servicio, por ejemplo

      http:localhost:8080//hola

          1. Hola Javi, en tal caso tendrías que relisar la documentación de Apache, para ver en que URL lo esta desplegando, en este ejemplo utilizamos Wildfly, por lo que si tu quieres utilizar otro app server, será necesario que busques su documentación.

        1. Hola, yo hice exactamente lo que comenta el tutorial pero a la hora de tratar de entrar a la url

          http://localhost:8080/CuentasWEB-0.0.1-SNAPSHOT/helloworld me manda el error de not found

          puse un index.html en el webcontent solo para asegurarme de que el contexto esta correcto… y si me muestra el contenido del index.html cuando entro a esta url http://localhost:8080/CuentasWEB-0.0.1-SNAPSHOT por lo que estoy seguro de que el server y el contexto estan publicados….. lo que no se esta publicando es el path @ApplicationPath(“/”) y mucho menos el @Path(“/helloworld”) … quiero suponer que es porque no le hemos especificado en ningún lado que esas clases existen en el proyecto…. no falta alguna configuración en donde se tenga que especificar esto?

          muchas gracias por tu tiempo… saludos… totales

  3. Hola Oscar,
    He descargado la aplicacion de git y aun asi obtengo un 404.

    Cual es la url que tengo que seleccionar, es decir, como la tengo que componer y de donde tengo que sacar los valores.

    Gracias

    1. Hola Cristina,

      Yo acabo de realizar una prueba y me respondió correctamente, lo probé sobre un Wildfly 11. Al momento de desplegar te indica cual es el context path de la aplicación, en este caso, la línea que nos interesa es la siguiente:
      23:14:50,116 INFO [org.wildfly.extension.undertow] (ServerService Thread Pool — 98) WFLYUT0021: Registered web context: '/api-0.0.1-SNAPSHOT' for server ‘default-server’

      Como puedes ver, la aplicación está sobre el context '/api-0.0.1-SNAPSHOT', dicho lo anterior, mi Wildfly está sobre el puerto 8080, asi que puede consumir si problemas el servicio de consulta de usuarios desde la URL http://localhost:8080/api-0.0.1-SNAPSHOT/users

      Espero que esto te sirva de algo para hacer funcionar la aplicación.

  4. Hola Oscar,

    Yo tampoco soy capaz de conseguir que se conecte a la url. He utilizado tu proyecto de git. Puedes explicar como se compone la url. de donde sacamos el context.

    Saludos,

  5. Hola Oscar,
    Estaba siguiendo tu tuto usando el servidor de Tomcat, pero me generaba el conocido error de 404, sin embargo decidí implementar JBoss como servidor and it works!
    (Tendré que darle otra revisada a la configuración de tomcat)
    Muchas gracias por el tuto!

    1. Hola Diana, el detalle es que cada servidor de aplicaciones publica las aplicaciones en diferentes context(path) lo que modifica la URL en la cual puedes ver el servicio, te recomiendo que prestes mucha atención en el log que genera el Tomcat al momento del deploy, seguramente allí te indica al context.

      saludos.

  6. Muchisimas gracias. Tú blog me ha sido de mucha ayuda para entender REST. Ánimo, sigue adelante… este tipo de material ayuda muchisimo a los que estamos iniciando. Además, explicas de manera muy precisa y correcta! Excelente contenido

  7. hola Oscar, he visto otros tutoriales sobre rest, y he visto como declaran en las dependencias el uso de jersey que entiendo es la implementacion de jax-rs , he visto que en tu turorial no es necesario , por lo que me surge la duda de cuando si es necesario declarar una implementacion como jersy.

    gracias de antemano!

    1. Hola Julio,
      Pongamos las cosas en el contexto adecuado, JAX-RS es un especificación, por lo tanto, por si solo no sirve, si no que requiere de una implementación, como lo son Jersey, RESTeasy, Restlet.
      Esto quiere decir que cualquier implementación que utilicemos debería de funcionar, pues todas implementan la especificación JAX-RS.

      Dicho lo anterior, procederé a responder tu pregunta, podrás ver que en el archivo pom.xml estoy importando javaee-api, esta librería contiene todo el estándar JEE, es decir, contiene las interfaces y anotaciones de JAX-RS pero sin una implementación funcional, esto quiere decir, que con esta librería yo puedo utilizar las anotaciones e interfaces de JAX-RS pero por si sola no funcionará. El segundo paso es importar la librería org.wildfly.core la cual contiene todas las librerías de Runtime de Wildfly, en esta segunda librería podría venir cualquier implementación de JAX-RS, como lo es Jersy, sin embargo, no me interesa saber cual contiene, por que yo solo utilizo las anotaciones e interfaces estandares de JAX-RS contenidas en javaee-api. Ahora bien, lo interesante viene al momento de hacer el deploy, pues es cuando el aplication server es quien pone la implementación real para que mi aplicación funcione.

      La única razón por la que tu deberías hacer referencia (importar) una implementación concreta como es el caso de Jersy, es cuando requieres utilizar una anotación o interface que sale del Estandar de JAX-RS, en tal caso, requieres el import por que el estandar no las cubrirá.

      Espero haber resuelto todas tus dudas.

      saludos.

    1. Hola Aldo,
      Efectivamente, cada servidor de aplicaciones maneja las URL de forma diferente, lo que te aconsejo es que revices en el log de tu servidor e identifiques que context le asigna a tu aplicación, sabiendo el context, el resto de la URL sería la misma.
      saludos.

  8. Saludos. sigo sin poder ver la pagina, después de un rato en un comentario vi que mencionas que a la hora de iniciar el servidor(WildFly 11.0) te dice el context y efectivamente es la que mencionas tu y no la que arroja por automático. Pero aun así a la hora de meterme a la pagina de helloworld “http://localhost:8080/api-0.0.1-SNAPSHOT/helloworld”, me manda un error de “Not Found” y si me meto a la pivot me arroja “Forbidden”. Soy nuevo en esto y quisiera aprender. Gracias

    1. Hola Raziel, la URL de un servicio se determina por varias partes, :///

      El host y puerto creo que queda muy claro, por lo que no me detendré en eso, con respecto al context, es que te asigna el servidor de aplicaciones para tu aplicación, el app-context es que determinas en la anotación @ApplicationPath, la cual dice a partir de que URL responderá todos los servicios, finalmente, service-uri es la URL que determinas para cada servicio, definida en la anotación @Path. En el caso de @Path, recuerda que se concatena con el path a nivel de clase(si existe) y el del método, la combinación de todo esto te dará la URL del servicio.
      Finalmente, recuerda que es importante consumir el servicio por medio del método adecuado (GET, POST, DELETE, ETC).

      saludos.

  9. hola tengo una duda. puedo hacer una api restfull, para integrar una aplicacion en java y una movil de react native?
    puedo pasar los datos de java directamente en json?
    para el servidor con node js?

    lo que pasa es que quiero hacer una aplicacion de ventas y pues quiero el servidor en tiempo real con nodejs, igual quiero integrar la app movil para agregar, consultar mas que todo la actividad que se hace en java eso es lo que quiero.
    he estado buscando mucho en internet y no tengo una idea clara. podria ayudarme
    estaré atento a su respuesta se lo agradeceria mucho…

    1. Hola estimado Jorginho,
      Claro que es posible implementar un API REST con Java o NodeJS, en el caso de Java puedes utilizar el API de JAX-RS, el cual combierte automáticamente los objetos Java en objetos JSON, en el caso de NodeJS, puedes utilizar el Framework de Express.
      Si quieres aprender a crear un API REST complet en NodeJS y luego integrarlo a React, te recomiendo mi libro, allí explico todo eso. https://reactiveprogramming.io/books/applicaciones-reactivas-con-react-nodejs-mongodb

      saludos.

    1. Hola Moises, re recomiendo que busques documentación del Jersey, el cual es un API para consumir servicios REST. Esta librería tiene clases para consumir los servicios muy fácilmente.

      saludos.

  10. Hola como estas?, yo no tengo ni la menor idea de nada del tutorial, jamas he trabajado este tipo de tecnología, y no entiendo nada. Un integrador de facturación electrónica me pide lo siguiente:

    se deberá realizar un llamado POST con Basic security con un JSon describiendo los datos de la factura.
    El usuario y contraseña a utilizar son los definidos al momento de realizar el registro en la web.
    Al ser Basic security se envían en el encabezado del llamado POST de la forma {usuario}:{contraseña} codificado en base 64.

    Se deberá realizar un POST a la siguiente URL:
    https://app.facturaelectronica.co/api/v1/invoice/process/new/batch/json/{environment}

    No tengo ni idea como se hace lo anterior !, leo tutoriales y no entiendo nada, que debo hacer?

    Este asunto me va a generar la pérdida de un contrato y debe responder hasta pecuniariamente.
    Te agradezco la luz que me puedas dar

    1. El archivo tipo json que me piden, si lo generé, y el validador de integridad esta ok. Ahora necesito hacer ese tal post para que ese archivo viaje al url que me piden

    2. Hola Jaime, si no entiendes nada, no tiene caso que te de una respuesta, pues seguramente tampoco la entenderás, así que lo único que te puedo recomendar es que compres un libro/curso donde te enseñe a crear API REST desde cero y que comiences de inmediato, por otra parte, si de esto depende ganar el contrato, pues no se que decirte, tendrás que improvisar rápido.
      saludos.

  11. Hola Oscar, te hago una consulta. Muy interesante el tutorial. Te dejo una consulta, teniendo en cuenta el “árbol” que genera por default Eclipse, donde debería empezar a escribir el código, es decir, donde agregaría la primer clase que especificas al comenzar a ingresar código.
    Saludos cordiales.
    Javier

    1. Hola Javier,
      Eso que comentas se conoce como el base package, es decir, el package a partir del cual se comienzan a crear las clases y los demas paquetes.
      Para definir este paquete no existe una una regla general, pero si que se siguen algunos consensos para su creación, por ejemplo, se suele comenzar con “com” para proyectos comerciales, o “org” para proyectos libres, luego, se suele poner el nombre de la compañia, finalmente el nombre del proyecto, por ejemplo:
      com.mycompany.myproyect
      org.mycompany.myproject
      Sin embargo, puedes crear el paquete que más te agrada, al final, no tiene un impacto sobre el producto terminado, es solo la forma en que organizamos las clases.

      saludos.

  12. buenas donde hay que meter exactamente estas dependencias??

    javax
    javaee-api
    7.0
    provided
    jar

    org.wildfly.core
    wildfly-server
    2.2.0.Final
    provided

    el pom.xml es:
    ped_tpi
    ped_tpi
    0.0.1-SNAPSHOT
    war

    src

    maven-compiler-plugin
    3.8.0

    1.8
    1.8

    maven-war-plugin
    3.2.3

    WebContent

    gracias

    1. El formulario no permite mostrar muy bien los XML, pero me imagino a que te refieres donde instalar las librería de Maven, esas las tienes que poner en el archivo pom.mxl,
      saludos

  13. Hola estimado, un muy buen artículo.
    Consulta, ¿puedo crear en mi netbeans un proyecto web para restful json y usar JPA con Eclipselink, de tal forma que puedo alimentar los servicios con los datos de mi base de datos en un servidor Payara?

    1. Si, es totalmente posible, al final, Payara es un servidor JavaEE completo, por lo que podrás implementar el API usando JAX-RS y cualquier implementación de JPA que gustes
      saludos.

  14. Hola, muy buenas, estoy buscando información, ejemplos, aplicaciones, etc… que pueda analizar para tomar ideas e integrar a mi aplicación web, en java, un sistema de permisos/roles para los usuario.

  15. Buenas tardes Oscar, tengo una duda como se estima un microservicio, en cuanto a tiempo de construcción, por ejemplo un CRUD, por cada acción se asigna un tiempo ???

    Gracias y Saludos.

    1. Hola Alberto, lo normal es que el desarrollo dure entre 1 a 3 semanas, que es lo que normalmente dura un Sprint de Scrum, más largo podrías ser, pero tambien podría ser un síntima de que estamos haciendo muy grande el Microservicio.

  16. Hola Oscar

    Quería saber si irás publicando los demás artículos del “curso completo para crear API REST con JAX-RS”. Son muy buenos tus artículos!

    Saludos

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *