JSON:API with Crnk
Crank up the development
of resource-oriented APIs.
Learn more in the examples and documentation.
Crnk is a native resource-oriented rest library where resources and relationships are first class citizens and not just path mappings on methods. This simplifies development and opens up many, powerful new possibilities.
Crnk follows the JSON:API specification and recommendations in Java to facilitate building RESTful applications. To quote the specification:

By following shared conventions, you can increase productivity, take advantage of generalized tooling, and focus on what matters: your application.

All batteries included: model your application as resources and relationships and implement the repositories to access them. Crnk will take care of everything else from low-level REST protocol details to resource linking and error handling. In the progress, the application gains a rich, discoverable API with sorting, filtering, paging, HATEOAS and more.
14. April 2019:

With 3.0.20190414162254-BETA a first beta of the next major version is available! There have been many incremental improvements to the code base over the past year. In particular the relationship handling has been automated in a number of ways. 3.0 has taken the features and learnings from this time and improves upon some of the configuration defaults. This in turn allows to setup resources and relationships more simply, more quickly and with fewer lines of code. A variety of new features complement the release, most notably the generation of Asciidoc documentation and a type-safe query API. Please provide feedback. Further beta releases will bring more refinement.

Get Started in 5 Minutes

The following gives a brief example of how to setup Crnk with Spring Boot For more information have a look at the examples and documentation and join us on Gitter and GitHub!

Add the crnk-bom to your dependency management, for example:
apply plugin: 'io.spring.dependency-management'
dependencyManagement {
    imports {
        mavenBom 'org.springframework.boot:spring-boot-dependencies:2.1.0.RELEASE'
        mavenBom "io.crnk:crnk-bom:${CRNK_VERSION}"
    }
}
                    
And add the following dependencies to your classpath:
compile 'io.crnk:crnk-setup-spring-boot'
compile 'io.crnk:crnk-format-plain-json'
compile 'io.crnk:crnk-home'
compile 'org.springframework.boot:spring-boot-starter-web'
					

Setup a Spring Boot application:

@Configuration
@SpringBootApplication
public class MinimalSpringBootApplication {

	public static void main(String[] args) {
		SpringApplication.run(MinimalSpringBootApplication.class, args);
		System.out.println("visit http://127.0.0.1:8080/ in your browser");
	}
}
					
The actual data objects known as resource in JSON:API terminology looks like:
@JsonApiResource(type = "projects")
public class Project {

	@JsonApiId
	private Long id;

	@JsonProperty
	private String name;

	public Project() {
	}

	public Project(Long id, String name) {
		this.id = id;
		this.name = name;
	}

	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;
	}
}


					
The actual implementation of a JSON:API repository. This example stores all data in-memory. Notice the QuerySpec.apply to do sorting, filtering and patching in-memory. More advanced use cases will translate the QuerySpec to a native query of the underlying data store. The @ApplicationScoped will lead for the repository to get picked up by the crnk-cdi integration.

@Component
public class ProjectRepositoryImpl extends ResourceRepositoryBase<Project, Long> {

	private static final AtomicLong ID_GENERATOR = new AtomicLong(124);

	private Map<Long, Project> projects = new HashMap<>();

	public ProjectRepositoryImpl() {
		super(Project.class);
	}

	@Override
	public synchronized void delete(Long id) {
		projects.remove(id);
	}

	@Override
	public synchronized <S extends Project> S save(S project) {
		if (project.getId() == null) {
			project.setId(ID_GENERATOR.getAndIncrement());
		}
		projects.put(project.getId(), project);
		return project;
	}

	@Override
	public synchronized ResourceList<Project> findAll(QuerySpec querySpec) {
		return querySpec.apply(projects.values());
	}
}