Skip to content

Instantly share code, notes, and snippets.

@scathers
Created January 24, 2018 20:28
Show Gist options
  • Save scathers/42ebd791eb6f120116896f1564fed57d to your computer and use it in GitHub Desktop.
Save scathers/42ebd791eb6f120116896f1564fed57d to your computer and use it in GitHub Desktop.
Spring Boot Elide Integration
package cathers.controller;
import java.security.Principal;
import java.util.Map;
import javax.persistence.EntityManagerFactory;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
import org.hibernate.SessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.HandlerMapping;
import com.yahoo.elide.Elide;
import com.yahoo.elide.ElideResponse;
import com.yahoo.elide.ElideSettings;
import com.yahoo.elide.ElideSettingsBuilder;
import com.yahoo.elide.core.DataStore;
import com.yahoo.elide.datastores.hibernate5.*;
/**
* An example Spring Boot controller that uses Elide version 4 for a JSON API REST service.
* Based on:
* https://dzone.com/articles/create-a-json-api-rest-service-with-spring-boot-an
*/
@RestController
@RequestMapping(path = ElideController.API_PREFIX, produces = ElideController.CONTENT_TYPE)
public class ElideController {
private static final Logger log = LoggerFactory.getLogger(ElideController.class);
public static final String API_PREFIX = "api";
public static final String CONTENT_TYPE = "application/vnd.api+json";
final EntityManagerFactory emf;
final SessionFactory sessionFactory;
final DataStore dataStore;
final ElideSettings elideSettings;
final Elide elide;
@Autowired
public ElideController(EntityManagerFactory emf) {
this.emf = emf;
sessionFactory = emf.unwrap(SessionFactory.class);
dataStore = new AbstractHibernateStore.Builder(sessionFactory).build();
elideSettings = new ElideSettingsBuilder(dataStore).build();
this.elide = new Elide(elideSettings);
}
/**
* We'll implement this interface as a lambda to make working with Elide easier
*/
public interface ElideCallable {
ElideResponse call(final Elide elide, final String path);
}
/**
* All our elide operations require similar initialisation, which we perform in this method before
* calling elideCallable with the elide object and the path that elide needs to know what it is
* supposed to do.
*
* @param request The request
* @param elideCallable A callback that is used to execute elide
* @return The response to the client
*/
private ResponseEntity<String> elideRunner(final HttpServletRequest request,
final ElideCallable elideCallable) {
// This gives us the full path that was used to call this endpoint.
final String restOfTheUrl =
((String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE))
// Remove the API prefix
.substring(("/" + API_PREFIX).length());
final ElideResponse elideResponse = elideCallable.call(elide, restOfTheUrl);
return ResponseEntity.status(elideResponse.getResponseCode()).body(elideResponse.getBody());
}
/**
* Converts a plain map to a multivalued map
*
* @param input The original map
* @return A MultivaluedMap constructed from the input
*/
private MultivaluedMap<String, String> fromMap(final Map<String, String> input) {
return new MultivaluedHashMap<String, String>(input);
}
@RequestMapping(method = RequestMethod.GET, value = {"/{entity}",
"/{entity}/{id}/relationships/{entity2}", "/{entity}/{id}/{child}", "/{entity}/{id}"})
@Transactional
public ResponseEntity<String> jsonApiGet(@RequestParam final Map<String, String> allRequestParams,
final HttpServletRequest request, final Principal principal) {
log.trace("GET Principal: {}", principal);
return elideRunner(request,
(elide, path) -> elide.get(path, fromMap(allRequestParams), principal));
}
@RequestMapping(method = RequestMethod.POST,
value = {"/{entity}", "/{entity}/{id}/relationships/{entity2}"})
@Transactional
public ResponseEntity<String> jsonApiPost(@RequestBody final String body,
final HttpServletRequest request, final Principal principal) {
return elideRunner(request, (elide, path) -> elide.post(path, body, principal));
}
@RequestMapping(method = RequestMethod.DELETE,
value = {"/{entity}/{id}", "/{entity}/{id}/relationships/{entity2}"})
@Transactional
public ResponseEntity<String> jsonApiDelete(@RequestBody(required = false) final String body,
final HttpServletRequest request, final Principal principal) {
return elideRunner(request, (elide, path) -> elide.delete(path, body, principal));
}
@RequestMapping(method = RequestMethod.PATCH,
value = {"/{entity}/{id}", "/{entity}/{id}/relationships/{entity2}"})
@Transactional
public ResponseEntity<String> jsonApiPatch(@RequestBody final String body,
final HttpServletRequest request, final Principal principal) {
/*
* Note that the patch operation here is the standard update, not the JSON Patch extension
* (http://jsonapi.org/extensions/jsonpatch/)
*/
return elideRunner(request,
(elide, path) -> elide.patch(CONTENT_TYPE, CONTENT_TYPE, path, body, principal));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment