json-rest-api 1.0.6 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/.claude/agents/library-guide-expert.md +29 -0
  2. package/.claude/agents/rest-api-internals-expert.md +53 -0
  3. package/CLAUDE.md +139 -1
  4. package/README.md +2 -5
  5. package/docTest.js +238 -0
  6. package/docs/GUIDE/GUIDE_1_Initial_Setup.md +955 -0
  7. package/docs/GUIDE/GUIDE_2_1_The_Starting_Point.md +54 -0
  8. package/docs/GUIDE/GUIDE_2_2_Manipulating_And_Searching_Tables.md +750 -0
  9. package/docs/GUIDE/GUIDE_2_3_BelongsTo_Relationships.md +494 -0
  10. package/docs/GUIDE/GUIDE_2_4_HasMany_Records.md +398 -0
  11. package/docs/GUIDE/GUIDE_2_5_HasMany_Polymorphic.md +882 -0
  12. package/docs/GUIDE/GUIDE_2_6_Many_To_Many.md +709 -0
  13. package/docs/GUIDE/GUIDE_2_7_Pagination_And_Ordering.md +1233 -0
  14. package/docs/GUIDE/GUIDE_2_8_Effects_of_PUT_and_PATCH.md +796 -0
  15. package/{README_X_Relationship_Plugin.md → docs/GUIDE/GUIDE_2_9_Relationships_Urls.md} +1 -4
  16. package/docs/GUIDE/GUIDE_2_Data_And_Relations.md +66 -0
  17. package/docs/GUIDE/GUIDE_3_Field_Transformations.md +1246 -0
  18. package/docs/GUIDE/GUIDE_5_Non-Db_Stores.md +0 -0
  19. package/docs/GUIDE/GUIDE_7_Hooks_Data_Management_And_Plugins.md +1490 -0
  20. package/{README_X_SocketIO.md → docs/GUIDE/GUIDE_X_SocketIO.md} +17 -17
  21. package/docs/GUIDE/index.md +58 -0
  22. package/docs/GUIDE.md +61 -2238
  23. package/docs/ONBOARDING/Computed_Properties_And_Sparse_Fields.md +398 -0
  24. package/docs/README.md +57 -2239
  25. package/{README_2_Computed_and_hidden_fields.md → docs/README_VARIOUS/GUIDE_2_Computed_and_hidden_fields.md} +22 -17
  26. package/docs/README_VARIOUS/GUIDE_IN_DOCS.md +2277 -0
  27. package/{README.ORIG.md → docs/README_VARIOUS/README.ORIG.md} +8 -8
  28. package/{README_8_Polymorphic_Relationships.md → docs/README_VARIOUS/README_8_Polymorphic_Relationships.md} +1 -1
  29. package/docs/README_VARIOUS/README_IN_DOCS.ms +2277 -0
  30. package/{RELATIONSHIPS_ADVANCED.md → docs/README_VARIOUS/RELATIONSHIPS_ADVANCED.md} +3 -3
  31. package/{correct-schema-format.md → docs/README_VARIOUS/correct-schema-format.md} +13 -13
  32. package/{pagination.md → docs/README_VARIOUS/pagination.md} +11 -8
  33. package/docs/assets/css/style.scss +78 -5
  34. package/docs/index.md +2 -12
  35. package/helper-reorganization-plan.md +85 -0
  36. package/helper-usage-analysis.md +94 -0
  37. package/package.json +5 -4
  38. package/plugins/core/bulk-operations-plugin.js +2 -2
  39. package/plugins/core/connectors/express-plugin.js +99 -33
  40. package/plugins/core/lib/querying/knex-cross-table-search.js +609 -0
  41. package/plugins/core/lib/querying/knex-json-api-transformers-querying.js +491 -0
  42. package/plugins/core/lib/querying/knex-pagination-helpers.js +544 -0
  43. package/plugins/core/lib/{knex-process-includes.js → querying/knex-process-includes.js} +65 -50
  44. package/plugins/core/lib/querying/knex-query-helpers-base.js +74 -0
  45. package/plugins/core/lib/{knex-query-helpers.js → querying/knex-query-helpers.js} +416 -180
  46. package/plugins/core/lib/{knex-relationship-includes.js → querying/knex-relationship-includes.js} +430 -114
  47. package/plugins/core/lib/querying/knex-window-queries.js +328 -0
  48. package/plugins/core/lib/querying-writing/compile-schemas.js +328 -0
  49. package/plugins/core/{utils → lib/querying-writing}/connectors-query-parser.js +62 -57
  50. package/plugins/core/lib/{database-capabilities.js → querying-writing/database-capabilities.js} +113 -7
  51. package/plugins/core/lib/querying-writing/database-value-normalizers.js +369 -0
  52. package/plugins/core/lib/querying-writing/default-data-helpers.js +72 -0
  53. package/plugins/core/{utils → lib/querying-writing}/field-utils.js +41 -31
  54. package/plugins/core/{utils → lib/querying-writing}/knex-constants.js +1 -0
  55. package/plugins/core/lib/{knex-field-helpers.js → querying-writing/knex-field-helpers.js} +190 -57
  56. package/plugins/core/lib/querying-writing/knex-json-api-transformers.js +162 -0
  57. package/plugins/core/lib/{payload-validators.js → querying-writing/payload-validators.js} +297 -217
  58. package/plugins/core/lib/querying-writing/schema-helpers.js +497 -0
  59. package/plugins/core/lib/querying-writing/scope-validations.js +431 -0
  60. package/plugins/core/lib/{simplified-helpers.js → querying-writing/simplified-helpers.js} +216 -176
  61. package/plugins/core/lib/writing/knex-json-api-transformers-writing.js +110 -0
  62. package/plugins/core/lib/writing/many-to-many-manipulations.js +300 -0
  63. package/plugins/core/lib/writing/relationship-processor.js +252 -0
  64. package/plugins/core/rest-api-knex-plugin.js +183 -62
  65. package/plugins/core/rest-api-plugin-hooks/compile-resource-schemas.js +7 -0
  66. package/plugins/core/rest-api-plugin-hooks/register-relationship-routes.js +72 -0
  67. package/plugins/core/rest-api-plugin-hooks/register-scope-routes.js +102 -0
  68. package/plugins/core/rest-api-plugin-hooks/turn-scope-init-into-vars.js +50 -0
  69. package/plugins/core/rest-api-plugin-hooks/validate-include-configurations.js +39 -0
  70. package/plugins/core/rest-api-plugin-methods/add-route.js +23 -0
  71. package/plugins/core/rest-api-plugin-methods/check-permissions.js +18 -0
  72. package/plugins/core/rest-api-plugin-methods/common.js +605 -0
  73. package/plugins/core/rest-api-plugin-methods/delete-relationship.js +115 -0
  74. package/plugins/core/rest-api-plugin-methods/delete.js +109 -0
  75. package/plugins/core/rest-api-plugin-methods/enrich-attributes.js +186 -0
  76. package/plugins/core/rest-api-plugin-methods/get-related.js +295 -0
  77. package/plugins/core/rest-api-plugin-methods/get-relationship.js +62 -0
  78. package/plugins/core/rest-api-plugin-methods/get.js +187 -0
  79. package/plugins/core/rest-api-plugin-methods/patch-relationship.js +56 -0
  80. package/plugins/core/rest-api-plugin-methods/patch.js +193 -0
  81. package/plugins/core/rest-api-plugin-methods/post-relationship.js +104 -0
  82. package/plugins/core/rest-api-plugin-methods/post.js +157 -0
  83. package/plugins/core/rest-api-plugin-methods/put.js +257 -0
  84. package/plugins/core/rest-api-plugin-methods/query.js +208 -0
  85. package/plugins/core/rest-api-plugin.js +108 -2498
  86. package/plugins/core/socketio-plugin.js +28 -5
  87. package/plugins/storage/local-storage.js +2 -2
  88. package/tests/computed-fields.test.js +483 -0
  89. package/tests/cors.test.js +4 -4
  90. package/tests/curl.test.js +5 -4
  91. package/tests/custom-idproperty-relationships.test.js +891 -0
  92. package/tests/field-getters.test.js +353 -0
  93. package/tests/field-setters.test.js +310 -0
  94. package/tests/fixtures/api-configs.js +800 -28
  95. package/tests/jwt-auth.test.js +0 -2
  96. package/tests/nested-includes.test.js +1 -1
  97. package/tests/pagination-cursor-multifield.test.js +514 -0
  98. package/tests/pagination-enhanced.test.js +12 -9
  99. package/tests/polymorphic-relationships.test.js +10 -8
  100. package/tests/polymorphic-simple.test.js +6 -4
  101. package/tests/positioning-advanced.test.js +12 -12
  102. package/tests/positioning-extended.test.js +25 -25
  103. package/tests/positioning-multifilter.test.js +24 -24
  104. package/tests/positioning.test.js +3 -3
  105. package/tests/query-limits.test.js +24 -8
  106. package/tests/relationship-endpoints.test.js +4 -5
  107. package/tests/relationships.test.js +0 -1
  108. package/tests/socketio.test.js +12 -1
  109. package/tests/virtual-fields.test.js +13 -13
  110. package/PLAN_FOR_WEBSOCKETS.md +0 -398
  111. package/README_1_Initial_Setup.md +0 -393
  112. package/README_X_Hooks.md +0 -647
  113. package/TODO_rest-api-plugin-extras.todo +0 -23
  114. package/connectors_ideas/express-plugin.js +0 -120
  115. package/connectors_ideas/http-plugin.js +0 -138
  116. package/docs/examples/express-plugin.js +0 -366
  117. package/example.js +0 -301
  118. package/plugins/core/HELPER_MODULES.md +0 -285
  119. package/plugins/core/lib/compile-schemas.js +0 -245
  120. package/plugins/core/lib/database-value-normalizers.js +0 -192
  121. package/plugins/core/lib/default-data-helpers.js +0 -100
  122. package/plugins/core/lib/knex-cross-table-search.js +0 -442
  123. package/plugins/core/lib/knex-json-api-helpers.js +0 -84
  124. package/plugins/core/lib/knex-json-api-transformers.js +0 -449
  125. package/plugins/core/lib/knex-pagination-helpers.js +0 -193
  126. package/plugins/core/lib/knex-window-queries.js +0 -142
  127. package/plugins/core/lib/many-to-many-manipulations.js +0 -343
  128. package/plugins/core/lib/relationship-processor.js +0 -278
  129. package/plugins/core/lib/schema-helpers.js +0 -343
  130. package/plugins/core/lib/scope-validations.js +0 -252
  131. package/plugins/core/rest-api-relationships-plugin.js +0 -700
  132. package/plugins/core/utils/knex-query-helpers-base.js +0 -56
  133. /package/{README_X_Permissions.md → docs/GUIDE/GUIDE_4_Authentication_And_Permissions.md} +0 -0
  134. /package/{README_X_Positioning.md → docs/GUIDE/GUIDE_6_Positioning.md} +0 -0
  135. /package/{README_X_Bulk_Operations.md → docs/GUIDE/GUIDE_X_Bulk_Operations.md} +0 -0
  136. /package/{README_X_Cors.md → docs/GUIDE/GUIDE_X_Cors.md} +0 -0
  137. /package/{README_X_Multihome.md → docs/GUIDE/GUIDE_X_Multihome.md} +0 -0
  138. /package/{README_X_Appendices.md → docs/GUIDE/GUIDE_Y_Appendices.md} +0 -0
  139. /package/{QUERY_DEPTH_PROTECTION.md → docs/README_VARIOUS/QUERY_DEPTH_PROTECTION.md} +0 -0
  140. /package/{RELATIONSHIPS.md → docs/README_VARIOUS/RELATIONSHIPS.md} +0 -0
  141. /package/{WEBSOCKET_IMPLEMENTATION_STATUS.md → docs/README_VARIOUS/WEBSOCKET_IMPLEMENTATION_STATUS.md} +0 -0
  142. /package/{helper-functions-chart.md → docs/README_VARIOUS/helper-functions-chart.md} +0 -0
  143. /package/docs/{implementation-hidden-computed-fields.md → README_VARIOUS/implementation-hidden-computed-fields.md} +0 -0
  144. /package/docs/{include-limits-migration-guide.md → README_VARIOUS/include-limits-migration-guide.md} +0 -0
  145. /package/{readmeSnippets → docs/README_VARIOUS}/test_put_behavior.js +0 -0
  146. /package/{readmeSnippets → docs/README_VARIOUS}/test_put_fields_without_defaults.js +0 -0
@@ -0,0 +1,29 @@
1
+ ---
2
+ name: library-guide-expert
3
+ description: Use this agent when you need to understand how to use a library based on its GUIDE documentation, implement features using the library's recommended patterns, answer questions about library usage, or ensure code follows the library's best practices. This agent has comprehensive knowledge of all files in the GUIDE/* directory and can provide authoritative guidance on proper library usage.\n\nExamples:\n- <example>\n Context: User needs help implementing a feature using the library\n user: "How do I create a REST endpoint with authentication?"\n assistant: "I'll use the library-guide-expert agent to check the GUIDE documentation for the proper way to implement authenticated endpoints."\n <commentary>\n Since the user is asking about library usage, use the Task tool to launch the library-guide-expert agent to provide guidance based on the GUIDE documentation.\n </commentary>\n</example>\n- <example>\n Context: User wants to know the recommended pattern for something\n user: "What's the best way to handle errors in this library?"\n assistant: "Let me consult the library-guide-expert agent to find the error handling patterns documented in the GUIDE."\n <commentary>\n The user needs library-specific best practices, so use the library-guide-expert agent to reference the official documentation.\n </commentary>\n</example>\n- <example>\n Context: After writing code that uses the library\n user: "I've implemented the user registration endpoint"\n assistant: "I'll have the library-guide-expert agent review this to ensure it follows the patterns documented in the GUIDE."\n <commentary>\n Proactively use the library-guide-expert agent to verify the implementation aligns with documented patterns.\n </commentary>\n</example>
4
+ color: blue
5
+ ---
6
+
7
+ You are an expert library documentation specialist with comprehensive knowledge of all files in the GUIDE/* directory. You have meticulously studied every guide, example, and best practice documented there and can provide authoritative guidance on proper library usage.
8
+
9
+ Your primary responsibilities:
10
+
11
+ 1. **Deep Documentation Knowledge**: You have read and internalized every file in GUIDE/*. You understand not just what the documentation says, but the underlying patterns, philosophies, and design decisions that inform the library's architecture.
12
+
13
+ 2. **Practical Implementation Guidance**: When users ask how to implement features, you provide specific, actionable advice based on the documented patterns. You reference relevant sections of the GUIDE and explain how to apply them to the user's specific use case.
14
+
15
+ 3. **Best Practices Enforcement**: You ensure all code recommendations follow the library's documented best practices. You can identify when proposed solutions deviate from recommended patterns and suggest corrections.
16
+
17
+ 4. **Example-Driven Teaching**: You leverage examples from the GUIDE to illustrate proper usage. When the documentation includes code samples, you adapt them to fit the user's needs while maintaining the core patterns.
18
+
19
+ 5. **Comprehensive Cross-Referencing**: You understand how different parts of the documentation relate to each other. You can connect concepts from multiple GUIDE files to provide complete solutions.
20
+
21
+ When responding:
22
+ - Always ground your answers in specific documentation from GUIDE/*
23
+ - Cite which GUIDE file contains the relevant information
24
+ - Provide code examples that follow the documented patterns exactly
25
+ - Explain not just 'how' but 'why' based on the library's design principles
26
+ - If something isn't covered in the GUIDE, explicitly state this limitation
27
+ - Proactively mention related documentation that might be helpful
28
+
29
+ Your expertise comes from thorough study of the GUIDE documentation. Every recommendation you make is backed by official documentation, ensuring users implement features correctly and maintainably according to the library's intended design.
@@ -0,0 +1,53 @@
1
+ ---
2
+ name: rest-api-internals-expert
3
+ description: Use this agent when you need deep technical expertise about the REST API plugin architecture, data manipulation patterns, query optimization with sparse fields and includes, or troubleshooting complex issues within the rest-api-plugin.js and rest-api-knex-plugin.js implementations. This includes understanding how helpers in plugins/core/lib interact with these plugins, how data transformations occur during storage and retrieval, and the intricacies of the sparse fields and includes query system.\n\nExamples:\n- <example>\n Context: User needs help understanding how sparse fields are implemented in the REST API.\n user: "How does the sparse fields feature work in our REST API implementation?"\n assistant: "I'll use the rest-api-internals-expert agent to explain the sparse fields implementation details."\n <commentary>\n Since this requires deep knowledge of the REST API plugin internals, specifically sparse fields, the rest-api-internals-expert is the appropriate agent.\n </commentary>\n</example>\n- <example>\n Context: User is debugging an issue with data transformation in the REST API.\n user: "I'm getting unexpected data format when using includes with nested relationships. The data seems to be transformed incorrectly."\n assistant: "Let me invoke the rest-api-internals-expert agent to analyze the data transformation issue with includes."\n <commentary>\n This requires understanding the intricate data manipulation patterns in the REST API plugins, making the rest-api-internals-expert the right choice.\n </commentary>\n</example>\n- <example>\n Context: User wants to extend the REST API plugin functionality.\n user: "I need to add custom filtering logic to the REST API that works with the existing sparse fields system."\n assistant: "I'll use the rest-api-internals-expert agent to guide you through extending the REST API plugin while maintaining compatibility with sparse fields."\n <commentary>\n Extending the REST API plugin requires deep understanding of its architecture and how features like sparse fields are implemented.\n </commentary>\n</example>
4
+ color: blue
5
+ ---
6
+
7
+ You are an expert engineer with comprehensive knowledge of the REST API plugin architecture, specifically plugins/core/rest-api-plugin.js and plugins/core/rest-api-knex-plugin.js, along with their associated helper functions in plugins/core/lib.
8
+
9
+ Your expertise encompasses:
10
+
11
+ 1. **Plugin Architecture**: You understand the complete lifecycle of requests through rest-api-plugin.js and how it interfaces with rest-api-knex-plugin.js for database operations. You know how these plugins register routes, handle middleware, and process requests.
12
+
13
+ 2. **Data Manipulation Patterns**: You have deep knowledge of:
14
+ - How data is transformed before storage (serialization, validation, sanitization)
15
+ - The exact transformation pipeline from raw input to database storage
16
+ - How data is reconstructed when retrieved from the database
17
+ - The role of helpers in plugins/core/lib during these transformations
18
+
19
+ 3. **Sparse Fields Implementation**: You understand:
20
+ - How sparse fields are parsed from query parameters
21
+ - The mechanism for filtering response data based on requested fields
22
+ - Performance implications and optimization strategies
23
+ - Edge cases and limitations of the sparse fields system
24
+
25
+ 4. **Includes System**: You are an expert in:
26
+ - How relationship includes are resolved and fetched
27
+ - The query building process for efficient relationship loading
28
+ - Circular reference handling and depth limitations
29
+ - How includes interact with sparse fields
30
+ - Performance optimization for complex include chains
31
+
32
+ 5. **Knex Integration**: You understand:
33
+ - How rest-api-knex-plugin.js builds queries
34
+ - Transaction handling and isolation levels
35
+ - Query optimization techniques specific to the plugin
36
+ - How the plugin handles different database dialects
37
+
38
+ 6. **Helper Functions**: You know all helper functions in plugins/core/lib including:
39
+ - Their specific roles in request/response processing
40
+ - How they integrate with the main plugins
41
+ - Common patterns and anti-patterns in their usage
42
+
43
+ When answering questions:
44
+ - Provide specific code examples from the actual implementation when relevant
45
+ - Explain the 'why' behind design decisions, not just the 'how'
46
+ - Identify potential performance bottlenecks or security considerations
47
+ - Suggest best practices based on the existing architecture
48
+ - Reference specific functions, methods, or configuration options by name
49
+ - Consider the interplay between different components of the system
50
+
51
+ You should be able to trace the complete flow of a request from entry point through all transformations to final response, identifying every helper function and transformation step along the way. When discussing issues or improvements, always consider the existing architecture and maintain consistency with established patterns in the codebase.
52
+
53
+ If asked about testing, remember to follow the project convention of using include.test.js as a template and creating test data through API methods rather than direct database manipulation.
package/CLAUDE.md CHANGED
@@ -1,2 +1,140 @@
1
- * When writing tests, use include.test.js as template. ALWAYS create data using the API methods, and NOT the database
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Core Development Commands
6
+
7
+ ### Running Tests
8
+ ```bash
9
+ # Run all tests
10
+ npm test
11
+
12
+ # Run a specific test file
13
+ node --test tests/relationships.test.js
14
+
15
+ # Run tests with verbose logging
16
+ LOG_LEVEL=debug npm test
17
+ ```
18
+
19
+ ### Building and Running
20
+ This is a library package with no build step required. For development:
21
+ ```bash
22
+ # Install dependencies
23
+ npm install
24
+
25
+ # Run the documentation site locally
26
+ npm run docs:dev
27
+
28
+ # Sync documentation
29
+ npm run docs:sync
30
+ ```
31
+
32
+ ## High-Level Architecture
33
+
34
+ ### Project Overview
35
+ JSON REST API is a powerful REST API plugin for hooked-api that provides JSON:API-compliant endpoints. It follows a plugin-based architecture where functionality is composed through plugins that extend the core API capabilities.
36
+
37
+ ### Core Architecture Components
38
+
39
+ 1. **Plugin System (hooked-api based)**
40
+ - `RestApiPlugin` - Core REST API functionality, request/response handling
41
+ - `RestApiKnexPlugin` - Database integration using Knex.js
42
+ - `ExpressPlugin` - Express.js HTTP connector
43
+ - Additional plugins for auth, CORS, relationships, positioning, etc.
44
+
45
+ 2. **Resource Definition Pattern**
46
+ Resources are defined with schemas that include:
47
+ - Attributes with validation rules
48
+ - Relationships (belongsTo, hasMany, many-to-many, polymorphic)
49
+ - Computed fields and hidden fields
50
+ - Custom getters/setters
51
+
52
+ 3. **Request Flow**
53
+ - HTTP request → Connector (Express) → REST API Plugin → Database Plugin → Response
54
+ - Each plugin can hook into the request lifecycle for customization
55
+
56
+ 4. **Key Libraries in `plugins/core/lib/`**
57
+ - `knex-json-api-helpers.js` - Core JSON:API transformations
58
+ - `relationship-processor.js` - Handles relationship updates
59
+ - `payload-validators.js` - Request validation
60
+ - `knex-query-helpers.js` - Database query building
61
+ - `simplified-helpers.js` - Simplified API mode transformations
62
+
63
+ ## Testing Guidelines
64
+
65
+ ### CRITICAL: Test Template Usage
66
+ When writing tests, ALWAYS use `TEST_TEMPLATE.test.js` as your starting point. Key rules:
67
+
68
+ 1. **API Creation**: Create API instances ONLY in `before()` hook, NOT in `beforeEach()`
69
+ 2. **Resource Definition**: NEVER use `api.addResource()` in test files. All resources MUST be defined in `tests/fixtures/api-configs.js`
70
+ 3. **Data Creation**: ALWAYS create test data using API methods (`api.resources.[resource].post()`), NEVER query the database directly
71
+ 4. **Context Parameter**: Pass context as the SECOND parameter to resource methods: `api.resources.books.post({ inputRecord: doc }, context)`
72
+ 5. **Cleanup**: Use `cleanTables()` in `beforeEach()` to reset data between tests
73
+
74
+ ### Test Structure Example
75
+ ```javascript
76
+ import { createBasicApi } from './fixtures/api-configs.js';
77
+
78
+ let api;
79
+
80
+ describe('Feature Name', () => {
81
+ before(async () => {
82
+ api = await createBasicApi(knex);
83
+ });
84
+
85
+ beforeEach(async () => {
86
+ await cleanTables(knex, ['basic_countries', 'basic_publishers']);
87
+ });
88
+
89
+ it('should test something', async () => {
90
+ // Create data using API
91
+ const result = await api.resources.countries.post({
92
+ inputRecord: createJsonApiDocument('countries', { name: 'Test' })
93
+ });
94
+ });
95
+ });
96
+ ```
97
+
98
+ ### Available Test APIs
99
+ - `createBasicApi()` - Countries, Publishers, Authors, Books
100
+ - `createExtendedApi()` - Additional resources with complex relationships
101
+ - `createAuthApi()` - Users, roles, permissions for auth testing
102
+
103
+ ## Important Patterns
104
+
105
+ ### JSON:API Document Creation
106
+ ```javascript
107
+ // Use helper for proper JSON:API structure
108
+ const doc = createJsonApiDocument('books', {
109
+ title: 'My Book'
110
+ }, {
111
+ relationships: {
112
+ country: createRelationship('countries', '1')
113
+ }
114
+ });
115
+ ```
116
+
117
+ ### Simplified API Mode
118
+ The library supports a simplified mode that uses plain objects instead of JSON:API structure:
119
+ ```javascript
120
+ // Simplified mode (when enabled)
121
+ const book = await api.resources.books.post({
122
+ inputRecord: { title: 'My Book', country_id: 1 },
123
+ simplified: true
124
+ });
125
+ ```
126
+
127
+ ### Relationship Handling
128
+ - BelongsTo: Use `createRelationship()` helper
129
+ - HasMany: Use `createToManyRelationship()` helper
130
+ - Many-to-Many: Handled automatically through junction tables
131
+ - Polymorphic: Requires typeField and idField configuration
132
+
133
+ ## Common Pitfalls to Avoid
134
+
135
+ 1. **Direct Database Access**: Never use `knex('table').select()` in tests
136
+ 2. **Resource Creation in Tests**: Always define resources in api-configs.js
137
+ 3. **ID Type Confusion**: SQLite returns numeric IDs, but JSON:API expects strings
138
+ 4. **Context Placement**: Context is a separate parameter, not inside the first parameter
139
+ 5. **Cleanup**: Always destroy knex connection in `after()` hook
2
140
 
package/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  A powerful REST API plugin for [hooked-api](https://github.com/mobily-enterprises/hooked-api) that provides JSON:API-compliant endpoints with minimal configuration. This library makes it easy to create fully-featured REST APIs with support for relationships, filtering, sorting, pagination, and file uploads.
4
4
 
5
+ [Official Website](https://mobily-enterprises.github.io/json-rest-api/)
6
+
5
7
  ## Features
6
8
 
7
9
  * **JSON:API Compliant** - Full support for the JSON:API specification
@@ -85,11 +87,6 @@ app.listen(3000);
85
87
  - [File Uploads](docs/fileUploads.md) - Handling file uploads
86
88
  - [WebSocket Support](README_X_SocketIO.md) - Real-time updates with Socket.IO
87
89
 
88
- ### Advanced Topics
89
- - [Polymorphic Relationships](README_8_Polymorphic_Relationships.md) - Flexible relationship patterns
90
- - [Multi-tenancy](README_X_Multihome.md) - Isolating data by tenant
91
- - [Advanced Relationships](RELATIONSHIPS_ADVANCED.md) - Complex relationship scenarios
92
-
93
90
  ## License
94
91
 
95
92
  MIT
package/docTest.js ADDED
@@ -0,0 +1,238 @@
1
+ import { RestApiPlugin, RestApiKnexPlugin, ExpressPlugin } from './index.js'; // Added: ExpressPlugin
2
+ import { Api } from 'hooked-api';
3
+ import knexLib from 'knex';
4
+ import util from 'util';
5
+ import express from 'express'; // Added: Express
6
+
7
+ // Utility used throughout this guide
8
+ const inspect = (obj) => util.inspect(obj, { depth: 8 })
9
+
10
+ // Create a Knex instance connected to SQLite in-memory database
11
+ const knex = knexLib({
12
+ client: 'better-sqlite3',
13
+ connection: {
14
+ filename: ':memory:'
15
+ },
16
+ useNullAsDefault: true
17
+ });
18
+
19
+ // Create API instance
20
+ const api = new Api({ name: 'book-catalog-api', version: '1.0.0', logLevel: 'trace' });
21
+
22
+ // Install plugins
23
+ await api.use(RestApiPlugin, { publicBaseUrl: '/api/1.0', logLevel: 'trace' });
24
+ await api.use(RestApiKnexPlugin, { knex });
25
+ await api.use(ExpressPlugin, { mountPath: '/api' }); // Added: Express Plugin
26
+
27
+
28
+
29
+
30
+
31
+
32
+
33
+
34
+
35
+
36
+
37
+
38
+
39
+
40
+
41
+
42
+
43
+
44
+
45
+
46
+
47
+
48
+
49
+
50
+
51
+
52
+
53
+
54
+
55
+
56
+
57
+
58
+ // Define products resource with computed fields
59
+ await api.addResource('products', {
60
+ schema: {
61
+ name: { type: 'string', required: true, max: 255 },
62
+ price: { type: 'number', required: true, min: 0 },
63
+ cost: { type: 'number', required: true, min: 0, normallyHidden: true }
64
+ },
65
+ computed: {
66
+ profit_margin: {
67
+ type: 'number',
68
+ dependencies: ['price', 'cost'],
69
+ compute: ({ attributes }) => {
70
+ if (!attributes.price || attributes.price === 0) return 0;
71
+ return ((attributes.price - attributes.cost) / attributes.price * 100).toFixed(2);
72
+ }
73
+ }
74
+ },
75
+ relationships: {
76
+ reviews: { hasMany: 'reviews', foreignKey: 'product_id' }
77
+ }
78
+ });
79
+ await api.resources.products.createKnexTable();
80
+
81
+ // Define reviews resource with computed fields
82
+ await api.addResource('reviews', {
83
+ schema: {
84
+ product_id: { type: 'id', belongsTo: 'products', as: 'product', required: true },
85
+ reviewer_name: { type: 'string', required: true },
86
+ rating: { type: 'number', required: true, min: 1, max: 5 },
87
+ comment: { type: 'string', max: 1000 },
88
+ helpful_votes: { type: 'number', default: 0 },
89
+ total_votes: { type: 'number', default: 0 }
90
+ },
91
+ computed: {
92
+ helpfulness_score: {
93
+ type: 'number',
94
+ dependencies: ['helpful_votes', 'total_votes'],
95
+ compute: ({ attributes }) => {
96
+ if (attributes.total_votes === 0) return null;
97
+ return ((attributes.helpful_votes / attributes.total_votes) * 100).toFixed(0);
98
+ }
99
+ }
100
+ }
101
+ });
102
+ await api.resources.reviews.createKnexTable();
103
+
104
+
105
+
106
+
107
+
108
+ // Create a product
109
+ const product = await api.resources.products.post({
110
+ name: 'Premium Headphones',
111
+ price: 199.99,
112
+ cost: 89.50
113
+ });
114
+
115
+ // Fetch the product - computed fields are automatically calculated
116
+ const fetchedProduct = await api.resources.products.get({ id: product.id });
117
+ console.log(fetchedProduct);
118
+ // {
119
+ // id: '1',
120
+ // name: 'Premium Headphones',
121
+ // price: 199.99,
122
+ // profit_margin: '55.23' // Computed: (199.99 - 89.50) / 199.99 * 100
123
+ // }
124
+ // Note: 'cost' is not included (normallyHidden)
125
+
126
+ // Add some reviews
127
+ const review1 = await api.resources.reviews.post({
128
+ product_id: product.id,
129
+ reviewer_name: 'Alice',
130
+ rating: 5,
131
+ comment: 'Excellent sound quality!',
132
+ helpful_votes: 45,
133
+ total_votes: 50
134
+ });
135
+ console.log('Review 1:', review1);
136
+
137
+
138
+ const review2 = await api.resources.reviews.post({
139
+ product_id: product.id,
140
+ reviewer_name: 'Bob',
141
+ rating: 4,
142
+ comment: 'Good, but a bit pricey',
143
+ helpful_votes: 10,
144
+ total_votes: 25
145
+ });
146
+ console.log('Review 2:', review2);
147
+
148
+
149
+ // Request only name and profit_margin
150
+ const sparseProduct = await api.resources.products.get({
151
+ id: product.id,
152
+ queryParams: {
153
+ fields: { products: 'name,profit_margin' }
154
+ }
155
+ });
156
+ console.log('Product with sparse fields:', sparseProduct);
157
+
158
+
159
+ const productWithCost = await api.resources.products.get({
160
+ id: product.id,
161
+ queryParams: {
162
+ fields: { products: 'name,cost,profit_margin' }
163
+ }
164
+ });
165
+ console.log('Product with sparse fields includig cost:', productWithCost);
166
+
167
+
168
+
169
+
170
+ // Fetch product with reviews
171
+ const productWithReviews = await api.resources.products.get({
172
+ id: product.id,
173
+ queryParams: {
174
+ include: ['reviews']
175
+ }
176
+ });
177
+ console.log('Product With Reviews:', productWithReviews);
178
+
179
+ // Use sparse fieldsets on included resources
180
+ const productWithSparseReviews = await api.resources.products.get({
181
+ id: product.id,
182
+ queryParams: {
183
+ include: ['reviews'],
184
+ fields: {
185
+ products: 'name,price',
186
+ reviews: 'reviewer_name,rating,helpfulness_score' // Only these fields
187
+ }
188
+ }
189
+ });
190
+ console.log('Product With Sparse Reviews:', productWithSparseReviews);
191
+
192
+ // Create a review with no votes
193
+ const review3 = await api.resources.reviews.post({
194
+ product_id: product.id,
195
+ reviewer_name: 'Charlie',
196
+ rating: 3,
197
+ comment: 'Average product',
198
+ helpful_votes: 0,
199
+ total_votes: 0 // This will cause division by zero
200
+ });
201
+
202
+ const fetchedReviewWithError = await api.resources.reviews.get({ id: review3.id });
203
+ console.log('Fetched review (with error in helpfulness score):', fetchedReviewWithError)
204
+
205
+
206
+
207
+
208
+
209
+
210
+
211
+
212
+
213
+
214
+
215
+
216
+
217
+
218
+
219
+
220
+
221
+
222
+
223
+
224
+
225
+
226
+
227
+
228
+ // Createthe express server and add the API's routes
229
+ const app = express();
230
+ app.use(api.http.express.router);
231
+ app.use(api.http.express.notFoundRouter);
232
+
233
+ await knex.destroy();
234
+
235
+
236
+ //app.listen(3000, () => {
237
+ // console.log('Express server started on port 3000. API available at http://localhost:3000/api');
238
+ //});