Instantly Deploy Java GraphQL APIs Using Apifi — Quick Start

David Finson
The Startup
Published in
4 min readOct 18, 2020

--

A Quick Start Guide to Getting a Java GraphQL API up and Running in no time Using Apifi and Spring Boot

What is Apifi and Why Should You Care?

Apifi is a Java (8+) annotation processing framework which auto generates GraphQL APIs for JPA based data models. It spans the full API stack; from data access to client side consumption. Apifi is centered around one simple goal: To eliminate the need for generic CRUD related boilerplate without compromising on control and customizability.

This means no service beans implementing generic CRUD logic, no manual GraphQL setup, no JpaRepositories, no web controller. All of that’s taken care of. You just focus on what makes your project unique, no boilerplate required.

TLDR; Apifi can instantly turn any JPA data model into a GraphQL API, no boilerplate code required.

What We’ll be Doing

In this article we’ll be demonstrating how to rapidly build a simple eCommerce Java GraphQL API using Apifi and Spring Boot. Before we start I’ll just note that Apifi is built on top of graphql-java, SPQR, and Spring Data JPA. You’ll probably be able to understand this guide regardless, but I’d strongly recommend being at least somewhat familiar with these tools in order to understand what’s actually going on under the hood.

Maven Dependencies

<dependencies>
<dependency>
<groupId>dev.sanda</groupId>
<artifactId>apifi</artifactId>
<version>0.1.0</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>

API Requirements and Data Model

The eCommerce API needs to be able to:

  1. Allow Customer sign up (i.e. Create customer).
  2. Get a Customer by ID.
  3. Add products to the inventory (i.e. Create products).
  4. Allow a Customer to add or remove products to and from their shopping cart (i.e. associate and disassociate existing products with and from a shopping cart).
  5. Allow a customer to complete their purchase by checking out (i.e. create a new order, empty the shopping cart, calculate the subtotal, and remove the selected products from the inventory).

The data model consists of 4 classes:

Customer

Product

Archivable is an interface defined within Apifi containing two methods:

Boolean getIsArchived();void setIsArchived(Boolean isArchived);

This allows us (and Apifi) to mark objects as archived instead of full-on deleting them from the database. This will come in handy when we implement the customer checkout logic and want to keep track of ordered products after removing (i.e. archiving) the sold items.

ShoppingCart

CustomerOrder

Note the @Transient ShoppingCart “fromCart” field in CustomerOrder. Transient fields exist in memory only and are not included in the database schema. We’ll demonstrate why this one is here a bit further down.

In order to turn this data model into a fully functional GraphQL API, we just need to add a few annotations. The first annotation which we’ll see as applied to the Customer class is @WithCrudEndpoints(...) :

This annotation allows us to define GraphQL queries and mutations with respect to the annotated class. In this case:

  • createCustomer ( input CustomerInput ) Customer
  • customerById ( input Long ) Customer

Next, we’ll use the same annotation on the Product class to define a

createProducts ( input [ProductInput] ) [Product]

mutation:

Next up is ShoppingCart. We’ll be using the @EntityCollectionApi(...) annotation this time:

This annotation allows us to define GraphQL queries and mutations with respect to the annotated Collection type field. In this case:

  • associateProductsWithShoppingCart (
    owner ShoppingCartInput, input [ProductInput] ) [Product]
  • removeProductsFromShoppingCart (
    owner ShoppingCartInput, input [ProductInput] ) [Product]

The associatePreExistingOnly = true flag denotes that only preexisting Product objects are allowed as input to the associateProductsWithShoppingCart mutation (This makes sense in our case — you can’t add products to a shopping cart if they’re not already in the inventory). If a non existent Product object were to be passed to the associateProductsWithShoppingCart mutation an exception would be thrown, terminating and rolling back the operation.

Last but not least, customers need to check out and complete their purchase after filling up their shopping carts. To do this, we’ll once again use the @WithCrudEndpoints(...) annotation:

This will create a

createCustomerOrder ( input CustomerOrderInput ) CustomerOrder

mutation.

The only requirement now left to complete is the customer checkout logic. As briefly mentioned above, when a customer checks out by creating a new CustomerOrder, the following should happen:

  1. The products in their shopping cart are to be associated with the new CustomerOrder object.
  2. The prices of these products are added up to calculate the subtotal.
  3. The shopping cart is emptied (all products are disassociated).
  4. The products are marked as archived in order to remove them from the available inventory.

In order to apply the required logic to the createCustomerOrder mutation, we create a bean class which we’ll call CustomerOrderApiHooks. This class will implement the ApiHooks<CustomerOrder> interface, and override the preCreate method. ApiHooks is an interface we can implement in order to inject custom logic before and after CRUD operations.

CustomerOrderApiHooks

And that’s it, all that’s left now is to see it in action:

Seth Myers at tenor

Thanks for reading! In this demo we’ve covered some some of the basics of Apifi. Feel free to check out the github repo and full documentation here.

--

--

David Finson
The Startup

Exploring the depths of software engineering, from fintech startup founding to enterprise-grade product development and open-source contributions.