GraphQL APIs

REST es la manera más conocida de proporcionar datos de un servidor, aunque sus respuestas son muy rígidas. GraphQL es un lenguaje de queries para APIs, que al igual que REST es usado para cargar datos de un servidor a un cliente, pero que es muy eficiente y flexible porque permite al cliente especificar exactamente lo que necesita.

Para integrar GraphQL en Spring Boot estas librerías son necesarias (deben añadirse manualmente):
  • graphql-spring-boot-starter - Este starter es muy útil porque configura automáticamente un Servlet GraphQL al que puedes acceder a través de /graphql.
  • graphql-java-tools - Una librería de ayuda para parsear el esquema de GraphQL.

GraphQL schema (.graphqls)

Define los data points que ofrece la API. Incluye los tipos de datos, las relaciones entre ellos y las operaciones que podemos realizar sobre ellos.

type Location { id: ID! name: String! address: String! } type Query { findAllLocations: [Location]! } type Mutation { newLocation(name: String!, address: String) : Location! deleteLocation(id:ID!) : Boolean updateLocationName(newName: String!, id:ID!) : Location! }

Operations

Las operaciones que GraphQL ofrece sobre los datos son:
  • Queries: nos permiten obtener datos. Cada query tendra su propio objeto.
  • Mutations: podemos actualizar la información almacenada en el servidor (Create, Update y Delete).
Un ejemplo de query: { "query": {findAllLocations {name id address} }" }
Además de Postman y otras herramientas del estilo, disponemos de GraphiQL para testear nuestra GraphQL API.

Ejemplo:


Location.java @Entity public class Location { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String name; private String address; public Location(Long id, String name, String address) { this.id = id; this.name = name; this.address = address; } public Location(String name, String address) { this.name = name; this.address = address; } public Location() {} public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } }
LocationNotFoundException public class LocationNotFoundException extends RuntimeException implements GraphQLError { private Map<String, Object> extensions = new HashMap<>(); public LocationNotFoundException(String message, Long invalidLocationId) { super(message); extensions.put("invalidLocationId", invalidLocationId); } @Override public List<SourceLocation> getLocations() { return null; } @Override public Map<String, Object> getExtensions() { return extensions; } @Override public ErrorType getErrorType() { return ErrorType.DataFetchingException; } }
Mutation.java @Component public class Mutation implements GraphQLMutationResolver { private LocationRepository locationRepository; public Mutation(LocationRepository locationRepository) { this.locationRepository = locationRepository; } public Location newLocation(String name, String address) { Location location = new Location(name, address); locationRepository.save(location); return location; } public boolean deleteLocation(Long id) { locationRepository.deleteById(id); return true; } public Location updateLocationName(String newName, Long id) { Optional<Location> optionalLocation = locationRepository.findById(id); if(optionalLocation.isPresent()) { Location location = optionalLocation.get(); location.setName(newName); locationRepository.save(location); return location; } else { throw new LocationNotFoundException("Location Not Found", id); } } }
LocationRepository.java public interface LocationRepository extends CrudRepository { }
Query.java @Component public class Query implements GraphQLQueryResolver { private LocationRepository locationRepository; public Query(LocationRepository locationRepository) { this.locationRepository = locationRepository; } public Iterable<Location> findAllLocations() { return locationRepository.findAll(); } }
LocationService.java public interface LocationService { List retrieveLocations(); }
LocationServiceImpl.java @Service public class LocationServiceImpl implements LocationService { @Autowired LocationRepository locationRepository; public List<Location> retrieveLocations() { return (List<Location>) locationRepository.findAll(); } }
LocationController.java @RestController public class LocationController { private LocationService locationService; @Autowired public void setLocationService(LocationService locationService) { this.locationService = locationService; } @GetMapping("/location") public ResponseEntity<List<Location>> getAllLocations() { List<Location> list = locationService.retrieveLocations(); return new ResponseEntity<List<LocationGlt;>(list, HttpStatus.OK); } }

Comentarios

Entradas populares de este blog

Django REST framework

Envío de checkboxes o selector multiple por AJAX con jQuery

Django: relaciones polimórficas