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.
28. October 2018:

Crnk 2.9 is available with support for faceted search, QuerySpec improvements and many smaller, incremental improvements. For more information see here.

Get Started 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 examples and 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<Schedule, Long> {

	@Override
	ScheduleList findAll(QuerySpec querySpec);

	class ScheduleList extends ResourceListBase<Schedule, ScheduleListMeta, ScheduleListLinks> {

	}

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