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.
29. November 2018:

Crnk 2.10 is available with support for a new simplified REST API endpoint next to JSON:API. They are very similar in nature. But the new one trades the normalization for a bit more simplicity, facilitating client development when complex data structures are not necessary. Further, two default properties have changed to ease development of new applications. Historically, they have been disabled to maintain 100% backward-compatibility, but more and more caused issues in newer applications. Make sure to familiarize yourselves with those to changes in case of an upgrade. For more information see here.

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 {

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

	private Map projects = new HashMap<>();

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

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

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

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