115
Crnk Documentation

Crnk Documentation · • Resources hold data as value fields, meta information and link information. • Relationships establish links between resources. • resource repositories

  • Upload
    others

  • View
    2

  • Download
    0

Embed Size (px)

Citation preview

  • Crnk Documentation

  • Table of Contents1. Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  2

    2. Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  2

    3. Setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  4

    3.1. Requirements. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  4

    3.2. Repository. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  4

    3.3. BOM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  5

    3.4. Logging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  5

    3.5. Integration with JAX-RS. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  6

    3.5.1. CrnkFeature . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  6

    3.5.2. Exception mapping for JAX-RS services. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  7

    3.5.3. Use JSON API format with JAX-RS services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  7

    3.5.4. JAX-RS service interoperability . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  8

    3.6. Integration with Servlet API. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  9

    3.6.1. Integrating using a Servlet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  9

    3.6.2. Integrating using a filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  10

    3.7. Integration with Spring and String Boot. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  10

    3.8. Integration with Vert.x . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  11

    3.9. Tomcat Setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  12

    3.10. Discovery with CDI. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  13

    3.11. Discovery with Guice. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  13

    3.12. Discovery with Spring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  13

    3.13. Discovery without a dependency injection framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  13

    3.14. No Discovery . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  14

    3.15. Implement a custom discovery mechanism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  14

    3.16. CrnkBoot. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  15

    3.17. Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  16

    4. Resource . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  17

    4.1. JsonApiResource . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  17

    4.2. JsonApiId . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  19

    4.3. JsonApiRelation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  19

    4.4. JsonApiRelationId. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  21

    4.5. JsonApiMetaInformation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  23

    4.6. JsonApiLinksInformation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  23

    4.7. Jackson annotations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  24

    4.8. Nested Resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  25

    5. Repositories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  27

    5.1. ResourceRepositoryV2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  27

    5.2. Query parameters with QuerySpec . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  31

  • 5.2.1. API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  31

    5.2.2. Filtering. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  32

    5.2.3. Sorting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  33

    5.2.4. Pagination. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  34

    5.2.5. Sparse Fieldsets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  35

    5.2.6. Inclusion of Related Resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  35

    5.2.7. URL Mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  36

    5.3. RelationshipRepositoryV2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  37

    5.3.1. Example. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  38

    5.3.2. RelationshipMatcher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  38

    5.3.3. ForwardingRelationshipRepository . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  39

    5.3.4. BulkRelationshipRepositoryV2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  39

    5.4. ResourceList. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  40

    5.5. Error Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  41

    5.5.1. Throwing an exception… . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  41

    5.5.2. …and mapping it to JSON API response. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  41

    5.6. Meta Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  43

    5.7. Links Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  43

    5.8. Inheritance. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  43

    5.8.1. Inheritance with a repository per type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  43

    5.8.2. Inheritance with a single repository per type hierarchy . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  44

    5.9. Payload Size Optimizations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  44

    5.10. Repository Decoration. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  44

    5.11. ResourceFieldContributor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  45

    5.12. @JsonApiExposed. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  47

    6. Client . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  47

    6.1. Setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  47

    6.2. Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  48

    6.3. URL handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  48

    6.4. Modules. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  48

    6.5. Type-Safety. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  49

    6.6. JAX-RS interoperability . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  50

    6.7. HTTP customization. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  52

    7. Reactive Programming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  52

    7.1. Servlet Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  53

    7.2. Interacting with traditional repositories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  56

    7.3. Roadmap and Limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  56

    8. Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  57

    8.1. Authentication. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  57

    8.2. Resource-based Access Control with the SecurityModule . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  58

    8.3. Role-based Access Control with ResourceFilter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  59

  • 8.4. Dataroom Access Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  59

    8.5. Adapt User Interfaces based on Authorizations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  60

    8.5.1. ResourcePermissionInformation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  60

    8.5.2. Home and Meta Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  60

    8.6. Provide Authentication Information to the User . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  60

    8.7. Exception Mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  61

    8.8. (Potential) Future Work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  61

    9. Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  62

    9.1. JPA Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  62

    9.1.1. JPA Module Setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  62

    9.1.2. JPA Entity Setup. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  65

    9.1.3. JPA Setup with Spring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  65

    9.1.4. Pagination. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  66

    9.1.5. Criteria API and QueryDSL. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  66

    9.1.6. Customizing the JPA repository . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  66

    9.1.7. DTO Mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  67

    9.2. JSR 303 Validation Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  69

    9.3. Tracing with Zipkin/Brave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  70

    9.4. Meta Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  70

    9.4.1. Setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  71

    9.4.2. Examples. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  71

    9.4.3. Identifiers for Meta Elements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  73

    9.4.4. Extending the Meta Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  74

    9.5. Home Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  74

    9.6. Operations Module. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  75

    9.7. UI Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  79

    9.8. Activiti Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  80

    9.8.1. Setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  80

    9.8.2. Example application. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  82

    9.8.3. Limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  85

    9.9. Spring Modules and Auto Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  85

    9.9.1. Spring MVC Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  85

    9.9.2. Spring Cloud Sleuth Module. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  85

    9.9.3. Spring Security Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  85

    9.9.4. JPA Module Auto Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  86

    9.9.5. Validation Module Auto Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  88

    9.9.6. UI Module Auto Configuration. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  88

    9.9.7. Operations Module Auto Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  88

    9.9.8. Meta Module Auto Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  88

    10. Module Development . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  88

    10.1. Request Filtering. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  88

  • 10.2. Resource Filtering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  89

    10.3. Filter Modifications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  89

    10.4. Filter Priority. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  89

    10.5. Access to HTTP layer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  90

    10.6. Module Extensions and dependencies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  90

    10.7. Integrate third-party data stores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  90

    10.8. Implement a custom discovery mechanism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  91

    10.9. Let a module hook into the Crnk HTTP client implementation . . . . . . . . . . . . . . . . . . . . . . . . . .  91

    10.10. Implement a custom integration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  91

    10.11. Create repositories at runtime . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  91

    10.11.1. Implementing repositories dynamically at runtime . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  92

    10.11.2. Registering repositories at runtime . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  94

    10.12. Discovery of Modules by CrnkClient . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  94

    11. Generation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  95

    11.1. Typescript. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  95

    11.1.1. Setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  96

    11.1.2. Error Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  99

    12. Angular Development with ngrx . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  99

    12.1. Feature overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  99

    12.2. Bulk support with JSON Patch. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  100

    12.3. Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  100

    12.4. Form Binding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  103

    12.4.1. Setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  104

    12.4.2. Updating Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  106

    12.4.3. Validation and Error handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  107

    12.4.4. Roadmap and Open Issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  107

    12.5. Table Binding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  107

    12.5.1. Setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  108

    12.5.2. Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  109

    12.6. Meta Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  109

    13. FAQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  109

  • Crnk is a native resource-oriented rest library where resources, theirrelationships and repositories are the main building blocks. In that regard Crnkdiffer quite dramatically from most REST library out there and opens up manynew possibilities. It allows you to rapidly build REST APIs without having toworry about lower protocol details and lets you instead focus on what matters:your application. On the HTTP/REST layer it follows the JSON API specificationand recommendations. JSON API and Crnk come with support for:

    • client and server implementation.

    • standardized url handling such as /api/persons?filter[title]=John and /api/persons/{id}

    • sorting, filtering, paging of resources

    • attaching link and meta information to resources.

    • inserting, updating and deleting of resources.

    • support to request complex object graphs in a single request with JSON API inclusions.

    • support for partial objects with sparse field sets.

    • atomically create, update and delete multiple with jsonpatch.com.

    • a flexible module API to choose and extend the feature set of Crnk.

    • eased testing with the client implementation providing type-safe stubs to access serverrepositories.

    • repositories providing runtime/meta information about Crnk to implement, for example,documentation and UI automation.

    • generation of type-safe client stubs (currently Typescript as target language implemented)

    • binding of Angular components with ngrx-json-api to Crnk endpoints.

    • filters and decorates to intercept and modify all aspects of an application and Crnk.

    • a module API to build and plugin-in reusable Crnk modules. Crnk comes with number of such(optional) modules to integrate with third-party libraries and frameworks.

    Crnk is small, modular and lightweight. It integrates well with many popular frameworks and APIs:

    • CDI: resolve repositories and extensions with CDI.

    • Spring: run Crnk with Spring, including support for Spring Boot, ORM, Security and Sleuth.

    • Reactor: for support of reactive programming.

    • Servlet API: run Crnk as servlet.

    • JAXRS: run Crnk as feature.

    • JPA: expose entities as JSON API resources.

    • bean validation: properly marshal validation and constraints exceptions.

    • Zipkin, Brave, Spring Sleuth: trace all your calls.

    While Crnk follows the JSON API specification, it is not limited to that. Have a look at the

    1

    http://jsonpatch.com/https://github.com/abdulhaq-e/ngrx-json-api

  • http://www.crnk.io/[roadmap> for more information.

    1. ExamplesCrnk comes with various examples. There is a main example application in a dedicated repositoryavailable from crnk-example. It shows an end-to-end example with Crnk, Angular, Spring Bootand ngrx-json-api.

    And there are various simpler example applications that show the integration of Crnk into variousframeworks like:

    • spring-boot-example

    • spring-boot-minimal-example showcasing a minimal setup of Crnk with Spring Boot.

    • spring-boot-microservice-example showcasing how to connect two separate JSON API endpointsthrough a relationship with crnk-client.

    • wildfly-example

    • dropwizard-mongo-example

    • dropwizard-simple-example

    • jersey-example

    • dagger-vertx-example showcasing a very lightweight setup with Dagger, Vert.x, Proguard,OpenJ9 VM having a small size, startup time and memory footprint.

    available from crnk-examples.

    The impatient may also directly want to jump to ResourceRepositoryV2, but it is highlyrecommended to familiarize one self with the architecture and annotations as well. Unliketraditional REST libraries, Crnk comes with a lot of built-in semantics that allow to automateotherwise laborious tasks.

    2. ArchitectureResources, relationships and repositories are the central building blocks of Crnk:

    • Resources hold data as value fields, meta information and link information.

    • Relationships establish links between resources.

    • resource repositories and relationship repositories implement access to resources andrelationships.

    A Crnk application models its API as resources and relationships. It is not uncommon forapplications to also have a few remaining service-oriented APIs. Later chapters will show how Crnkintegrates with other libraries like JAX-RS or Spring MVC to achieve this. Based on such a model, anapplication implements repositories to provide access trough that model.

    2

    http://www.crnk.io/https://github.com/crnk-project/crnk-examplehttps://github.com/crnk-project/crnk-framework/tree/master/crnk-examples/

  • Currently implemented is the JSON API specification to access that model as part of the crnk-coreproject. The JSON API specification provide all the essential building blocks like sorting, filtering,paging, document formats, linking and error handling to access resources and relationships. Butother implementations, such as GraphQL or different kinds of REST/JSON APIs, are possible as well.With JSON API, an incoming request is processed as follows:

    • A Crnk interceptor is called from the underlying framework. This might be, for example, from aServlet environment, JAX-RS or Spring MVC.

    • The request is deserialized to Crnk data structures like Document, Resource, ResourceIdentifier orErrorData.

    • The type of request is determined: whether it is a POST, PATCH, GET or DELETE request and whetherit is a resource or relationship request.

    • The request is forwarded to the appropriate repository.

    • GET requests can ask for inclusions of further, related resources. Result resources will thentrigger further requests to other repositories. This can happen either manually from within theinitially called repository or automatically by Crnk (explained in detail in later chapters).

    • The result resources are merged into response document and returned to the underlyingframework for delivery. Possible exceptions are handled as and mapped as well.

    A benefit of Crnk is its flexibility how to set all this up:

    • Resources and relationships can be defined with simple Java Beans and annotations orprogrammatically. The later allows virtually any kind of customization at runtime, like settingup repositories dynamically. One example is crnk-jpa that is able to expose any JPA entity asJSON API resource.

    • Resources and relationships can be entirely decoupled concerns. For example, an independentrelationship repository C can introduce a relationship between a resource a and resource bimplemented by resource repositories A and B. For example, an audit component could interceptand log any modifications. Access to it is provided by introducing a new relationship historyonto each resource.

    • Information about resources, relationships and repositories are available trough a Java API andJSON API endpoint.

    • Filters and decorators allow to intercept and modify every step along the request chain. Thiscan be used, for example, to enforce security, collect metrics or do tracing.

    To facilitate the setup, Crnk comes with a small module API. Independent functionality can beassembled as module and then just included into the application. Crnk comes with a number ofmodules on its own:

    • crnk-jpa

    • crnk-validation

    • crnk-operations

    • various Spring modules

    • …

    3

  • Such modules can make use of filters, decorators, decoupled resources and relationships andvarious other features. Everything together fosters the use of the composite pattern where largerapplications can be assembled from smaller parts, some from third-party modules and othersmanually implemented.

    The part of crnk-core taking care of all this is denoted as the engine. The subsequent chaptersexplain how to setup and use Crnk.

    3. SetupCrnk integrates well with many popular framework. The example applications outline variousdifferent possible setups. But application are also free to customize their setup to their liking. Thereare three main, orthogonal aspects of Crnk that need configuration:

    1. The integration into a web framework like JAXRS or the Servlet API to be able to processrequests.

    2. The discovery of repositories, modules, exception mappers, etc. Usually by a dependencyinjection framework. But can also happen manually.

    3. The selection of third-party modules to reuse. For a list of modules provided by Crnk see the chapter.

    The subsequent sections explain various possibilities resp. how to implement a custom one. The[reactive] chapter further outlines how to setup Crnk in an asynchronous/reactive setting.

    3.1. RequirementsCrnk library requires minimum Java 8 (as of Crnk 2.4) to build and run. In the future it will comewith support for both the current major Java releases (9, 10, 11, etc.) and the current long-termsupport version that gets released every three years.

    3.2. RepositoryCrnk Maven artifacts are available from Bintray/JCenter.

    https://bintray.com/crnk-project

    In Gradle it looks like:

    repositories {  jcenter()}

    Note that due to performance/reliability issues, releases are only intermittently pushed to MavenCentral. It is highly recommended for project to go with JCenter as well.

    4

    https://bintray.com/crnk-project

  • Stable releases hosted on Bintray/JCenter are also available from:

    https://bintray.com/crnk-project/maven https://dl.bintray.com/crnk-project/maven/

    Most recent builds are available from (for a limited period of time):

    https://bintray.com/crnk-project/mavenLatest https://dl.bintray.com/crnk-project/mavenLatest/

    3.3. BOMWith io.crnk:crnk-bom a Maven BOM is provided that manages the dependencies of all crnkartifacts. In Gradle the setup then looks as follows:

    buildscript {  dependencies {  classpath "io.spring.gradle:dependency-management-plugin:1.0.4.RELEASE"  }}

    gradle.beforeProject { Project project ->  project.with {  apply plugin: 'io.spring.dependency-management'  dependencyManagement {  imports {  mavenBom "io.crnk:crnk-bom:$CRNK_VERSION"  }  }  }}

    The crnk modules can then simply be used without having to specify a version:

    dependencies {  compile 'io.crnk:crnk-rs'  compile 'io.crnk:crnk-setup-spring-boot2'  ...}

    3.4. LoggingCrnk makes use of SLF4J to do logging. Make sure to have the API properly setup. For example bymaking use of Logback or one of the many bridges to other Logging frameworks.

    TIP Set io.crnk to DEBUG if you encounter any issues during setup or later at runtime.

    5

    https://bintray.com/crnk-project/mavenhttps://dl.bintray.com/crnk-project/maven/https://bintray.com/crnk-project/mavenLatesthttps://dl.bintray.com/crnk-project/mavenLatest/

  • 3.5. Integration with JAX-RSCrnk allows integration with JAX-RS environments through the usage of JAX-RS specification. JAX-RS 2.0 is required for this integration. Under the hood there is a @PreMatching filter which checkseach request for JSON API processing. The setup can look as simple as:

    3.5.1. CrnkFeature

    @ApplicationPath("/")  public class MyApplication extends Application {

      @Override  public Set getSingletons() {  CrnkFeature crnkFeature = new CrnkFeature();  return Collections.singleton((Object)crnkFeature);  }  }

    CrnkFeature provides various accessors to customize the behavior of Crnk. A more advanced setupmay look like:

    6

  •   public class MyAdvancedCrnkFeature implements Feature {

      @Inject  private EntityManager em;

      @Inject  private EntityManagerFactory emFactory;

      ...

      @Override  public boolean configure(FeatureContext featureContext) {  // also map entities to JSON API resources (see further below)  JpaModule jpaModule = new JpaModule(emFactory, em, transactionRunner);  jpaModule.setRepositoryFactory(new ValidatedJpaRepositoryFactory());

      // limit all incoming requests to 20 resources if not specified otherwise  DefaultQuerySpecUrlMapper urlMapper = new DefaultQuerySpecUrlMapper();  urlMapper.setDefaultLimit(20L);

      ServiceLocator serviceLocator = ...  CrnkFeature feature = new CrnkFeature();  feature.addModule(jpaModule);  feature.getBoot().setUrlMapper(urlMapper);

      featureContext.register(feature);  return true;  }  }

    Crnk will install a JAX-RS filter that will intercept and process any Crnk-related request.

    Note that depending on the discovery mechanism in use (like Spring or CDI), modules like thisJpaModule can be picked up automatically and do not manual registration.

    3.5.2. Exception mapping for JAX-RS services

    In many cases Crnk repositories are used along regular JAX-RS services. In such scenarios it can beworthwhile if Crnk repositories and JAX-RS services make use of the same exception handling andresponse format. To make use of the JSON API resp. Crnk exception handling in JAX-RS services, onecan add the JsonapiExceptionMapperBridge to the JAX-RS application. The constructor ofJsonapiExceptionMapperBridge takes CrnkFeature as parameter.

    For an example have a look at the next section which make use of it together withJsonApiResponseFilter.

    3.5.3. Use JSON API format with JAX-RS services

    Similar to JsonapiExceptionMapperBridge in the previous section, it is possible for JAX-RS services to

    7

  • return resources in JSON API format with JsonApiResponseFilter. JsonApiResponseFilter wrapsprimitive responses with a data object; resource objects with data and included objects. Theconstructor of JsonApiResponseFilter takes CrnkFeature as parameter.

    To determine which JAX-RS services should be wrapped, JsonApiResponseFilter checks whether the@Produce annotation delivers JSON API. The produce annotation can be added, for example, to theclass:

    ScheduleRepository.java

    @Path("schedules")@Produces(HttpHeaders.JSONAPI_CONTENT_TYPE)

    And the JAX-RS application setup looks like:

    JsonApiResponseFilterTestBase.java

      @ApplicationPath("/")  class TestApplication extends ResourceConfig {

      TestApplication(JsonApiResponseFilterTestBase instance, booleanenableNullResponse) {  instance.setEnableNullResponse(enableNullResponse);

      property(CrnkProperties.RESOURCE_SEARCH_PACKAGE, "io.crnk.rs.resource");  property(CrnkProperties.NULL_DATA_RESPONSE_ENABLED,Boolean.toString(enableNullResponse));

      CrnkFeature feature = new CrnkFeature();  feature.addModule(new TestModule());

      register(new JsonApiResponseFilter(feature));  register(new JsonapiExceptionMapperBridge(feature));  register(new JacksonFeature());

      register(feature);  }  }

    Note that:

    • CrnkProperties.NULL_DATA_RESPONSE_ENABLED determines whether null responses should bewrapped as JSON API responses.

    • Make use of proper service discovery instead of CrnkProperties.RESOURCE_SEARCH_PACKAGE in realapplications.

    3.5.4. JAX-RS service interoperability

    It is possible to implement repositories that host both JAX-RS and JSON-API methods to complement

    8

  • JSON API repositories with non-resource based services. Have a look at the Crnk Client chapter foran example.

    3.6. Integration with Servlet APIThere are two ways of integrating crnk using Servlets:

    • Adding an instance of CrnkServlet

    • Adding an instance of CrnkFilter

    3.6.1. Integrating using a Servlet

    There is a CrnkServlet implementation allowing to integrate Crnk into a Servlet environment. It canbe configured with all the parameters outlined in the subsequent sections. Many times applicationwill desire to do more advanced customizations, in this case one can extends CrnkServlet and getaccess to CrnkBoot. The code below shows a sample implementation:

    SampleCrnkServlet.java

    public class SampleCrnkServlet extends CrnkServlet {

      @Override  protected void initCrnk(CrnkBoot boot) {  // do your configuration here  }}

    The newly created servlet must be added to the web.xml file or to another deployment descriptor.The code below shows a sample web.xml file with a properly defined and configured servlet:

          SampleCrnkServlet  io.crnk.servlet.SampleCrnkServlet      crnk.config.core.resource.domain  http://www.mydomain.com        SampleCrnkServlet  /api/v1/ *   

    init-param allow to pass configuration flags to Crnk. For a list of properties see here.

    9

  • 3.6.2. Integrating using a filter

    Integrating Crnk as a Servlet filter works in a very similar fashion as for servlets:

    SampleCrnkFilter.java

    public class SampleCrnkFilter extends CrnkFilter {

      @Override  protected void initCrnk(CrnkBoot boot) {  // do your configuration here  }}

    The newly created filter must be added to web.xml file or other deployment descriptor. A code belowshows a sample web.xml file with properly defined and configured filter

          SampleCrnkFilter  io.crnk.servlet.SampleCrnkFilter      crnk.config.core.resource.domain  http://www.mydomain.com     

    init-param allow to pass configuration flags to Crnk. For a list of properties see here.

    3.7. Integration with Spring and String BootCrnk provides with:

    • io-crnk:crnk-setup-spring support for plain Spring 4 and 5.

    • io-crnk:crnk-setup-spring-boot1 support for Spring Boot 1.x. This module is considered beingdeprecated and will be removed in the future.

    • io-crnk:crnk-setup-spring-boot2 support for Spring Boot 2.x.

    There is a CrnkCoreAutoConfiguration in crnk-setup-spring-boot2 that outlines the basic setup thatcan easily be applied to a Spring-only setup without Spring Boot using crnk-setup-spring:

    • It uses the CrnkFilter servlet filter to fetch the requests.

    • Service discovery is performed with SpringServiceDiscovery using the SpringApplicationContext.

    10

  • There are further auto configurations that automatically setup various Crnk modules. And thereare also further integrations into Spring (like for RestTemplate and Spring Security). Moreinformation is available in Spring modules.

    The web integration can be customized for Spring Boot setups with the subsequent properties:

    application.properties

    crnk.enabled=truecrnk.domain-name=http://localhost:8080crnk.path-prefix=/apicrnk.default-page-limit=20crnk.max-page-limit=1000crnk.allow-unknown-attributes=falsecrnk.return404-on-null=true

    See CrnkCoreProperties for more information. The Spring modules and their auto configurationsmake further configuration properties available.

    3.8. Integration with Vert.x

    CAUTIONReactive programming support has been introduced in Crnk 2.6 and is stillconsidered experimental with some limitations. Please also provide feedbackabout this Vert.x integration.

    Crnk integrates with Vert.x RxJava 2 using crnk-reactive and crnk-setup-vertx. More informationabout reactive programming is available here. To make use of Crnk with Vert.x, make sure youhave the following dependencies specified:

      compile 'io.crnk:crnk-setup-vertx'  compile 'io.vertx:vertx-rx-java2'

    An example Vert.x vehicle may then look like:

    11

    https://github.com/crnk-project/crnk-framework/blob/master/crnk-setup/crnk-setup-spring-boot2/src/main/java/io/crnk/setup/spring/boot/core/CrnkCoreProperties.java

  • CrnkVerticle.java

    public class CrnkVerticle extends AbstractVerticle {

      private static final Logger LOGGER = LoggerFactory.getLogger(CrnkVerticle.class);

      public ReactiveTestModule testModule = new ReactiveTestModule();

      private int port;

      public CrnkVerticle(int port) {  this.port = port;  }

      @Override  public void start() {  HttpServer server = vertx.createHttpServer();

      CrnkVertxHandler handler = new CrnkVertxHandler((boot) -> {  boot.addModule(HomeModule.create());  boot.addModule(testModule);  });

      server.requestStream().toFlowable()  .flatMap(request -> handler.process(request))  .subscribe((response) -> LOGGER.debug("delivered response {}",response), error -> LOGGER.debug("error occured", error));  server.listen(port);  }}

    CrnkVertxHandler holds the Crnk setup. Its constructor takes a Consumer that allows thecustomization of Crnk. The example makes use of it to register two modules.CrnkVertxHandler.process is the main method that allows to process HttpServerRequest objects ofVert.x.

    3.9. Tomcat SetupThere is a bit of a controversy about which characters to encode or not encode in URLs based onRFC 7230 and RFC 3986. JSON API is affected in that regard due to the use of [ and ]. Browservendors have yet to endorse those RFCs. But unfortunately, Tomcat already started to enforce theRFCs from their side. As such it is useful to relax the [ and ] characters to simplify development withJSON API, like entering URLs manually in the browser. For this purpose relaxedPathChars can be setto [], for more information see:

    https://stackoverflow.com/questions/41053653/tomcat-8-is-not-able-to-handle-get-request-with-in-query-parameters

    12

    https://stackoverflow.com/questions/41053653/tomcat-8-is-not-able-to-handle-get-request-with-in-query-parametershttps://stackoverflow.com/questions/41053653/tomcat-8-is-not-able-to-handle-get-request-with-in-query-parameters

  • The Spring Boot auto configuration already does this out-of-the-box.

    IMPORTANTThere is no weakened security out of this as long as parameters are not usedin some obscure fashion.

    3.10. Discovery with CDITo enable CDI support, add io.crnk:crnk-cdi to your classpath. Crnk will then pickup theCdiServiceDiscovery implementation and use it to discover its modules and repositories. Modules,repositories, etc. will then be picked up if they are registered as CDI beans.

    By default Cdi.current() is used to obtain a BeanManager. The application may also make use ofCdiServiceDiscovery.setBeanManager(…) to set a custom one. The various integrations likeCrnkFeature provide a setServiceDiscovery method to set a customized instance.

    WARNINGCdi.current() has shown to be unreliable in some cases when doing EARdeployment. In such cases it is highly recommended to set the BeanManagermanually.

    3.11. Discovery with GuiceA GuiceServiceDiscovery implementation is provided. The various integrations like CrnkFeatureprovide a setServiceDiscovery method to set the instance. For an example have a look at thedropwizard example application (https://github.com/crnk-project/crnk-framework/tree/master/crnk-examples/dropwizard-simple-example).

    3.12. Discovery with SpringThe Spring integration comes with a SpringServiceDiscovery that makes use of the SpringApplicationContext to discover beans.

    3.13. Discovery without a dependency injectionframework

    WARNINGThis mechanism is considered to be rather deprecated and a lightweightdependency injection framework like guice or the setup of manual modules isrecommended instead.

    If no dependency injection framework is used, Crnk can also discover beans on its own. For thispurpose, the org.reflections:reflections library has to be added to the classpath and theCrnkProperties.RESOURCE_SEARCH_PACKAGE be defined. In JAX-RS this may look like:

    13

    https://github.com/crnk-project/crnk-framework/tree/master/crnk-examples/dropwizard-simple-examplehttps://github.com/crnk-project/crnk-framework/tree/master/crnk-examples/dropwizard-simple-example

  • @ApplicationPath("/")  public class MyApplication extends Application {

      @Override  public Set getSingletons() {  CrnkFeature crnkFeature = new CrnkFeature();  crnkFeature.getBoot().setServiceLocator(...);  return Collections.singleton((Object)crnkFeature);  }

      @Override  public Map getProperties() {  Map map = new HashMap();  map.put(CrnkProperties.RESOURCE_SEARCH_PACKAGE, "com.myapplication.model")  return map;  }  }

    A JsonServiceLocator service locator can be provided to control the instatiation of object. By defaultthe default constructor will be used. The CrnkProperties.RESOURCE_SEARCH_PACKAGE property is passedto define which package should be searched for beans. Multiple packages can be passed byspecifying a comma separated string of packages i.e.com.company.service.dto,com.company.service.repository. It will pick up any public non-abstractclass that makes use of Crnk interfaces, like repositories, exception mappers and modules.

    3.14. No DiscoveryIt is also possible to make use of no discovery mechanism at all. In this case it is still possible to addrepositories and other features through modules. A simple example looks like:

    DropwizardService

      SimpleModule module = new SimpleModule("example");  module.addRepository(new ProjectRepository());

      CrnkFeature crnkFeature = new CrnkFeature();  crnkFeature.addModule(module);

      environment.jersey().register(crnkFeature);

    Have a look at the various [modules] chapters for more information.

    3.15. Implement a custom discovery mechanismApplication can bring along there own implementation of ServiceDiscovery. For more informationsee here.

    14

  • 3.16. CrnkBootCrnkBoot is a class shared among all the different integrations that takes care of setting up andstarting Crnk. Every integration will provide access to it:

    • CrnkFeature.getBoot() for JAX-RS.

    • @Autowired CrnkBoot boot for Spring.

    • CrnkServlet.getBoot() or CrnkServlet.initBoot(…) in case of a subclass.

    • CrnkVertxHandler.getBoot() for Vert.x.

    CrnkBoot allows for virtually any kind of customization not directly provided by the integrationitself, such as Spring Boot auto configurations and properties. Some possibilities:

    • getObjectMapper allows access to the used Jackson instance.

    • addModule allows to add a module. See and chapters for more information.

    • setServiceDiscovery sets a custom service discovery mechanism.

    • setPropertiesProvider allows to set how properties are resolved.

    • getQuerySpecDeserializer and setQuerySpecDeserializer allows to reconfigure how parametersare parsed. Note that in some areas JSON API only provides reocmmendations and Crnk followsthose recommendations by default. So depending on your use cases, you may want to configureor implement some aspects differently.

    • setMaxPageLimit allows to set the maximum number of allowed resources that can be fetchedwith a request by limiting pagination.

    • setDefaultPageLimit allows to set a default page limit if none is specified by the request. Highlyrecommended to be used as people frequently browse repositories on there own with a webbrowser and fail to provide pagination. As a result, your entire database may get downloadedand may bring down your servers depending on the datasize.

    • setWebPathPrefix like /api to specify the path from where the JSON API endpoint is available.

    • setUrlMapper to provide a new url mapping implementation to customize how Crnk generateslinks.

    • getResourceRegistry to access the available JSON API resources and repositories.

    • setAllowUnknownAttributes to ignore unknown filter and sort attributes.

    • setAllowUnknownParameters to ignore query parameters not specified by JSON API (filter, sort,etc.).

    IMPORTANT

    Appropriate page limits are vital to protect against denial-of-service attackswhen working with large data sets! Such attacks may not be of maliciousnature, but normal users using a browser and just omitting to specifypagination parameters.

    15

  • 3.17. PropertiesAny of the integrations allows API access to customize Crnk. There are also a number ofconfiguration flags provided by CrnkProperties:

    • crnk.config.core.resource.domain Domain name as well as protocol and optionally port numberused when building links objects in responses i.e. http://crnk.io. The value must not end with /.If the property is omitted, then they are extracted from the incoming request, which shouldwork well for most use cases.

    • crnk.config.web.path.prefix Default prefix of a URL path used in two cases:

    ◦ When building links objects in responses

    ◦ When performing method matching An example of a prefix /api/v1.

    • crnk.config.include.paging.packagingEnabled enables pagination for inclusions. Disabled bydefault. Be aware this may inadvertently enable pagination for included resources when doingpaging on root resources if data structures are cyclic. SeeCrnkProperties.INCLUDE_PAGING_ENABLED fore mor information.

    • crnk.config.lookup.behavior.default specifies the default lookup behavior for relationships. Formore information see @JsonApiRelation.

    • crnk.config.include.behavior with possible values BY_TYPE (default) and BY_ROOT_PATH.BY_ROOT_PATH specifies that an inclusion can only requested as path from the root resource suchas include[tasks]=project.schedule. While BY_TYPE can further request inclusions by typedirectly such as include[tasks]=project&include[projects]=schedule. For simple objectstructures they are semantically the same, but they do differ for more complex ones, like whenmultiple attributes lead to the same type or for cycle structures. In the later case BY_TYPEinclusions become recursive, while BY_ROOT_PATH do not. Note that the use of BY_TYPEoutmatches BY_ROOT_PATH, so BY_TYPE includes everything BY_ROOT_PATH does andpotentially more. For more information see CrnkProperties.INCLUDE_BEHAVIOR.

    • crnk.config.resource.immutableWrite with values IGNORE (default) or FAIL. Determines how todeal with field that cannot be changed upon a PATCH or POST request. For more informationsee CrnkProperties.RESOURCE_FIELD_IMMUTABLE_WRITE_BEHAVIOR.

    • crnk.config.resource.response.return_404 with values true and false (default). Enforces a 404response should a repository return a null value. This is common practice, but not strictlymandated by the JSON API specification. In general it is recommended for repository to throwResourceNotFoundException.

    • crnk.config.serialize.object.links to serialize links as objects. See http://jsonapi.org/format/#document-links. Disabled by default.

    • crnk.config.resource.request.rejectPlainJson whether to reject GET requests withapplication/json accept headers and enforce application/vnd.api+json. Disabled by default.

    • crnk.config.resource.request.allowUnknownAttributes lets Crnk ignore unknown filter and sortparameters. Disabled by default.

    • crnk.config.serialize.object.links determines whether links should be serialized as simplestring (default) or as objects (with a self attribute holding the url).

    • crnk.config.resource.request.rejectPlainJson determines whether Crnk should reject

    16

    http://crnk.iohttp://jsonapi.org/format/#document-linkshttp://jsonapi.org/format/#document-links

  • application/json requests to JSON-API endpoints. Disabled by default. The JSON-APIspecification mandates the use of the application/vnd.api+json MIME-Type. In cases wherefrontends or intermediate proxies prefer the application/json MIME-Type, that type can be sentin the Accept header instead. If an application wants to serve a different response depending onwhether the client’s Accept header contains application/vnd.api+json or application/json, thisoption can be enabled. This *does not affect the payload Content-Type. POST and PATCH requestsmust still use Content-Type: application/vnd.api+json to describe their request body

    4. ResourceA resource as defined by JSON API holds the actual data. The engine part of crnk-core is agnostic tohow such resources are actually implemented (see the [architecture] and [modules] chapters). Thischapter describes the most common way Java Beans and annotations. See here for moreinformation how setup resources and repositories programmatically at runtime.

    4.1. JsonApiResourceIt is the most important annotation which defines a resource. It requires type parameter to bedefined that is used to form a URLs and type field in passed JSONs. According to JSON API standard,the name defined in type can be either plural or singular

    The example below shows a sample class which contains a definition of a resource.

      @JsonApiResource(type = "tasks")  public class Task {  // fields, getters and setters  }

    where type parameter specifies the resource’s name.

    By default the type of a resource in a JSON API document and its name within URLs match, forexample:

    17

  • {  "links": {  "self": "http://localhost/api/tasks",  },  "data": [{  "type": "tasks",  "id": "1",  "attributes": {  "title": "Some task"  }  }}

    The optional resourcePath allows to define separate values, typically with resourcePath being pluraland type being singular:

      @JsonApiResource(type = "task", resourcePath = "tasks")  public class Task {  // fields, getters and setters  }

    resulting in (notice the self link does not change, but type does):

    {  "links": {  "self": "http://localhost/api/tasks",  },  "data": [{  "type": "task",  "id": "1",  "attributes": {  "title": "Some task"  }  }}

    The optional pagingSpec parameter allows to set the desired paging specification:

      @JsonApiResource(type = "tasks", pagingSpec = OffsetLimitPagingSpec.class)  public class Task {  // fields, getters and setters  }

    There is built-in support for OffsetLimitPagingSpec (default) or NumberSizePagingSpec. The paging

    18

  • spec must be backed by a matching PagingBehavior implementation. More detailed informationabout pagination can be found at Pagination section.

    The optional subTypes parameter allows to specify an inheritance relationship to other resources:

      @JsonApiResource(type = "task", subTypes = SpecialTask.class)  public class Task {  // fields, getters and setters  }

      @JsonApiResource(type = "specialTask", resourcePath = "task")  public class SpecialTask extends Task{  // fields, getters and setters  }

    In this case the SpecialTask extends Task but shares the same resourcePath, meaning SpecialTaskdoes not bring along a repository implementation (see next chapter), but is served by the taskrepository. For a more information have a look at the [inheritance] section.

    4.2. JsonApiIdDefines a field which will be used as an identifier of a resource. Each resource requires thisannotation to be present on a field which type implements Serializable or is of primitive type.

    The example below shows a sample class which contains a definition of a field which contains anidentifier.

      @JsonApiResource(type = "tasks")  public class Task {  @JsonApiId  private Long id;

      // fields, getters and setters  }

    4.3. JsonApiRelationIndicates an association to either a single value or collection of resources. The type of such fieldsmust be a valid resource.

    The example below shows a sample class which contains this kind of relationship.

    19

  •   @JsonApiResource(type = "tasks")  public class Task {

      // ID field

     @JsonApiRelation(lookUp=LookupIncludeBehavior.AUTOMATICALLY_WHEN_NULL,serialize=SerializeType.ONLY_ID)  private Project project;

      // fields, getters and setters  }

    The optional serialize parameter specifies how the association should be serialized when making arequest. There are two things to consider. Whether related resources should be added to theinclude section of the response document. And whether the id of related resources should beserialized along with the resource in the corresponding relationships.[name].data section. EitherLAZY, ONLY_ID or EAGER can be specified:

    • LAZY only serializes the ID and does the inclusion if explicitly requested by the include URLparameter. This is the default.

    • ONLY_ID always serializes the ID, but does only to an inclusion if explicitly requested by theinclude URL parameter.

    • EAGER always both serializes the ID and does an inclusion.

    There are two possibilities of how related resources are fetched. Either the requested repositorydirectly returns related resources with the returned resources. Or Crnk can take-over that work bydoing nested calls to the corresponding RelationshipRepositoryV2 implementations. The behavior iscontrolled by the optional lookUp parameter. There are three options:

    • NONE makes the requested repository responsible for returning related resources. This is thedefault.

    • AUTOMATICALLY_WHEN_NULL will let Crnk lookup related resources if not already done by therequested repository.

    • AUTOMATICALLY_ALWAYS will force Crnk to always lookup related resource regardless whether it isalready done by the requested repository.

    There are many different ways how a relationship may end-up being implemented. In the best case,no implementation is necessary at all and requests can be dispatches to one of the two relatedresource repositories. The repositoryBehavior allows to configure behavior:

    • DEFAULT makes use of IMPLICIT_FROM_OWNER if a relationship also makes use of @JsonApiRelationId(see below) or lookUp=NONE (see above). In any other case it expects a custom implementation.

    • CUSTOM expects a custom implementation.

    • FORWARD_OWNER forward any relationship request to the owning resource repository, therepository that defines the requested relationship field. GET requests will fetch the owning

    20

  • resources and grab the related resources from there (with the appropriate inclusionparameter). This assumes that the owning resource properties hold the related resources (or atleast there IDs in case of JsonApiRelationId, see below). POST, PATCH, DELETE requests willupdate the properties of the owning resource accordingly and invoke a save operation on theowning resource repository. An implementation is provided byImplicitOwnerBasedRelationshipRepository.

    • FORWARD_GET_OPPOSITE_SET_OWNER works like FORWARD_OWNER for PATCH, POST, DELETE methods. Incontrast, GET requests are forwarded to the opposite resource repository. For example, if thereis a relationship between Task and Project with the project and tasks relationship fields. To getall tasks of a project, the task repository will be queried with a project.id= filterparameter. Relational database are one typical example where this pattern fits nicely. Incontract to IMPLICIT_FROM_OWNER only a single resource repository is involved with a slightlymore complex filter parameter, giving performance benefits. An implementation is provided byRelationshipRepositoryBase.

    • FORWARD_OPPOSITE the opposite to FORWARD_OWNER. Querying works likeIMPLICIT_GET_OPPOSITE_MODIFY_OWNER.

    The forwarding behaviors are implemented by ForwardingRelationshipRepository.

    IMPORTANT

    It likely takes a moment to familiarize oneself with all configuration optionsof @JsonApiRelation and the subsequent @JsonApiRelationId. But at the sametime it is one area where a native resource-oriented REST library like Crnkcan provide significant benefit and reduce manual work compared to moreclassical REST libraries like Spring MVC or JAX-RS.

    4.4. JsonApiRelationIdFields annotated with @JsonApiRelation hold fully-realized related resources. There are situationswhere the id of a related resource is available for free or can be obtained much more cheaply thenfetching the entire related resource. In this case resources can make use of fields annotated with@JsonApiRelationId. The complement @JsonApiRelation fields by holding there ID only. An examplelooks like:

    21

  • @JsonApiResource(type = "schedules")public class Schedule {  ...

      @JsonApiRelationId  private Long projectId;

      @JsonApiRelation  private Project project;

      public Long getProjectId() {  return projectId;  }

      public void setProjectId(Long projectId) {  this.projectId = projectId;  this.project = null;  }

      public Project getProject() {  return project;  }

      public void setProject(Project project) {  this.projectId = project != null ? project.getId() : null;  this.project = project;  }}

    Notice that: - Schedule resource holds both a project and projectId field that point to the samerelated resource. - setters must set both properties to make sure they stay in sync. If only the ID isset, the object must be nulled. - propertyId will never show in requests and responses. It can beconsidered to be transient.

    By default, the naming convention for @JsonApiRelationId field is to end with a Id or Ids suffix. Crnkwill the pair those two objects automatically. Trailing s are ignored for multi-valued fields, meaningthat projectIds matches with projects. But it is also possible to specify a custom name, for example:

    @JsonApiRelationIdprivate Long projectFk;

    @JsonApiRelation(idField = "projectFk")private Project project;

    If a @JsonApiRelationId field cannot be matched to a @JsonApiRelation field, an exception will bethrown.

    @JsonApiRelationId fields are used for:

    22

  • • GET requests to fill-in the data section of a relationship.

    • POST and PATCH requests to fill-in the new value without having to fetch and set the entire relatedresource.

    Further (substantial) benefit for @JsonApiRelationId fields is that no RelationshipRepositorymust be implemented. Instead Crnk will automatically dispatch relationship requests to theowning and opposite ResourceRepository. This allows to focus on the development ofResourceRepository. See RelationshipRepository for more information.

    4.5. JsonApiMetaInformationField or getter annotated with JsonApiMetaInformation are marked to carry a MetaInformationimplementation. See http://jsonapi.org/format/#document-meta for more information about metadata. Example:

      @JsonApiResource(type = "projects")  public class Project {

      ...

      @JsonApiMetaInformation  private ProjectMeta meta;

      public static class ProjectMeta implements MetaInformation {

      private String value;

      public String getValue() {  return value;  }

      public void setValue(String value) {  this.value = value;  }  }  }

    4.6. JsonApiLinksInformationField or getter annotated with JsonApiLinksInformation are marked to carry a LinksInformationimplementation. See http://jsonapi.org/format/#document-links for more information about linking.Example:

    23

    http://jsonapi.org/format/#document-metahttp://jsonapi.org/format/#document-links

  •   @JsonApiResource(type = "projects")  public class Project {

      ...

      @JsonApiLinksInformation  private ProjectLinks links;

      public static class ProjectLinks implements LinksInformation {

      private String value;

      public String getValue() {  return value;  }

      public void setValue(String value) {  this.value = value;  }  }  }

    By default links are serialized as:

    "links": {  "self": "http://example.com/posts"}

    With crnk.config.serialize.object.links=true links get serialized as:

    "links": {  "self": {  "href": "http://example.com/posts",  }}

    4.7. Jackson annotationsCrnk comes with (partial) support for Jackson annotations. Currently supported are:

    Annotation Description

    @JsonIgnore Excludes a given attribute from serialization.

    @JsonProperty.value Renames an attribute during serialization.

    24

  • Annotation Description

    @JsonProperty.access Specifies whether an object can be read and/or written.

    @JsonAnyGetter and@JsonAnySetter

    To map dynamic data structures to JSON.

    Support for more annotations will be added in the future. PRs welcomed.

    4.8. Nested Resources

    WARNING This feature is experimental and will be refined in subsequent releases.

    A resource may be nested and belong to a parent resource. In this case the nested resource is accessthrough its parent resource. An URL then looks like:

    http://example.com/posts/1/comments/2

    For a resource to become nested, it must make use of a structure identifier:

    NestedId.java

    package io.crnk.test.mock.models.nested;

    import io.crnk.core.resource.annotations.JsonApiId;import io.crnk.core.resource.annotations.JsonApiRelationId;

    import java.io.Serializable;

    public class NestedId implements Serializable {

      @JsonApiId  private String id;

      @JsonApiRelationId  private String parentId;

      public NestedId() {

      }

      public NestedId(String parentId, String id) {  this.parentId = parentId;  this.id = id;  }

      public String getId() {  return id;  }

    25

    http://example.com/posts/1/comments/2http://example.com/posts/1/comments/2http://example.com/posts/1/comments/2http://example.com/posts/1/comments/2http://example.com/posts/1/comments/2http://example.com/posts/1/comments/2http://example.com/posts/1/comments/2

  •   public void setId(String id) {  this.id = id;  }

      public String getParentId() {  return parentId;  }

      public void setParentId(String parentId) {  this.parentId = parentId;  }

      public static NestedId parse(String idString) {  String[] elements = idString.split("\\-");  NestedId id = new NestedId();  id.parentId = elements[0];  id.id = elements[1];  return id;  }

      public int hashCode() {  return toString().hashCode();  }

      public boolean equals(Object object) {  return object instanceof NestedId && object.toString().equals(toString());  }

      public String toString() {  return parentId + "-" + id;  }}

    The id is setup of two parts:

    • the local identifier of the child resource, annotated with @JsonApiId. It must be unique among allnested resources having the same parent.

    • the identifier of the parent resource, annotated with a @JsonApiRelationId. The nested resourcemust have matching relationship field (in this case parent)`.

    NestedId further implements parse, toString, hashCode and equals to deal with String serializationand equality.

    For an example have a look at NestedRepositoryClientTest and its parent class. Depending on theuse of [JsonApiExposed] it is or is not be possible to also directly access http://example.com/commentswithout going through the parents.

    Current Limitations:

    • Nesting is currently limited to a single level (and the possibility to have further relationships on

    26

    http://example.com/commentshttp://example.com/commentshttp://example.com/comments

  • the nested resource).

    • When creating new resources with CrnkClient, the nested identifier must be setup in order tolet CrnkClient access the parentId.

    • Being experimental.

    5. RepositoriesThe modelled resources and relationships must be complemented by a corresponding repositoryimplementation. This is achieved by implementing one of those two repository interfaces:

    • ResourceRepositoryV2 for resources.

    • RelationshipRepositoryV2 resp. BulkRelationshipRepositoryV2 for relationships.

    The repositories are used to serve POST, GET, PATCH and DELETE requests as specified by JSON APIspecification. The repository contract closely resembles the JSON API specification. Subsequentsections and chapters outline various possibilities to speed-up and potentially reuse existingrepository implementations.

    IMPORTANTWhen accessing repositories, do not forget to use theapplication/vnd.api+json content type.

    5.1. ResourceRepositoryV2ResourceRepositoryV2 is the main interface used to operate on resources with POST, GET, PATCH andDELETE requests. The interface takes two generic arguments:

    1. The type of a resource. Typically this is a plain Java Bean making use of the JSON APIannotations. But may also be something entirely different (see [architectures> and

  • including sorting, filtering, paging, field sets and inclusions. A ResourceList must be returnedthat carries the result resources, links information and meta information.

    • create(S resource) Called by POST requests. The request body is deserialized and passed asresource parameter. The method may or may not have to generate an ID for the newly createdresource. The request body may specify relationship data to point to other resources. Duringdeserialization, those resources are looked up and the @JsonApiRelation annotated fields setaccordingly. For relationships making use of @JsonApiRelationId annotation, only the identifierwill be set without the resource annotation, allowing to improve for performance. The createmethod has to save those relationships, but it does and must not perform any changes on therelated resources. For bulk inserting and updating resources, have a look at the operationsmodule. The method must return the updated resource, most notably with a valid identifier.

    • save(S resource) Saves a resource upon a PATCH request. The general semantics is identical tothe create(…) method, with two notable exceptions. First, resources are updated but are notallowed to be inserted. A ResourceNotFoundException must be thrown if the resource does notexist. Second, the PATCH request allows for partial updates. Internally Crnk will get the currentstate of a resource, patch it and pass it to this save method. API to distinguish patched from un-patched fields is not yet (directly) available, feel free to open a ticket.

    • delete(ID id) Removes a resource identified by id parameter. A ResourceNotFoundException mustbe thrown if the resource does not exist.

    The ResourceRepositoryBase is a base class that takes care of some boiler-plate, like implementingfindOne with findAll. An implementation can then look as simple as:

    Task.java

    @JsonApiResource(type = "tasks")public class Task {

      @JsonApiId  private Long id;

      @JsonProperty("name")  private String name;

      @Size(max = 20, message = "Description may not exceed {max} characters.")  private String description;

      @JsonApiRelationId  private Long projectId;

      @JsonApiRelation(opposite = "tasks", lookUp =LookupIncludeBehavior.AUTOMATICALLY_WHEN_NULL,  repositoryBehavior = RelationshipRepositoryBehavior.FORWARD_OWNER,  serialize = SerializeType.ONLY_ID)  private Project project;

      ...}

    28

  • and

    TaskRepositoryImpl.java

    @Componentpublic class TaskRepositoryImpl extends ResourceRepositoryBase implementsTaskRepository {

      // for simplicity we make use of static, should not be used in real applications  private static final Map tasks = new ConcurrentHashMap();

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

      public TaskRepositoryImpl() {  super(Task.class);  }

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

      @Override  public S create(S entity) {  if (entity.getId() != null && tasks.containsKey(entity.getId())) {  throw new BadRequestException("Task already exists");  }  return save(entity);  }

      @Override  public Class getResourceClass() {  return Task.class;  }

      @Override  public Task findOne(Long taskId, QuerySpec querySpec) {  Task task = tasks.get(taskId);  if (task == null) {  throw new ResourceNotFoundException("Task not found!");  }  return task;  }

      @Override  public ResourceList findAll(QuerySpec querySpec) {  return querySpec.apply(tasks.values());

    29

  •   }

      @Override  public void delete(Long taskId) {  tasks.remove(taskId);  }}

    The example is taken from crnk-examples/spring-boot-example. (the basic Spring boot examplefrom crnk-framework, not the dedicated full-blown one from crnk-example).

    Together with matching project repository, some URLs to checkout:

    http://127.0.0.1:8080/api/taskshttp://127.0.0.1:8080/api/tasks/1http://127.0.0.1:8080/api/tasks/1http://127.0.0.1:8080/api/tasks/1/projecthttp://127.0.0.1:8080/api/tasks/1/relationships/projecthttp://127.0.0.1:8080/api/tasks?sort=-namehttp://127.0.0.1:8080/api/tasks?sort=-id,namehttp://127.0.0.1:8080/api/tasks?sort=-id,namehttp://127.0.0.1:8080/api/tasks?sort=id&page[offset]=0&page[limit]=2http://127.0.0.1:8080/api/tasks?filter[name]=Do thingshttp://127.0.0.1:8080/api/tasks?filter[name][EQ]=Do thingshttp://127.0.0.1:8080/api/tasks?filter[name][LIKE]=Do%http://127.0.0.1:8080/api/tasks?filter[name][EQ]=SomeTask,OtherTaskhttp://127.0.0.1:8080/api/tasks?fields=namehttp://127.0.0.1:8080/api/projectshttp://127.0.0.1:8080/api/tasks?include=projecthttp://127.0.0.1:8080/api/browse/

    You may notice that:

    • links get automatically created.

    • totalResourceCount and pagination links are added to the response if the page parameter isapplied.

    • related project gets automatically resolved from projectId. No relationship repository isimplemented here due to the use of @JsonApiRelationId (see below).

    • the response gets automatically truncated with the fields parameter, ideally suited forbandwidth sensitive applications.

    • multiple values can be separated by comma, typically repositories will then use an OR andaccept and resource matching any of the values.

    This is one small example that shows the power of native resource-oriented REST libraries.Implementing a similar API with more classical REST libraries can be a substantial amount of work.

    30

    https://github.com/crnk-project/crnk-framework/tree/master/crnk-examples/spring-boot-example/src/main/java/io/crnk/example/springboot/domain/repository

  • There is further a ReadOnlyResourceRepositoryBase base class that does not allow to override thecreate, delete and update methods. crnk-meta accordingly reports insertable, updateable, deltablefor such repositories as false.

    5.2. Query parameters with QuerySpecCrnk passes JSON API query parameters to repositories trough a QuerySpec parameter. It holdsrequest parameters like sorting and filtering specified by JSON API. The subsequent sections willprovide a number of example.

    NOTE

    Not everything is specified by JSON API. For some request parameters onlyrecommendations are provided as different applications are likely to be in need ofdifferent semantics and implementations. For this reason the engine part in crnk-core makes use of QueryAdapter and allows implementations other than QuerySpec(like the legacy QueryParams). The mapping of HTTP request parameters toQuerySpec and back is implemented by QuerySpecUrlMapper that may can also beextended, customized or replaced.

    For example showing its use URLs also have a look at the ResourceRepositoryV2 section.

    5.2.1. API

    The QuerySpec API looks like (further setters available as well):

      public class QuerySpec {  public List apply(Iterable resources){...}

      public Long getLimit() {...}

      public long getOffset() {...}

      public PagingSpec getPagingSpec() {...}

      public List getFilters() {...}

      public List getSort() {...}

      public List getIncludedFields() {...}

      public List getIncludedRelations() {...}

      public QuerySpec getQuerySpec(Class resourceClass) {...}

      ...  }

    There are Spec class for all major features:

    31

  • • FilterSpec

    • SortSpec

    • IncludeFieldSpec

    • IncludeRelationSpec

    • PagingSpec

    More information is given in the subsequent sections.

    QuerySpec provides a method apply that allows in-memory sorting, filtering and paging on anyjava.util.Collection. It is useful for testing, mocking and on smaller datasets to keep theimplementation of a repository as simple as possible.

    5.2.2. Filtering

    NOTE

    The JSON API specification does not a mandate a specific filtering semantic. Insteadit provides a recommendation that comes by default with Crnk. Depending on thedata store in use, application may choose to extend or replace that defaultimplementation by extending or replacing DefaultQuerySpecUrlMapper.

    Resource filtering can be achieved by providing parameters which start with filter:

    • GET /tasks?filter[name]=Super task to filter by name with the default EQ operator.

    • GET /tasks?filter[name][EQ]=Super task to filter by name with the EQ operator.

    • GET /tasks?filter[name][EQ]=SomeTask,OtherTask to filter by multiple OR-ed values.

    • GET /tasks?filter[name][LIKE]=Super% to filter by name with the LIKE operator using % aswildcard.

    • GET /tasks?filter[address.plz][EQ]=Super task to filter by attribute name within a structured orrelated attributes address.

    • GET /tasks?filter[address.city][EQ]=Super task to filter by attribute city within a structured orrelated attributes address.

    • GET /tasks?filter[name]=Super task&filter[dueDate][GT]=2015-10-01

    • GET /tasks?filter[name]=null to filter by name being equals null.

    • GET /tasks?filter[tasks][name]=Super task is the longer version of /tasks/?filter[name]=Supertask where the tasks type is explicitly stated. See the subsequent [inclusion] section how to usethis to perform filtering of related resources.

    A filter parameter is represented by a FilterSpec. It holds the path to the attribute, the operator andthe filter value. The attribute specifies what gets filtered. The operator specifies how it is filtered.And the value specifies after what should be filtered.

    The filter value FilterSpec.value is strongly typed. Typically (by default) it is assumed that the filtervalue matches the attribute type and Crnk will attempt to parse passed String-based filter valueaccordingly. There are exceptions, for example, the LIKE filter operator always requires the filtervalue to be a string to support wildcards for not just String types, but also Enums and other types

    32

  • (the underlying FilterOperator implementation can specify this with getFilterType(…)).

    Operators within FilterSpec are represented by the FilterOperator class. By default, QuerySpecuses the EQ operator if no operator was provided. Crnk comes with a set of default filters:

    Name Descriptor

    EQ equals operator where values match exactly.

    NEQ not equals where values do not match.

    LIKE where the value matches the specified pattern. It is usually not case-sensitive and makes use of % as wildclard, but may different dependingon the underlying implementation.

    LT lower than the specified value

    LE lower than or equals the specified value

    GT greater than the specified value

    GE greater than or equals the specified value

    By default the filtering process is quite opinionated and should fit many typical patterns. But therealso many possibilities to customize its behavior to the use case at hand. For this purpose[CrnkBoot] offers access to the DefaultQuerySpecUrlMapper with CrnkBoot.getUrlMapper() andTypeParser with CrnkBoot.getModuleRegistry().getTypeParser() (or ModuleContext). For example:

    • TypeParser allows to register and override the parsing of Strings to other classes. By default ithas has built-in parsers for various JRE classes, it looks on the type itself for a String constructoror static parse(String) parse method and otherwise fallbacks to Jackson. Further StringParsercan add support for arbitrary types.

    • DefaultQuerySpecUrlMapper.setIgnoreParseExceptions(…) allows to ignore if parsing of a filtervalue fails. In this case the filter value is left as String and it is assumed the repository itself willtake care of the parsing.

    • CrnkBoot.setAllowUnknownAttributes ignore unknown attributes and passes them as is to therepositories to handle them. More information in the [properties] section.

    • The application is free to implements custom FilterOperator. Next to the name a matchesmethod can be implemented to support in-memory filtering with QuerySpec.apply. Otherwise, itis up to the repository implementation to handle the various filter operators; usually bytranslating them to datastore-native query expressions. Custom operators can be registeredwith DefaultQuerySpecUrlMapper.addSupportedOperator(..). The default operator can beoverridden by setting DefaultQuerySpecUrlMapper.setDefaultOperator(…). For more informationsee QuerySpecUrlMapper.

    5.2.3. Sorting

    Sorting information for the resources can be achieved by providing sort parameter.

    GET /tasks?sort=name,-shortName GET /tasks?sort=assignee.firstName,assignee.lastName

    33

  • • Sorting parameters are represented by SortSpec within QuerySpec similar to FilterSpec above.

    • - is used to denote to sort in descending order.

    5.2.4. Pagination

    Offset/Limit Paging

    Crnk comes by default with support for offset/limit paging:

    GET /tasks?page[offset]=0&page[limit]=10

    The parameters are then available with QuerySpec.getPaging(type) or the shortcutsQuerySpec.getLimit and QuerySpec.getOffset.

    Number/Size Paging

    Support for number/size-based paging can be enabled by registering the NumberSizePagingBehaviorin one of two ways:

    • register NumberSizePagingBehavior.createModule()

    • register NumberSizePagingBehavior directly to service discovery.

    Paging parameters can then look like:

    GET /tasks?page[number]=1&page[size]=10

    Internally Crnk is able to translate between offset/limit and number/size-based paging. If arepository has been implemented with offset/limit paging, it works equally well when number/sizepaging is used. The conversion takes place automatically when invokingQuerySpec.getPaging(desiredPagingType).

    Pagination Links

    JSON API specifies first, previous, next and last links (see http://jsonapi.org/format/#fetching-pagination). The PagedLinksInformation interface provides a Java representation of those links thatcan be implemented and returned by repositories along with the result data. There is a defaultimplementation named DefaultPagedLinksInformation.

    There are two ways to let Crnk compute pagination links automatically:

    1. The repository returns meta information implementing PagedMetaInformation. With thisinterface the total number of (potentially filtered) resources is passed to Crnk, which in turnallows the computation of the links.

    2. The repository returns meta information implement