Crnk: JSON API library
Star
News    Documentation    Related Projects

Crank up the development of RESTful applications with Crnk (pronounced Crank). Crnk is an implementation of 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.

3. November 2017: with 2.3.20171103140100 is available with Brave4/Zipkin2 support and a number of bug fixes. For more information see in the news and documentation.
Easy to integrate with frameworks like Spring, JEE, CDI, JAX-RS, Dropwizard, Servlet API.
Long-term support for technologies such as Java 7 and JPA 2.0 to ease enterprise adoption.
Lightweight with only few dependencies of the core libraries, most notably the Jackson library.
JSON API client and server implementation with the possibility of shared, fully type-safe repository interfaces.
Open Source and released under the Apache License, Version 2.0. license. Suitable for both open source and commercial projects.
Modular design to choose and extend the feature set through a Module API.
Mobile friendly. Fetch complex object graphs in a single request with JSON API inclusions. Fetch partial objects with JSON API sparse field sets. Use together with the popular OkHttp library on Android devices.
Typescript friendly. Generate Typescript interfaces to access your repositories and resources in a type-safe manner.
Expose any JPA entity as JSON API resource with out-of-the-box sorting, filtering, paging and CRUD support without any implementation work. Or further map your entities to DTOs.
Standardized error handling with support for JSR-303 Bean Validation and a variety of other standard Java exception types.
Atomically insert, update and delete multiple resources with JSON Patch.
Integrate into Zipkin to trace incoming and outgoing requests.
Up-to-date documentation with Asciidoc.
Secure your repositories on repository, resource and field level.
Support for Angular development with @crnk/angular-ngrx.
Focus on quality with continuous releases and extensive test coverage.

Coverage Status.

Extensive meta model of your repositories available as JSON API repositories for the purpose of documentation and UI automation.

Example applications

Checkout the various example applications in crnk-examples. To start the spring boot application (the most advanced one) checkout crnk-framework and run:

gradlew :crnk-examples:spring-boot-example:run
		

A number of URLs to try:

http://127.0.0.1:8080/ JSON Home document provided by crnk-home listing all repositories.
http://127.0.0.1:8080/browse/ crnk-ui allowing to browse all repositories.
http://127.0.0.1:8080/projects Simple in-memory repository (PersonRepositoryImpl.java).
http://127.0.0.1:8080/schedule ScheduleEntity JPA entity exposed as repository with crnk-jpa. See ModuleConfig.java.
http://127.0.0.1:8080/schedule?filter[name]
[GT]=schedule1&page[limit]=3&sort=-name
Sorting, filtering and pagination. Notice the total resource count in the meta data and the various pagination links.
http://127.0.0.1:8080/scheduleDto ScheduleEntity mapped to ScheduleDto and exposed as repository. Notice the additional computed attribute upperName. For the setup checkout ModuleConfig.java.
http://127.0.0.1:8080/meta/resource Meta data of all resources provided by crnk-meta. Have a look also at the relationships, such as to the attributes.

Have a look at the console when issuing requests. crnk-brave with a log reporter is used for tracing.

Setup in 5 Minutes

The following gives a brief example of how to setup Crnk with JAX-RS and CDI. For more information have a look at the documentation and join us on Gitter and GitHub!

Add crnk-core together with the CDI and JAX-RS integrations to your classpath:
compile 'io.crnk:crnk-core:${version}'
compile 'io.crnk:crnk-cdi:${version}'
compile 'io.crnk:crnk-rs:${version}'
					

Setup a JAX-RS application and add the CrnkFeature. In this example a default page size and some meaningful Jackson settings are further configured.

@ApplicationPath("/api")
@Singleton
public class DemoApplication extends Application {

	private static final Long DEFAULT_PAGE_SIZE = 20L;

	@Override
	public Set<Object> getSingletons() {
		CrnkFeature crnk = new CrnkFeature();
		crnk.setDefaultPageLimit(DEFAULT_PAGE_SIZE);

		ObjectMapper objectMapper = crnk.getObjectMapper();
		objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
		objectMapper.findAndRegisterModules();
		objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

		return new HashSet<>(Arrays.asList(crnk));
	}
}
					
The actual data objects known as resource in JSON API terminology looks like:
@JsonApiResource(type = "schedules")
public class Schedule {

	@JsonApiId
	private Long id;

	private String name;

	public Long getId() {
		return id;
	}

	public Schedule setId(Long id) {
		this.id = id;
		return this;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

					
Specifying an interface for your repository is an optional step, but can be quite convient when working on the client-side (like for testing). This particular example further specifies the structure of links and meta data attached to the actual data.
public interface ScheduleRepository extends ResourceRepositoryV2 {

	@Override
	ScheduleList findAll(QuerySpec querySpec);

	class ScheduleList extends ResourceListBase {

	}

	class ScheduleListLinks extends DefaultPagedLinksInformation implements LinksInformation {

		private String someLink = "http://...";

		public String getSomeLink() {
			return someLink;
		}

		public void setSomeLink(String someLink) {
			this.someLink = someLink;
		}
	}

	class ScheduleListMeta implements MetaInformation {

		private String someMeta = "value";

		public String getSomeMeta() {
			return someMeta;
		}

		public void setSomeMeta(String someMeta) {
			this.someMeta = someMeta;
		}
	}
}
					
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.

@ApplicationScoped
public class ScheduleRepositoryImpl extends ResourceRepositoryBase<Schedule, Long> implements ScheduleRepository {

	private static Map<Long, Schedule> schedules = new HashMap<>();

	public ScheduleRepositoryImpl() {
		super(Schedule.class);
	}

	public static void clear() {
		schedules.clear();
	}

	@Override
	public ScheduleList findAll(QuerySpec querySpec) {
		ScheduleList list = new ScheduleList();
		list.addAll(querySpec.apply(schedules.values()));
		list.setLinks(new ScheduleListLinks());
		list.setMeta(new ScheduleListMeta());
		return list;
	}

	@Override
	public <S extends Schedule> S save(S entity) {
		schedules.put(entity.getId(), entity);
		return null;
	}

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

Roadmap