apuntes:servicios_web
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
apuntes:servicios_web [2018/03/01 16:24] – [Consumir un servicio web desde Django] Santiago Faci | apuntes:servicios_web [2021/10/21 06:56] (current) – Santiago Faci | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ===== Servicios Web ===== | + | ====== Creación de servicios web. Spring Boot ====== |
==== ¿Qué son los servicios web? ==== | ==== ¿Qué son los servicios web? ==== | ||
Line 76: | Line 76: | ||
</ | </ | ||
- | ===== Spring | + | ===== Desarrollo de servicios web con Spring |
- | < | + | En el punto anterior sobre [[https:// |
- | {{ spring-logo.png }} | + | |
- | < | + | |
- | [[http:// | + | Podemos seguir |
- | Para eso, lo primero que haremos será utilizar el [[http:// | + | Partimos entonces de un proyecto de aplicación con [[https:// |
- | + | ||
- | Una vez tengamos creado el proyecto inicial, podemos empezar a trabajar en él para tener nuestro servidor. En este caso se trata de crear un servidor que tendrá los servicios web necesarios para que los usuarios de una aplicación Android puedan registrar sus opiniones en nuestra Base de Datos. Así, otros usuarios podrán visualizarlas en sus terminales. | + | |
==== Configuración del servidor ==== | ==== Configuración del servidor ==== | ||
Line 94: | Line 90: | ||
<file java application.properties> | <file java application.properties> | ||
# Configuración para el acceso a la Base de Datos | # Configuración para el acceso a la Base de Datos | ||
- | spring.jpa.hibernate.ddl-auto=none | + | spring.jpa.hibernate.ddl-auto=update |
spring.jpa.properties.hibernate.globally_quoted_identifiers=true | spring.jpa.properties.hibernate.globally_quoted_identifiers=true | ||
+ | |||
# Puerto donde escucha el servidor una vez se inicie | # Puerto donde escucha el servidor una vez se inicie | ||
- | server.port=${port:8080} | + | server.port=8080 |
# Datos de conexion con la base de datos MySQL | # Datos de conexion con la base de datos MySQL | ||
- | spring.datasource.url=jdbc: | + | spring.datasource.url=jdbc: |
- | spring.datasource.username=root | + | spring.datasource.username=myshopuser |
- | spring.datasource.password= | + | spring.datasource.password=mypassword |
spring.datasource.driverClassName=com.mysql.jdbc.Driver | spring.datasource.driverClassName=com.mysql.jdbc.Driver | ||
</ | </ | ||
- | Sobre el fichero '' | + | Hay que tener en cuenta que la propiedad //spring.jpa.hibernate.ddl-auto// |
- | <file java build.gradle> | + | * //none//: Para indicar que no queremos que genere la base de datos |
- | . . . | + | * //update//: Si queremos que la genere de nuevo en cada arranque |
- | apply plugin: ' | + | * //create//: Si queremos que la cree pero que no la genere de nuevo si ya existe |
- | apply plugin: ' | + | |
- | apply plugin: ' | + | |
- | apply plugin: ' | + | |
- | jar { | + | ==== Definir la base de datos ==== |
- | baseName | + | |
- | version | + | |
- | } | + | |
- | repositories { | + | Hay que tener en cuenta que //Spring// utiliza por debajo el framework de // |
- | mavenCentral() | + | |
- | } | + | |
- | dependencies { | + | Simplemente tendremos que crear la base de datos. Y ya de paso aprovecharemos para crear un usuario con el que la aplicación |
- | compile(' | + | |
- | compile(' | + | |
- | compile(' | + | |
- | providedRuntime(" | + | |
- | } | + | |
- | configurations { | + | <code sql> |
- | | + | CREATE DATABASE myshoponline; |
- | } | + | CREATE USER myshopuser IDENTIFIED BY ' |
- | </file> | + | GRANT ALL PRIVILEGES ON myshoponline.* TO myshopuser; |
+ | </code> | ||
- | Ahora, modificaremos la clase principal '' | + | Usaremos // |
- | Conviene prestar atención a los comentarios que he dejado en esta clase, donde se explica cómo lanzar | + | Así, simplemente tenemos que crear la clase con los atributos y métodos |
- | <file java Application.java> | + | Usaremos, además, la librería [[https:// |
+ | |||
+ | <code java> | ||
+ | import lombok.*; | ||
+ | |||
+ | import javax.persistence.*; | ||
+ | import | ||
/** | /** | ||
- | | + | |
- | * | + | |
- | * Cómo compilar/ | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | * | + | |
- | | + | |
- | | + | |
- | | + | |
* | * | ||
* @author Santiago Faci | * @author Santiago Faci | ||
- | * @version curso 2015-2016 | + | * @version curso 2021 |
*/ | */ | ||
- | @SpringBootApplication | + | @Data |
- | public class Application extends SpringBootServletInitializer | + | @AllArgsConstructor |
+ | @NoArgsConstructor | ||
+ | @Entity(name = " | ||
+ | public class Product | ||
- | public static void main(String[] args) { | + | @Id |
- | | + | @GeneratedValue(strategy = GenerationType.IDENTITY) |
- | } | + | |
+ | @Column | ||
+ | private String name; | ||
+ | @Column | ||
+ | private String description; | ||
+ | @Column | ||
+ | private String category; | ||
+ | @Column | ||
+ | private float price; | ||
+ | @Column(name = " | ||
+ | private LocalDateTime creationDate; | ||
+ | } | ||
+ | </ | ||
- | @Override | + | > **Recordad que todas las anotaciones Java en el ejemplo anterior son clases que pertenecen al paquete 'javax.persistence' |
- | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { | + | |
- | return application.sources(applicationClass); | + | |
- | } | + | |
- | private static Class< | + | ==== El acceso a la base de datos ==== |
- | } | + | |
- | </ | + | |
- | ==== Definir | + | Ahora creamos la '' |
- | Hay que tener en cuenta que //Spring// utiliza por debajo el framework | + | <code java> |
+ | /** | ||
+ | * Repositorio | ||
+ | * @author Santiago Faci | ||
+ | * @version curso 2021 | ||
+ | */ | ||
+ | @Repository | ||
+ | public interface ProductRepository extends CrudRepository< | ||
- | A continuación se muestra el script '' | + | Set< |
+ | Set< | ||
+ | } | ||
+ | </ | ||
- | <file sql opiniones.sql> | + | ==== Implementación de la lógica de negocio: Los Services ==== |
- | CREATE DATABASE IF NOT EXISTS opiniones; | + | |
- | USE opiniones; | + | |
- | CREATE TABLE IF NOT EXISTS opiniones ( | + | Los Services serán la capa de nuestra aplicación web donde implementaremos toda la lógica de negocio. |
- | id INT UNSIGNED PRIMARY KEY, | + | |
- | titulo VARCHAR(50) NOT NULL, | + | |
- | texto VARCHAR(50), | + | |
- | fecha DATETIME, | + | |
- | puntuacion INT UNSIGNED | + | |
- | ); | + | |
- | </ | + | |
- | Así, simplemente tenemos que crear la clase con los atributos y métodos que queramos y añadir las anotaciones que orientarán a // | + | Definiremos una interface |
<code java> | <code java> | ||
- | import javax.persistence.*; | + | public |
- | /** | + | |
- | * Opinion que los usuarios tienen sobre un monumento | + | |
- | * Se deben definir las anotaciones que indican la tabla y columnas a las que | + | |
- | * representa esta clase y sus atributos | + | |
- | * | + | |
- | * @author Santiago Faci | + | |
- | * @version curso 2015-2016 | + | |
- | */ | + | |
- | @Entity | + | |
- | @Table(name = " | + | |
- | public | + | |
- | @Id | + | Set< |
- | @GeneratedValue | + | |
- | private int id; | + | |
- | | + | |
- | private | + | |
- | | + | void deleteProduct(long id); |
- | | + | |
- | | + | |
- | private Date fecha; | + | |
- | | + | |
- | private int puntuacion; | + | |
- | + | ||
- | // Constructor | + | |
- | // Getters y Setters | + | |
- | . . . | + | |
} | } | ||
</ | </ | ||
- | > **Recordad que todas las anotaciones Java en el ejemplo anterior son clases que pertenecen al paquete ' | + | Que implementaremos |
- | ==== El Acceso a la Base de Datos ==== | + | <code java> |
+ | @Service | ||
+ | public class ProductServiceImpl implements ProductService { | ||
- | Ahora creamos la '' | + | @Autowired |
+ | private ProductRepository productRepository; | ||
- | <code java> | + | @Override |
- | /** | + | public Set<Product> findAll() { |
- | * Clase que hace de interfaz con la Base de Datos | + | |
- | * Al heredar de CrudRepository se asumen una serie de operaciones | + | } |
- | * para registrar o eliminar contenido | + | |
- | * Se pueden añadir operaciones ya preparadas como las que hay de ejemplo ya hechas | + | |
- | * | + | |
- | * @author Santiago Faci | + | |
- | * @version curso 2015-2016 | + | |
- | */ | + | |
- | public interface OpinionRepository extends CrudRepository< | + | |
- | List<Opinion> findAll(); | + | @Override |
- | List<Opinion> findByPuntuacion(int puntuacion); | + | public Set<Product> findByCategory(String category) { |
+ | return productRepository.findByCategory(category); | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public Optional<Product> findById(long id) { | ||
+ | return productRepository.findById(id); | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public Product addProduct(Product product) { | ||
+ | return productRepository.save(product); | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public Product modifyProduct(long id, Product newProduct) { | ||
+ | Product product = productRepository.findById(id) | ||
+ | .orElseThrow(() -> new ProductNotFoundException(id)); | ||
+ | newProduct.setId(product.getId()); | ||
+ | return productRepository.save(newProduct); | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public void deleteProduct(long id) { | ||
+ | productRepository.findById(id) | ||
+ | .orElseThrow(() -> new ProductNotFoundException(id)); | ||
+ | productRepository.deleteById(id); | ||
+ | } | ||
} | } | ||
</ | </ | ||
- | ==== Implementación del Controller | + | ==== Implementación del controller |
- | Por último, crearemos la clase que hará de '' | + | Antes de continuar, es muy conveniente leerse el siguiente artículo sobre los diferentes [[https:// |
- | En este caso hemos creado tres operaciones: | + | Y a continuacuón, |
- | * getOpiniones(): Devuelve todas las opiniones de la base de datos | + | * Obtener todos los productos: Método GET que devuelve toda la colección |
- | * getOpiniones(int puntuacion): Devuelve las opiniones | + | * Obtener todos los productos |
- | * addOpinion(String titulo, String texto, int puntuacion): Registra una nueva opinión | + | * Obtener un producto determinado: Método GET que devuelve un objeto determinado utilizando un parámetro Path |
+ | * Registrar un nuevo producto: Método POST que registra un nuevo producto | ||
+ | * Modificar un producto: Método PUT que modifica un producto | ||
+ | * Eliminar un producto: Método DELELET que elimina un producto existente | ||
- | Cada una de las operaciones | + | Como veremos, algunas |
- | * http:// | + | Para entender el siguiente fragmento de código conviene tener en cuenta lo siguiente: |
- | * http:// | + | * Cada método anotado define un endpoint que podrá ser invocado por otra aplicación |
- | * http:// | + | * Las anotaciones @GetMapping, |
- | * http:// | + | * Si el endpoint debe utilizar '' |
+ | * Si el endpoint debe utilizar '' | ||
+ | * Si el endpoint debe utilizar '' | ||
+ | * La respuesta será siempre un objeto '' | ||
<code java> | <code java> | ||
- | /** | ||
- | * Controlador para las opiniones | ||
- | * Contendrá todos los métodos que realicen operaciones sobre opiniones de los usuarios | ||
- | * | ||
- | * @author Santiago Faci | ||
- | * @version curso 2015-2016 | ||
- | */ | ||
@RestController | @RestController | ||
- | public class OpinionController | + | public class ProductController |
- | | + | |
- | private | + | private |
- | /** | + | |
- | * Obtiene todas las opiniones de los usuarios | + | public |
- | | + | Set< |
- | */ | + | if (category.equals("" |
- | @RequestMapping("/opiniones") | + | products = productService.findAll(); |
- | public | + | else |
+ | products = productService.findByCategory(category); | ||
- | List<Opinion> listaOpiniones = repository.findAll(); | + | return new ResponseEntity<>(products, HttpStatus.OK); |
- | | + | } |
- | | + | |
- | /** | + | |
- | * Obtiene todas las opiniones con una puntuacion determinada | + | public |
- | | + | Product product = productService.findById(id) |
- | * @return | + | .orElseThrow(() -> new ProductNotFoundException(id)); |
- | */ | + | |
- | @RequestMapping("/opiniones_puntuacion") | + | |
- | public | + | |
- | List<Opinion> listaOpiniones = repository.findByPuntuacion(puntuacion); | + | return new ResponseEntity<>(product, HttpStatus.OK); |
- | | + | } |
- | | + | |
- | /** | + | |
- | * Registra una nueva opinión en la Base de Datos | + | public |
- | * @param titulo | + | |
- | * @param texto | + | |
- | * @param puntuacion | + | } |
- | */ | + | |
- | | + | |
- | public | + | |
- | @RequestParam(value = " | + | |
- | @RequestParam(value = " | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | } | + | public ResponseEntity< |
+ | productService.deleteProduct(id); | ||
+ | return new ResponseEntity<> | ||
+ | } | ||
+ | |||
+ | @ExceptionHandler(ProductNotFoundException.class) | ||
+ | @ResponseBody | ||
+ | @ResponseStatus(HttpStatus.NOT_FOUND) | ||
+ | public ResponseEntity< | ||
+ | Response response = Response.errorResonse(NOT_FOUND, | ||
+ | return new ResponseEntity<> | ||
+ | } | ||
} | } | ||
</ | </ | ||
- | ==== Ejecución | + | Como se puede ver, al final del controlador, |
- | Una vez terminado todo, para lanzar el servidor tenemos dos opciones: | + | <code java> |
- | * Desde el propio IDE, ejecutando '' | + | public class ProductNotFoundException extends RuntimeException { |
- | * Utilizando el jar que podemos generar con el comando '' | + | |
- | {{ youtube> | + | public ProductNotFoundException() |
+ | super(); | ||
+ | | ||
- | ==== Depuración de Servicios Web ==== | + | public ProductNotFoundException(String message) { |
+ | super(message); | ||
+ | } | ||
- | La primera aproximación a la hora de depurar los Servicios Web desarrollados es utilizar el navegador introduciendo las URLs esperando obtener la salida apropiada y comprobar asi que todo funciona correctamente. Es bastante cómodo pero fácil de usar y eficiente, hasta un punto. | + | public ProductNotFoundException(long id) { |
+ | super(" | ||
+ | } | ||
+ | } | ||
+ | </ | ||
- | Si lo que queremos | + | También necesitaremos implementar la clase '' |
- | <figure> | + | <code java> |
- | {{ postman.png }} | + | @Data |
- | < | + | @AllArgsConstructor(access = AccessLevel.PRIVATE) |
- | ===== Consumir un servicio web desde Django ===== | + | public class Response { |
- | Puesto que la idea es consumir un servicio web que nos ofrecerá una serie de datos en formato JSON y nos interesaría convertirlos fácilmente a objetos Python, instalaremos el paquete // | + | public static final int NO_ERROR = 0; |
+ | public static final int NOT_FOUND = 101; | ||
- | <code bash> | + | public static final String NO_MESSAGE = ""; |
- | santi@zenbook:$ pip3 install djangorestframework requests | + | |
+ | private Error error; | ||
+ | |||
+ | | ||
+ | @AllArgsConstructor(access = AccessLevel.PRIVATE) | ||
+ | static class Error { | ||
+ | private long errorCode; | ||
+ | private String message; | ||
+ | } | ||
+ | |||
+ | public static Response noErrorResponse() { | ||
+ | return new Response(new Error(NO_ERROR, | ||
+ | } | ||
+ | |||
+ | public static Response errorResonse(int errorCode, String errorMessage) { | ||
+ | return new Response(new Error(errorCode, | ||
+ | } | ||
+ | } | ||
</ | </ | ||
- | Una vez instalado el paquete tendremos que añadirlo al fichero '' | + | ==== Trazabilidad. Logs de aplicación ==== |
- | <file python settings.py> | + | Si queremos mantener la trazabilidad de la ejecución de nuestra aplicación (y esto sería válido tanto para la aplicación web como para el proyecto de servicio web que estamos haciendo ahora), tenemos que configurar cómo queremos que se registren los sucesos y trazas de la ejecución. |
- | . . . | + | |
- | INSTALLED_APPS = [ | + | |
- | . . . | + | |
- | ' | + | |
- | ] | + | |
- | . . . | + | |
- | </ | + | |
- | En nuestro caso vamos a concectar con un servicio web que ofrece datos sobre opiniones de usuarios de forma que obtenemos, entre otros, un titulo, un texto y una puntuación. Entonces crearemos un modelo de datos '' | + | Por defecto, cuando ejecutamos la aplicación en modo desarrollo, y también ocurre asi cuando se hace en producción, Spring Boot lanza por pantalla |
- | <file python models.py> | + | Para eso, simplemente tenemos que crear un fichero llamado '' |
- | . . . | + | |
- | class Opinion(models.Model): | + | |
- | titulo = models.CharField(max_length=200) | + | |
- | texto = models.CharField(max_length=200) | + | |
- | puntuacion = models.IntegerField | + | |
- | pelicula = models.CharField(max_length=200) | + | |
- | . . . | + | |
- | </ | + | |
- | Ahora, en un fichero que llamaremos '' | + | <code xml> |
+ | <?xml version=" | ||
+ | < | ||
+ | <!-- Propiedades | ||
+ | < | ||
+ | < | ||
- | <file python serializer.py> | + | |
- | from rest_framework import serializers | + | < |
- | from .models import Opinion | + | class=" |
+ | < | ||
+ | < | ||
+ | < | ||
+ | %white(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %-60.60yellow(%C{20}): | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | <!-- Configuración para que se almacene el log en un fichero: File Appender --> | ||
+ | < | ||
+ | class=" | ||
+ | < | ||
+ | <encoder | ||
+ | class=" | ||
+ | < | ||
+ | </ | ||
- | class OpinionSerializer(serializers.ModelSerializer): | + | <!-- Política de rotado de logs: diario y cuando el fichero llegue a los 10 MB --> |
- | class Meta: | + | < |
- | | + | |
- | | + | < |
- | </file> | + | < |
+ | class=" | ||
+ | < | ||
+ | </ | ||
+ | | ||
+ | </appender> | ||
- | Desde Django podríamos acceder al servicio web para listar todas las opiniones: | + | <!-- Define el nivel de log para cada appender --> |
+ | <root level=" | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
- | <file python views.py> | + | Asi es como quedaría el fichero log resultante con las trazas de ejecución de la aplicación: |
- | import requests | + | |
- | . . . | + | |
- | def opiniones(request): | + | |
- | ws = requests.get(' | + | |
- | json = ws.json() | + | |
- | serializer = OpinionSerializer(data=json, | + | |
- | if serializer.is_valid(): | + | |
- | lista_opiniones = serializer.save() | + | |
- | context = {' | + | |
- | return render(request, | + | |
- | else: | + | |
- | print(serializer.errors) | + | |
- | return render(request, | + | <code bash> |
- | . . . | + | santi@zenbook: |
- | </file> | + | santi@zenbook: |
+ | total 56 | ||
+ | drwxr-xr-x | ||
+ | drwxr-xr-x | ||
+ | -rw-r--r-- | ||
+ | </code> | ||
- | O bien acceder a las opiniones para una pelicula determinada, pasando como parámetro | + | Hasta el momento, la mayoría de las trazas que se registran las emite el propio framework Spring Boot. Pero nosotros tenemos la oportunidad |
- | <file python views.py> | + | <code java> |
- | import requests | + | private final Logger logger |
- | . . . | + | </code> |
- | def pelicula(request, | + | |
- | pelicula | + | |
- | . . . | + | |
- | ws = requests.get(' | + | |
- | json = ws.json() | + | |
- | serializer = OpinionSerializer(data=json, | + | |
- | if serializer.is_valid(): | + | |
- | lista_opiniones = serializer.save() | + | |
- | context = {' | + | |
- | return render(request, | + | |
- | else: | + | |
- | print(serializer.errors) | + | |
- | return render(request, ' | + | Por ejemplo, a continuación se registran un par de trazas para que quede constancia de que se ha invocado a la operación que permite listar los productos del catálogo: |
- | . . . | + | |
- | </ | + | |
- | En el caso de que no queramos guardarlo en la Base de Datos, podemos simplemente obtener los datos como una lista de ' | + | <code java> |
+ | @GetMapping("/ | ||
+ | public ResponseEntity< | ||
+ | logger.info(" | ||
+ | Set< | ||
+ | if (category.equals("" | ||
+ | products = productService.findAll(); | ||
+ | else | ||
+ | products = productService.findByCategory(category); | ||
- | < | + | logger.info(" |
+ | return new ResponseEntity<> | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | También en el caso de que se produzca alguna excepción, será interesante registrar una traza e incluso podremos incluir la propia excepción: | ||
+ | |||
+ | <code java> | ||
+ | @ExceptionHandler(ProductNotFoundException.class) | ||
+ | @ResponseBody | ||
+ | @ResponseStatus(HttpStatus.NOT_FOUND) | ||
+ | public ResponseEntity< | ||
+ | Response response = Response.errorResonse(NOT_FOUND, | ||
+ | logger.error(pnfe.getMessage(), | ||
+ | return new ResponseEntity<> | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | A continuación podemos ver cómo quedará la traza del ejemplo anterior registrada en el log de la aplicación: | ||
+ | |||
+ | < | ||
+ | 2021-03-02 21: | ||
+ | com.sanvalero.myshop.exception.ProductNotFoundException: | ||
+ | at com.sanvalero.myshop.service.ProductServiceImpl.lambda$deleteProduct$1(ProductServiceImpl.java: | ||
+ | at java.base/ | ||
+ | at com.sanvalero.myshop.service.ProductServiceImpl.deleteProduct(ProductServiceImpl.java: | ||
+ | at com.sanvalero.myshop.controller.ProductController.deleteProduct(ProductController.java: | ||
+ | at java.base/ | ||
+ | at java.base/ | ||
+ | at java.base/ | ||
+ | at java.base/ | ||
+ | at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java: | ||
+ | at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java: | ||
+ | at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java: | ||
+ | at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java: | ||
+ | at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java: | ||
+ | at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java: | ||
+ | at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java: | ||
+ | at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java: | ||
+ | at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java: | ||
+ | at org.springframework.web.servlet.FrameworkServlet.doDelete(FrameworkServlet.java: | ||
+ | at javax.servlet.http.HttpServlet.service(HttpServlet.java: | ||
+ | at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java: | ||
+ | at javax.servlet.http.HttpServlet.service(HttpServlet.java: | ||
. . . | . . . | ||
- | if serializer.is_valid(): | ||
- | lista_opiniones = serializer.data | ||
- | // Visualiza el titulo de la primera opinion obtenida | ||
- | print(lista_opiniones[0][' | ||
. . . | . . . | ||
</ | </ | ||
- | ===== Seguridad | + | ===== Relaciones entre clases |
+ | ===== Probar los Servicios Web ===== | ||
- | ---- | + | Si antes de integrar una aplicación con un determinado servicio web, queremos probar éste para comprobar cómo funcionar, tenemos que usar aplicaciones destinadas para ese propósito, como [[https:// |
- | ---- | + | Para el servicio web desarrollado a lo largo de este tema, vamos a ver cómo se definirían una serie de pruebas para todos sus endpoints utilizando Postman. |
- | {{ ejercicio.png? | + | Crearemos una colección y diferentes requests que nos permitan probar todos los endpoints desarrollados en este proyecto (Pincha en la captura para aumentarla y ver cómo configurar cada uno de los casos) |
- | ===== Ejercicios ===== | + | < |
+ | {{ getProducts.png }} | ||
+ | < | ||
+ | </ | ||
- | - Realiza un servicio web que proporcione una API para notificar sobre eventos que tienen lugar en una ciudad. Se dispondrá de una Base de Datos con los datos de eventos (nombre, descripción, | + | < |
- | - Listado de todos los eventos | + | {{ getProductsByCategory.png }} |
- | - Listado con los eventos que disponen | + | < |
- | - Información de un evento concreto a partir del nombre del mismo | + | </ |
- | - Amplia el ejercicio anterior para que sea posible registrar y eliminar eventos | + | |
- | - Diseña una web con Django que muestre los resultados de los partidos de fútbol utilizando como origen de datos el servicio web desarrollado en el primer ejercicio | + | |
- | - Incorpora a la web realizada en el punto anterior un buscador por equipos de futbol (local o visitante) | + | |
- | ---- | ||
- | ===== Proyectos de Ejemplo ===== | + | < |
+ | {{ addProduct.png }} | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | |||
+ | < | ||
+ | {{ modifyProduct.png }} | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | |||
+ | < | ||
+ | {{ deleteProduct.png }} | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | |||
+ | < | ||
+ | {{ deleteProductError.png }} | ||
+ | < | ||
+ | </ | ||
---- | ---- | ||
- | ===== Prácticas | + | ===== Ejercicios |
+ | |||
+ | - Crea una aplicación que ofrezca unos servicios web para la gestión de vuelos. La aplicación tendrá una base de datos de vuelos donde almacenará: | ||
+ | - Búsqueda de vuelos, pudiendo filtrar por origen, destino y numero de escalas | ||
+ | - Registro de un nuevo vuelo | ||
+ | - Dar de baja un vuelo | ||
+ | - Dar de baja todos los vuelos a un destino determinado | ||
+ | - Modificar un vuelo\\ \\ | ||
+ | - Crea una API que ofrezca servicios web de búsqueda de hoteles. Se mantendrá un base de datos de hoteles (nombre, descripción, | ||
+ | - Búsqueda de hotel por localidad o categoría | ||
+ | - Búsqueda de habitaciones de un hotel por tamaño y precio (rango minimo-> | ||
+ | - Registrar un nuevo hotel | ||
+ | - Registrar una nueva habitación a un hotel | ||
+ | - Eliminar una habitación determinada de un hotel | ||
+ | - Modificar una habitación para indicar que está ocupada | ||
+ | ===== Proyectos de ejemplo ===== | ||
+ | |||
+ | Todos los proyectos de ejemplo de esta parte están en el [[http:// | ||
+ | |||
+ | Los proyectos que se vayan haciendo en clase estarán disponibles en el [[http:// | ||
+ | |||
+ | Para manejaros con Git recordad que tenéis una serie de videotutoriales en [[https:// | ||
---- | ---- | ||
- | (c) 2018 Santiago Faci | + | (c) 2016-2021 |
apuntes/servicios_web.1519921499.txt.gz · Last modified: 2019/01/04 13:22 (external edit)