@objectql/server 1.4.0 → 1.5.0

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.
package/dist/openapi.js CHANGED
@@ -6,7 +6,40 @@ function generateOpenAPI(app) {
6
6
  const objects = registry.list('object');
7
7
  const paths = {};
8
8
  const schemas = {};
9
- // 1. Generate Schemas
9
+ // 1. JSON-RPC Endpoint
10
+ paths['/api/objectql'] = {
11
+ post: {
12
+ summary: 'JSON-RPC Entry Point',
13
+ description: 'Execute any ObjectQL operation via a JSON body.',
14
+ tags: ['System'],
15
+ requestBody: {
16
+ content: {
17
+ 'application/json': {
18
+ schema: {
19
+ type: 'object',
20
+ properties: {
21
+ op: { type: 'string', enum: ['find', 'findOne', 'create', 'update', 'delete', 'count', 'action'] },
22
+ object: { type: 'string' },
23
+ args: { type: 'object' }
24
+ },
25
+ required: ['op', 'object']
26
+ }
27
+ }
28
+ }
29
+ },
30
+ responses: {
31
+ 200: {
32
+ description: 'Operation Result',
33
+ content: {
34
+ 'application/json': {
35
+ schema: { type: 'object' } // Dynamic result
36
+ }
37
+ }
38
+ }
39
+ }
40
+ }
41
+ };
42
+ // 2. Generate Schemas
10
43
  for (const obj of objects) {
11
44
  const schemaName = obj.name;
12
45
  const properties = {};
@@ -17,29 +50,21 @@ function generateOpenAPI(app) {
17
50
  type: 'object',
18
51
  properties
19
52
  };
20
- // 2. Generate Paths (RPC Style representation for documentation purposes)
21
- // Since we only have one endpoint, we might document operations as descriptions
22
- // Or if we support REST style in the future, we would add /object paths here.
23
- // For now, let's document the "Virtual" REST API that could exist via a gateway
24
- // OR just document the schema.
25
- // Let's assume the user might want to see standard CRUD paths even if implementation is RPC,
26
- // so they can pass it to frontend generators?
27
- // No, that would be misleading if the server doesn't support it.
28
- // Let's DOCUMENT the RPC operations as if they were paths,
29
- // OR clearer: One path /api/objectql with polymorphic body?
30
- // Swagger UI handles oneOf poorly for top level operations sometimes.
31
53
  }
32
- // Let's do a "Virtual" REST path generation for better visualization
33
- // Assuming we WILL support REST mapping in this update.
54
+ // 3. REST API Paths
34
55
  for (const obj of objects) {
35
56
  const name = obj.name;
36
- // GET /name (List)
37
- paths[`/${name}`] = {
57
+ const basePath = `/api/data/${name}`; // Standard REST Path
58
+ // GET /api/data/:name (List)
59
+ paths[basePath] = {
38
60
  get: {
39
- summary: `List ${name}s`,
61
+ summary: `List ${name}`,
40
62
  tags: [name],
41
63
  parameters: [
42
- { name: 'filter', in: 'query', schema: { type: 'string' }, description: 'JSON filter args' }
64
+ { name: 'filter', in: 'query', schema: { type: 'string' }, description: 'JSON filter args' },
65
+ { name: 'fields', in: 'query', schema: { type: 'string' }, description: 'Comma-separated fields to return' },
66
+ { name: 'top', in: 'query', schema: { type: 'integer' }, description: 'Limit' },
67
+ { name: 'skip', in: 'query', schema: { type: 'integer' }, description: 'Offset' }
43
68
  ],
44
69
  responses: {
45
70
  200: {
@@ -77,26 +102,50 @@ function generateOpenAPI(app) {
77
102
  }
78
103
  }
79
104
  };
80
- // GET /name/{id}
81
- paths[`/${name}/{id}`] = {
105
+ // /api/data/:name/:id
106
+ paths[`${basePath}/{id}`] = {
82
107
  get: {
83
108
  summary: `Get ${name}`,
84
109
  tags: [name],
85
110
  parameters: [{ name: 'id', in: 'path', required: true, schema: { type: 'string' } }],
86
- responses: { 200: { description: 'Item' } }
111
+ responses: {
112
+ 200: {
113
+ description: 'Item',
114
+ content: {
115
+ 'application/json': {
116
+ schema: { $ref: `#/components/schemas/${name}` }
117
+ }
118
+ }
119
+ }
120
+ }
87
121
  },
88
122
  patch: {
89
123
  summary: `Update ${name}`,
90
124
  tags: [name],
91
125
  parameters: [{ name: 'id', in: 'path', required: true, schema: { type: 'string' } }],
92
- requestBody: { content: { 'application/json': { schema: { type: 'object', properties: { data: { type: 'object' } } } } } },
93
- responses: { 200: { description: 'Updated' } }
126
+ requestBody: {
127
+ content: {
128
+ 'application/json': {
129
+ schema: {
130
+ type: 'object',
131
+ properties: {
132
+ data: { type: 'object' }
133
+ }
134
+ }
135
+ }
136
+ }
137
+ },
138
+ responses: {
139
+ 200: { description: 'Updated' }
140
+ }
94
141
  },
95
142
  delete: {
96
143
  summary: `Delete ${name}`,
97
144
  tags: [name],
98
145
  parameters: [{ name: 'id', in: 'path', required: true, schema: { type: 'string' } }],
99
- responses: { 200: { description: 'Deleted' } }
146
+ responses: {
147
+ 200: { description: 'Deleted' }
148
+ }
100
149
  }
101
150
  };
102
151
  }
@@ -1 +1 @@
1
- {"version":3,"file":"openapi.js","sourceRoot":"","sources":["../src/openapi.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"openapi.js","sourceRoot":"","sources":["../src/openapi.ts"],"names":[],"mappings":";;AAcA,0CAyKC;AAzKD,SAAgB,eAAe,CAAC,GAAc;IAC1C,MAAM,QAAQ,GAAI,GAAW,CAAC,QAAQ,CAAC,CAAC,iCAAiC;IACzE,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAmB,CAAC;IAE1D,MAAM,KAAK,GAAwB,EAAE,CAAC;IACtC,MAAM,OAAO,GAAwB,EAAE,CAAC;IAGxC,uBAAuB;IACvB,KAAK,CAAC,eAAe,CAAC,GAAG;QACrB,IAAI,EAAE;YACF,OAAO,EAAE,sBAAsB;YAC/B,WAAW,EAAE,iDAAiD;YAC9D,IAAI,EAAE,CAAC,QAAQ,CAAC;YAChB,WAAW,EAAE;gBACT,OAAO,EAAE;oBACL,kBAAkB,EAAE;wBAChB,MAAM,EAAE;4BACJ,IAAI,EAAE,QAAQ;4BACd,UAAU,EAAE;gCACR,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE;gCAClG,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gCAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;6BAC3B;4BACD,QAAQ,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC;yBAC7B;qBACJ;iBACJ;aACJ;YACD,SAAS,EAAE;gBACP,GAAG,EAAE;oBACD,WAAW,EAAE,kBAAkB;oBAC/B,OAAO,EAAE;wBACL,kBAAkB,EAAE;4BAChB,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,iBAAiB;yBAC/C;qBACJ;iBACJ;aACJ;SACJ;KACJ,CAAC;IAEF,sBAAsB;IACtB,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QACxB,MAAM,UAAU,GAAG,GAAG,CAAC,IAAI,CAAC;QAC5B,MAAM,UAAU,GAAwB,EAAE,CAAC;QAE3C,KAAK,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1D,UAAU,CAAC,SAAS,CAAC,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;QACzD,CAAC;QAED,OAAO,CAAC,UAAU,CAAC,GAAG;YAClB,IAAI,EAAE,QAAQ;YACd,UAAU;SACb,CAAC;IACN,CAAC;IAED,oBAAoB;IACpB,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;QACtB,MAAM,QAAQ,GAAG,aAAa,IAAI,EAAE,CAAC,CAAC,qBAAqB;QAE3D,6BAA6B;QAC7B,KAAK,CAAC,QAAQ,CAAC,GAAG;YACd,GAAG,EAAE;gBACD,OAAO,EAAE,QAAQ,IAAI,EAAE;gBACvB,IAAI,EAAE,CAAC,IAAI,CAAC;gBACZ,UAAU,EAAE;oBACR,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,WAAW,EAAE,kBAAkB,EAAE;oBAC5F,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,WAAW,EAAE,kCAAkC,EAAE;oBAC5G,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE;oBAC/E,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE;iBACpF;gBACD,SAAS,EAAE;oBACP,GAAG,EAAE;wBACD,WAAW,EAAE,WAAW,IAAI,EAAE;wBAC9B,OAAO,EAAE;4BACL,kBAAkB,EAAE;gCAChB,MAAM,EAAE;oCACJ,IAAI,EAAE,QAAQ;oCACd,UAAU,EAAE;wCACR,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,wBAAwB,IAAI,EAAE,EAAE,EAAE;qCAC3E;iCACJ;6BACJ;yBACJ;qBACJ;iBACJ;aACJ;YACD,IAAI,EAAE;gBACF,OAAO,EAAE,UAAU,IAAI,EAAE;gBACzB,IAAI,EAAE,CAAC,IAAI,CAAC;gBACZ,WAAW,EAAE;oBACT,OAAO,EAAE;wBACL,kBAAkB,EAAE;4BAChB,MAAM,EAAE;gCACJ,IAAI,EAAE,QAAQ;gCACd,UAAU,EAAE;oCACR,IAAI,EAAE,EAAE,IAAI,EAAE,wBAAwB,IAAI,EAAE,EAAE;iCACjD;6BACJ;yBACJ;qBACJ;iBACJ;gBACD,SAAS,EAAE;oBACP,GAAG,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE;iBAClC;aACJ;SACJ,CAAC;QAEF,sBAAsB;QACtB,KAAK,CAAC,GAAG,QAAQ,OAAO,CAAC,GAAG;YACxB,GAAG,EAAE;gBACD,OAAO,EAAE,OAAO,IAAI,EAAE;gBACtB,IAAI,EAAE,CAAC,IAAI,CAAC;gBACZ,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC;gBACpF,SAAS,EAAE;oBACP,GAAG,EAAE;wBACD,WAAW,EAAE,MAAM;wBACnB,OAAO,EAAE;4BACL,kBAAkB,EAAE;gCAChB,MAAM,EAAE,EAAE,IAAI,EAAE,wBAAwB,IAAI,EAAE,EAAE;6BACnD;yBACJ;qBACJ;iBACJ;aACJ;YACD,KAAK,EAAE;gBACH,OAAO,EAAE,UAAU,IAAI,EAAE;gBACzB,IAAI,EAAE,CAAC,IAAI,CAAC;gBACZ,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC;gBACpF,WAAW,EAAE;oBACT,OAAO,EAAE;wBACL,kBAAkB,EAAE;4BAChB,MAAM,EAAE;gCACJ,IAAI,EAAE,QAAQ;gCACd,UAAU,EAAE;oCACR,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;iCAC3B;6BACJ;yBACJ;qBACJ;iBACJ;gBACD,SAAS,EAAE;oBACP,GAAG,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE;iBAClC;aACJ;YACD,MAAM,EAAE;gBACJ,OAAO,EAAE,UAAU,IAAI,EAAE;gBACzB,IAAI,EAAE,CAAC,IAAI,CAAC;gBACZ,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC;gBACpF,SAAS,EAAE;oBACP,GAAG,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE;iBAClC;aACJ;SACJ,CAAC;IACN,CAAC;IAED,OAAO;QACH,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE;YACF,KAAK,EAAE,cAAc;YACrB,OAAO,EAAE,OAAO;SACnB;QACD,KAAK;QACL,UAAU,EAAE;YACR,OAAO;SACV;KACJ,CAAC;AACN,CAAC;AAED,SAAS,qBAAqB,CAAC,KAA2B;IACtD,MAAM,IAAI,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;IAE5D,QAAQ,IAAI,EAAE,CAAC;QACX,KAAK,QAAQ,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;QACzC,KAAK,SAAS,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;QAC3C,KAAK,OAAO,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;QACxC,KAAK,SAAS,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;QAC3C,KAAK,MAAM,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;QAC5D,KAAK,MAAM,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;QACvC,OAAO,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,8BAA8B;IACtE,CAAC;AACL,CAAC"}
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@objectql/server",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "HTTP Server Adapter for ObjectQL",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "dependencies": {
8
8
  "js-yaml": "^4.1.1",
9
- "@objectql/types": "1.4.0",
10
- "@objectql/core": "1.4.0"
9
+ "@objectql/core": "1.5.0",
10
+ "@objectql/types": "1.5.0"
11
11
  },
12
12
  "devDependencies": {
13
13
  "@types/js-yaml": "^4.0.9",
@@ -23,13 +23,13 @@ export function createNodeHandler(app: IObjectQL) {
23
23
 
24
24
  const handleRequest = async (json: any) => {
25
25
  try {
26
- // TODO: Parse user from header or request override
26
+ // Determine Operation based on JSON or previously derived info
27
27
  const qlReq: ObjectQLRequest = {
28
28
  op: json.op,
29
29
  object: json.object,
30
30
  args: json.args,
31
- user: json.user, // For dev/testing, allowing user injection
32
- ai_context: json.ai_context // Support AI context
31
+ user: json.user,
32
+ ai_context: json.ai_context
33
33
  };
34
34
 
35
35
  const result = await server.handle(qlReq);
@@ -66,6 +66,7 @@ export function createNodeHandler(app: IObjectQL) {
66
66
  res.statusCode = statusCode;
67
67
  res.end(JSON.stringify(result));
68
68
  } catch (e) {
69
+ console.error(e);
69
70
  res.statusCode = 500;
70
71
  res.end(JSON.stringify({
71
72
  error: {
@@ -76,56 +77,134 @@ export function createNodeHandler(app: IObjectQL) {
76
77
  }
77
78
  };
78
79
 
79
- if (req.method !== 'POST') {
80
- // Attempt to handle GET requests for simple queries like /api/objectql/table
81
- // We map this to a find operation
82
- // URL pattern: /api/objectql/:objectName
83
- const match = req.url?.match(/\/([^\/?]+)(\?.*)?$/);
84
- if (req.method === 'GET' && match) {
85
- const objectName = match[1];
86
- // Ignore special paths
87
- if (objectName !== 'openapi.json' && objectName !== 'metadata') {
88
- await handleRequest({
89
- op: 'find',
80
+ // Parse URL
81
+ const urlObj = new URL(req.url || '/', `http://${req.headers.host || 'localhost'}`);
82
+ const pathName = urlObj.pathname;
83
+ const method = req.method;
84
+
85
+ // 1. JSON-RPC: POST /api/objectql
86
+ if (pathName === '/api/objectql' && method === 'POST') {
87
+ await processBody(req, async (json) => {
88
+ await handleRequest(json);
89
+ }, res);
90
+ return;
91
+ }
92
+
93
+ // 2. REST API: /api/data/:object and /api/data/:object/:id
94
+ // Regex to match /api/data/objectName(/id)?
95
+ const restMatch = pathName.match(/^\/api\/data\/([^/]+)(?:\/(.+))?$/);
96
+
97
+ if (restMatch) {
98
+ const objectName = restMatch[1];
99
+ const id = restMatch[2];
100
+ const query = Object.fromEntries(urlObj.searchParams.entries());
101
+
102
+ if (method === 'GET') {
103
+ // GET /api/data/:object/:id -> findOne
104
+ if (id) {
105
+ await handleRequest({
106
+ op: 'findOne',
90
107
  object: objectName,
91
- args: {} // TODO: Parse query params to args
92
- });
93
- return;
108
+ args: { filters: [['_id', '=', id]] } // Assuming _id or id mapping
109
+ });
110
+ }
111
+ // GET /api/data/:object -> find (List)
112
+ else {
113
+ // Parse standard params
114
+ const args: any = {};
115
+ if (query.fields) args.fields = (query.fields as string).split(',');
116
+ if (query.top) args.limit = parseInt(query.top as string);
117
+ if (query.skip) args.skip = parseInt(query.skip as string);
118
+ if (query.filter) {
119
+ try {
120
+ args.filters = JSON.parse(query.filter as string);
121
+ } catch (e) {
122
+ // ignore invalid filter json
123
+ }
124
+ }
125
+ await handleRequest({ op: 'find', object: objectName, args });
94
126
  }
127
+ return;
95
128
  }
96
129
 
97
- res.statusCode = 405;
98
- res.end(JSON.stringify({
99
- error: {
100
- code: ErrorCode.INVALID_REQUEST,
101
- message: 'Method Not Allowed'
102
- }
103
- }));
104
- return;
130
+ if (method === 'POST' && !id) {
131
+ // POST /api/data/:object -> create
132
+ await processBody(req, async (body) => {
133
+ await handleRequest({
134
+ op: 'create',
135
+ object: objectName,
136
+ args: body.data || body // Support enclosed in data or flat
137
+ });
138
+ }, res);
139
+ return;
140
+ }
141
+
142
+ if (method === 'PATCH' && id) {
143
+ // PATCH /api/data/:object/:id -> update
144
+ await processBody(req, async (body) => {
145
+ await handleRequest({
146
+ op: 'update',
147
+ object: objectName,
148
+ args: {
149
+ id: id,
150
+ data: body.data || body
151
+ }
152
+ });
153
+ }, res);
154
+ return;
155
+ }
156
+
157
+ if (method === 'DELETE' && id) {
158
+ // DELETE /api/data/:object/:id -> delete
159
+ await handleRequest({
160
+ op: 'delete',
161
+ object: objectName,
162
+ args: { id: id }
163
+ });
164
+ return;
165
+ }
166
+ }
167
+
168
+ // Fallback or 404
169
+ if (req.method === 'POST') {
170
+ // Fallback for root POSTs if people forget /api/objectql but send to /api something
171
+ await processBody(req, handleRequest, res);
172
+ return;
105
173
  }
106
174
 
107
- // 1. Check if body is already parsed (e.g. by express.json())
108
- if (req.body && typeof req.body === 'object') {
109
- await handleRequest(req.body);
175
+ // Special case for root: since we accept POST / (RPC), correct response for GET / is 405
176
+ if (pathName === '/') {
177
+ res.setHeader('Allow', 'POST');
178
+ res.statusCode = 405;
179
+ res.end(JSON.stringify({ error: { code: ErrorCode.INVALID_REQUEST, message: 'Method Not Allowed. Use POST for JSON-RPC.' } }));
110
180
  return;
111
181
  }
112
182
 
113
- // 2. Parse Body from stream
114
- let body = '';
115
- req.on('data', chunk => body += chunk);
116
- req.on('end', async () => {
117
- try {
118
- const json = JSON.parse(body);
119
- await handleRequest(json);
120
- } catch (e) {
121
- res.statusCode = 400;
122
- res.end(JSON.stringify({
123
- error: {
124
- code: ErrorCode.INVALID_REQUEST,
125
- message: 'Invalid JSON'
126
- }
127
- }));
128
- }
129
- });
183
+ res.statusCode = 404;
184
+ res.end(JSON.stringify({ error: { code: ErrorCode.NOT_FOUND, message: 'Not Found' } }));
130
185
  };
131
186
  }
187
+
188
+ // Helper to process body
189
+ async function processBody(req: IncomingMessage & { body?: any }, callback: (json: any) => Promise<void>, res: ServerResponse) {
190
+ if (req.body && typeof req.body === 'object') {
191
+ return callback(req.body);
192
+ }
193
+
194
+ let body = '';
195
+ req.on('data', chunk => body += chunk);
196
+ req.on('end', async () => {
197
+ try {
198
+ const json = body ? JSON.parse(body) : {};
199
+ await callback(json);
200
+ } catch (e) {
201
+ res.statusCode = 400;
202
+ res.end(JSON.stringify({
203
+ error: {
204
+ code: 'INVALID_JSON',
205
+ message: 'Invalid JSON body'
206
+ }
207
+ }));
208
+ }
209
+ });
210
+ }