Over a million developers have joined DZone.

Creating Entities in a Spring Boot/Elide JSON API Server

Learn how to update the application to allow new entities to be created.

Build APIs from SQL and NoSQL or Salesforce data sources in seconds. Read the Creating REST APIs white paper, brought to you in partnership with CA Technologies.

In a previous article, I showed you how to create a Spring Boot application that integrated the Elide JSON API library to create a read-only REST API. In part 2, we’ll update the application to allow new entities to be created.

The JSON API supports the HTTP POST verb for creating new entities, and for creating new to-many relationships. We’ll add support for these two REST endpoints in our application.

First, though, we have some house keeping to do. As you saw in the first article, we have to do some work to prepare Elide once a request has been received: get the Hibernate Session Factory, find the complete request URL, create a logger, and then create the Elide object itself. This code is going to be shared between all Elide operations, so it makes sense to move it into a common location.

/**
     * 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 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);

        /*
            Elide works with the Hibernate SessionFactory, not the JPA EntityManagerFactory.
            Fortunately we san unwrap the JPA EntityManagerFactory to get access to the
            Hibernate SessionFactory.
         */
        final SessionFactory sessionFactory = emf.unwrap(SessionFactory.class);

        /*
            Elide takes a hibernate session factory
        */
        final DataStore dataStore = new HibernateStore(sessionFactory);

        /*
            Define a logger
         */
        final Logger logger = new Slf4jLogger();

        /*
            Create the Elide object
         */
        final Elide elide = new Elide(logger, dataStore);

        /*
            There is a bug in Elide on Windows that will convert a leading forward slash into a backslash,
            which then displays the error "token recognition error at: '\\'".
         */
        final String fixedPath = restOfTheUrl.replaceAll("^/", "");

        /*
            Now that the boilerplate initialisation is done, we let the caller do something useful
         */
        return elideCallable.call(elide, fixedPath);
    }


The new elideRunner() method is almost a line for line copy of what used to be found in the method that responded to the GET request. The only real differences are that we don’t process the request parameters (because, as we’ll see, the Elide post() method doesn’t require these), and that we defer the actual execution of the Elide library to an interface that takes the newly created Elide object and the path of the request.

/**
 * We'll implement this interface as a lambda to make working with Elide easier
 */
public interface ElideCallable {
    String call(final Elide elide, final String path);
}


Before we handle the POST request, let’s look at what the GET request method now looks like:

    @CrossOrigin(origins = "*")
    @RequestMapping(
            method = RequestMethod.GET,
            produces = MediaType.APPLICATION_JSON_VALUE,
            value={"/{entity}", "/{entity}/{id}/relationships/{entity2}", "/{entity}/{id}/{child}", "/{entity}/{id}"})
    @Transactional
    public String jsonApiGet(@RequestParam final Map<String, String> allRequestParams, final HttpServletRequest request) {
        /*
            Here we pass through the data Spring has provided for us in the parameters, then making
            use of Java 8 Lambdas to do something useful.
         */
        return elideRunner(
                request,
                (elide, path) -> elide.get(path, fromMap(allRequestParams), new Object()).getBody());
    }


We have effectively reduced the method to a single line of code, making use of Java 8 lambdas to execute the Elide library’s get() method.

Not surprisingly, the method handling the POST request is very similar.

    @CrossOrigin(origins = "*")
    @RequestMapping(
            method = RequestMethod.POST,
            produces = MediaType.APPLICATION_JSON_VALUE,
            value={"/{entity}", "/{entity}/{id}/relationships/{entity2}"})
    @Transactional
    public String jsonApiPost(@RequestBody final String body, final HttpServletRequest request) {
        /*
            There is not much extra work to do here over what we have already put in place for the
            get request. Our callback changes slightly, but we are still just passing objects
            from Spring to Elide.
         */
        return elideRunner(
                request,
                (elide, path) -> elide.post(path, body, new Object(), SecurityMode.SECURITY_INACTIVE).getBody());
    }


Like its GET counterpart, the method handling the POST request does nothing more than pass the parameters supplied by Spring into Elide, making use of the common functionality now abstracted away by the elideRunner() method.

To create a new entity, POST the following JSON to the http://localhost:8080/parent endpoint:

{
  "data": {
    "type": "parent",
    "attributes": {
      "description": "James drives a racecar",
      "name": "James"
    }
  }
}


The response will be something like this:

{
  "data": {
    "type": "parent",
    "id": "12",
    "attributes": {
      "description": "James drives a racecar",
      "name": "James"
    },
    "relationships": {
      "children": {
        "data": []
      }
    }
  }
}


To define a relationship between a parent and a child, POST the following to http://localhost:8080/parent/12/children endpoint:

{
  "data": { "type": "child", "id": "1" }
}


The response will be something like this:

{
  "errors": [
    "com.yahoo.elide.core.exceptions.ForbiddenAccessException: ForbiddenAccess not shared child#1"
  ]
}


This is because Elide has a security layer which prevents these relationships from being defined without some additional code. In the next article, we’ll take a look at these security annotations and give ourselves the ability to define relationships between entities.

Grab the source code for this project from GitHub.

The Integration Zone is brought to you in partnership with CA Technologies.  Use CA Live API Creator to quickly create complete application backends, with secure APIs and robust application logic, in an easy to use interface.

Topics:
json api ,spring boot

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}