Code Monkey home page Code Monkey logo

spring-boot-rest-api-helpers's Introduction

spring-boot-rest-api-helpers

Inspired by built-in fake REST data provider react-admin with queries like:

    GET /movies?filter={id: 1} //get movies by id = 1
    GET /movies?filter={id: [1,2]} //get movies by id = 1 or id = 2
    GET /actors?filter={movies: 1, firstName: John} //actors played in movie with id = 1 and their first  name is John
    GET /actors?filter={birthDateGt: 1960}&sort=[id,DESC]&range=[0,100] //actors born later than 1960
    GET /actors?filter={q: %Keanu Re%} //full text search on all text fields
    GET /actors?sort=[firstName,DESC,birthDate,ASC] //sort by multiple fields in case of ties

More Inspiration was drawn from languages like FIQL/RSQL so recently more features were added along with in-memory integration tests, support for non-number primary keys, resulting in a total refactoring of the code and fix of a lot of bugs (there are still some edge cases).

Now it is possible to also do the following (after url-encode of the query part of the url):

    GET /movies?filter={idNot: 1} //get movies with id not equal to 1
    GET /actors?filter={movies: null} //actors that have played in no movie
    GET /actors?filter={moviesNot: null} //actors that have played to a movie
    GET /actors?filter={movies: [1,2]} //actors played in either movie with id = 1, or movie with id = 2
    GET /actors?filter={moviesAnd: [1,2]} //actors played in both movies with id = 1 and id = 2
    GET /actors?filter={moviesNot: [1,2]} //actors played in neither movie with id = 1, nor movie with id = 2
    GET /actors?filter={name: Keanu Ree%} //full text search on specific fields just by the inclusion of one or two '%' in the value

    GET /actors?filter={movies: {name: Matrix}} //actors that have played in movie with name Matrix
    GET /actors?filter={movies: {name: Matrix%}} //actors that have played in movies with name starting with Matrix
    GET /movies?filter={actors: {firstName: Keanu, lastNameNot: Reves}} //movies with actors that firstName is 'Keanu' but lastName is not 'Reves'

    GET /actors?filter=[{firstName: Keanu},{firstName: John}] //actors with firstName  'Keanu' or 'John'
    GET /actors?filter={firstName: [Keanu, John]} //equivalent to the above

    GET /documents?filter={uuid: f44010c9-4d3c-45b2-bb6b-6cac8572bb78} //get document with java.util.UUID equal to f44010c9-4d3c-45b2-bb6b-6cac8572bb78
    GET /libraries?filter={documents: {uuid: f44010c9-4d3c-45b2-bb6b-6cac8572bb78}} //get libraries that contain document with uuid equal to f44010c9-4d3c-45b2-bb6b-6cac8572bb78
    GET /libraries?filter={documents: f44010c9-4d3c-45b2-bb6b-6cac8572bb78} //same as above

The key names are not the ones on the database but the ones exposed by the REST API and are the names of the entity attribute names. Here movies is plural because an Actor has @ManyToMany annotation on List<Movie> movies attribute.

  • Keep in mind that key/value pairs that are in { } are combined by default with AND.
/actors?filter={firstName:'A',lastName:'B'} => firstName = A and lastName = B
  • Values or Objects that contain key/values in [] are combined by default with OR unless the key in front of the [] is ending with 'And'.
/actors?filter={movies: [1,2]} => actors having acted at movies with ids 1 OR 2 
/movies?filter={actors: [{firstName:'A'}, {lastName:'B'}] } => movies having actors with firstName = A OR lastName = B
/actors?filter={moviesAnd: [1,2]} => actors acted at movies with ids 1 AND 2 
/movies?filter={actorsAnd: [{firstName:'A'}, {lastName:'B'}] } => movies having actors with firstName = A AND lastName = B

The above functionality is possible via this simple setup:

@RestController
@RequestMapping("actors")
public class ActorController {

    @Autowired
    private ActorRepository repository;

    @Autowired
    private FilterService<Actor, Long> filterService;

    @GetMapping
    public Iterable<Actor> filterBy(
            @RequestParam(required = false, name = "filter") String filterStr,
            @RequestParam(required = false, name = "range") String rangeStr, 
            @RequestParam(required = false, name="sort") String sortStr) {

        QueryParamWrapper wrapper = QueryParamExtractor.extract(filterStr, rangeStr, sortStr);
        return filterService.filterBy(wrapper, repository, Arrays.asList("firstName", "lastName"));
    }
}

The main important parts include:

  • @ControllerAdvices that wrap Collections in objects {content: []) with paging and number of results information along with Status Codes based on Exceptions thrown and returns 404 in case of null returned from endpoints. Place here additional functionality annotated with @ControllerAdvice and extending the appropriate class depending on your needs.
  • BaseRepository interface that needs to be extended by each of resource Repositories
  • CustomSpecifications does all the magic of Criteria API query generation so that filtering and sorting works along with FilterService that provides some helper methods to the Controller code and helps provide convert the String query params to FilterWrapper so that it can be injected behind the scenes.
  • ObjectMapperProvider that can be used by the Spring Boot Application in case serialization and deserialization need to work through fields instead of Getters and Setters

Installation

For now installation is done through jitpack:

Add this in your pom.xml repositories:

<repositories>
    <repository>
        <id>jitpack.io</id>
        <url>https://jitpack.io</url>
    </repository>
    ...
</repositories>

and add this as a dependency in your pom.xml dependencies:

    <dependency>
        <groupId>com.github.zifnab87</groupId>
        <artifactId>spring-boot-rest-api-helpers</artifactId>
        <version>edb1770</version> <!-- or latest short commit id -->
    </dependency>

Usage

  • Add springboot.rest package in the scanBasePackages at the top of your Spring Boot Application class
@SpringBootApplication(scanBasePackages = {"com.myproject", "springboot.rest"})
  • inject and expose as @Bean the provided ObjectMapperProvider
    @Autowired
    private ObjectMapperProvider objMapperProvider;

    @Bean
    public ObjectMapper objectMapper() {
        return objMapperProvider.getObjectMapper();
    }
  • configure appplication.properties to use snake-case or camelCase for properties in API
spring-boot-rest-api-helpers.use-snake-case = false
  • for each of the Rest API resources create a class XYZ that is annotated with @Entity
  • for each of the Rest API resources create an interface XYZRepository that extends BaseRepository<XYZ,KeyType>
  • for each of the Rest API resources create a class XYZController annotated with @RestController

for more examples see/run the integration tests with mvn -Dtest=filterByTests test

Working Example

For an example of how it can be used along with admin-on-rest (a predecessor of React Admin), see admin-on-rest-demo-java-rest

spring-boot-rest-api-helpers's People

Contributors

jazcarate avatar jdevoo avatar zifnab87 avatar

Watchers

 avatar

Forkers

kis-global

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.