@unispechq/unispec-schema 0.4.0 → 0.4.2

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 (44) hide show
  1. package/README.md +170 -162
  2. package/examples/README.md +128 -0
  3. package/examples/invalid/config/additional-properties.json +26 -0
  4. package/examples/invalid/config/missing-service-name.json +22 -0
  5. package/examples/invalid/config/missing-version.json +6 -0
  6. package/examples/invalid/graphql-additional-properties.json +22 -0
  7. package/examples/invalid/graphql-missing-arg-type.json +26 -0
  8. package/examples/invalid/graphql-missing-name.json +19 -0
  9. package/examples/invalid/graphql-missing-schema.json +19 -0
  10. package/examples/invalid/mixed-invalid-protocol.json +26 -0
  11. package/examples/invalid/mixed-missing-graphql-schema.json +33 -0
  12. package/examples/invalid/mixed-multiple-errors.json +41 -0
  13. package/examples/invalid/rest-additional-properties.json +25 -0
  14. package/examples/invalid/rest-invalid-identifiers.json +29 -0
  15. package/examples/invalid/rest-invalid-method.json +23 -0
  16. package/examples/invalid/rest-missing-required.json +21 -0
  17. package/examples/invalid/websocket-additional-properties.json +27 -0
  18. package/examples/invalid/websocket-invalid-direction.json +27 -0
  19. package/examples/invalid/websocket-missing-channel-name.json +25 -0
  20. package/examples/invalid/websocket-missing-message-name.json +25 -0
  21. package/examples/valid/config/complete.json +61 -0
  22. package/examples/valid/config/minimal.json +8 -0
  23. package/examples/valid/graphql-complete.json +348 -0
  24. package/examples/valid/graphql-simple.json +34 -0
  25. package/examples/valid/mixed-complete.json +799 -0
  26. package/examples/valid/mixed-simple.json +56 -0
  27. package/examples/valid/rest-complete.json +539 -0
  28. package/examples/valid/rest-simple.json +279 -0
  29. package/examples/valid/websocket-complete.json +471 -0
  30. package/examples/valid/websocket-simple.json +116 -0
  31. package/index.cjs +7 -7
  32. package/index.d.ts +9 -9
  33. package/index.mjs +9 -9
  34. package/package.json +15 -6
  35. package/schema/index.json +19 -19
  36. package/schema/types/common.schema.json +195 -195
  37. package/schema/types/graphql.schema.json +172 -172
  38. package/schema/types/rest.schema.json +221 -226
  39. package/schema/types/schemas.schema.json +84 -84
  40. package/schema/types/service.schema.json +158 -158
  41. package/schema/types/websocket.schema.json +185 -190
  42. package/schema/unispec-config.schema.json +509 -509
  43. package/schema/unispec-tests.schema.json +368 -378
  44. package/schema/unispec.schema.json +18 -23
@@ -0,0 +1,41 @@
1
+ {
2
+ "unispecVersion": "0.1.0",
3
+ "service": {
4
+ "description": "API with multiple errors",
5
+ "protocols": {
6
+ "rest": {
7
+ "routes": [
8
+ {
9
+ "name": "",
10
+ "method": "INVALID",
11
+ "responses": {
12
+ "200": {
13
+ "description": "Success"
14
+ }
15
+ }
16
+ }
17
+ ]
18
+ },
19
+ "graphql": {
20
+ "queries": [
21
+ {
22
+ "description": "Missing name",
23
+ "returnType": "[User!]!"
24
+ }
25
+ ]
26
+ },
27
+ "websocket": {
28
+ "channels": [
29
+ {
30
+ "messages": [
31
+ {
32
+ "description": "Missing name",
33
+ "direction": "invalid"
34
+ }
35
+ ]
36
+ }
37
+ ]
38
+ }
39
+ }
40
+ }
41
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "unispecVersion": "0.1.0",
3
+ "service": {
4
+ "name": "extra-props-api",
5
+ "description": "API with additional properties",
6
+ "protocols": {
7
+ "rest": {
8
+ "routes": [
9
+ {
10
+ "name": "getUsers",
11
+ "path": "/users",
12
+ "method": "GET",
13
+ "invalidProperty": "should not exist",
14
+ "responses": {
15
+ "200": {
16
+ "description": "Success",
17
+ "invalidProperty": "should not exist"
18
+ }
19
+ }
20
+ }
21
+ ]
22
+ }
23
+ }
24
+ }
25
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "unispecVersion": "0.1.0",
3
+ "service": {
4
+ "name": "invalid-name-with-spaces",
5
+ "description": "API with invalid service name",
6
+ "protocols": {
7
+ "rest": {
8
+ "routes": [
9
+ {
10
+ "name": "route with spaces",
11
+ "path": "/test",
12
+ "method": "GET",
13
+ "queryParams": [
14
+ {
15
+ "name": "param with spaces",
16
+ "required": false
17
+ }
18
+ ],
19
+ "responses": {
20
+ "200": {
21
+ "description": "Success"
22
+ }
23
+ }
24
+ }
25
+ ]
26
+ }
27
+ }
28
+ }
29
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "unispecVersion": "0.1.0",
3
+ "service": {
4
+ "name": "invalid-method-api",
5
+ "description": "API with invalid HTTP method",
6
+ "protocols": {
7
+ "rest": {
8
+ "routes": [
9
+ {
10
+ "name": "invalidMethod",
11
+ "path": "/test",
12
+ "method": "INVALID",
13
+ "responses": {
14
+ "200": {
15
+ "description": "Success"
16
+ }
17
+ }
18
+ }
19
+ ]
20
+ }
21
+ }
22
+ }
23
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "unispecVersion": "0.1.0",
3
+ "service": {
4
+ "description": "API with missing required fields",
5
+ "protocols": {
6
+ "rest": {
7
+ "routes": [
8
+ {
9
+ "name": "getUsers",
10
+ "method": "GET",
11
+ "responses": {
12
+ "200": {
13
+ "description": "Success"
14
+ }
15
+ }
16
+ }
17
+ ]
18
+ }
19
+ }
20
+ }
21
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "unispecVersion": "0.1.0",
3
+ "service": {
4
+ "name": "invalid-websocket-api",
5
+ "description": "WebSocket API with additional properties",
6
+ "protocols": {
7
+ "websocket": {
8
+ "url": "/ws",
9
+ "channels": [
10
+ {
11
+ "name": "notifications",
12
+ "description": "Notification channel",
13
+ "invalidProperty": "should not exist",
14
+ "messages": [
15
+ {
16
+ "name": "message",
17
+ "description": "Message",
18
+ "invalidProperty": "should not exist",
19
+ "schemaRef": "Message"
20
+ }
21
+ ]
22
+ }
23
+ ]
24
+ }
25
+ }
26
+ }
27
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "unispecVersion": "0.1.0",
3
+ "service": {
4
+ "name": "invalid-websocket-api",
5
+ "description": "WebSocket API with invalid direction",
6
+ "protocols": {
7
+ "websocket": {
8
+ "url": "/ws",
9
+ "channels": [
10
+ {
11
+ "name": "invalid-channel",
12
+ "description": "Channel with invalid direction",
13
+ "direction": "invalid",
14
+ "messages": [
15
+ {
16
+ "name": "message",
17
+ "description": "Message with invalid direction",
18
+ "direction": "invalid",
19
+ "schemaRef": "Message"
20
+ }
21
+ ]
22
+ }
23
+ ]
24
+ }
25
+ }
26
+ }
27
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "unispecVersion": "0.1.0",
3
+ "service": {
4
+ "name": "invalid-websocket-api",
5
+ "description": "WebSocket API with invalid channel",
6
+ "protocols": {
7
+ "websocket": {
8
+ "url": "/ws",
9
+ "channels": [
10
+ {
11
+ "description": "Channel without name",
12
+ "direction": "both",
13
+ "messages": [
14
+ {
15
+ "name": "message",
16
+ "direction": "both",
17
+ "schemaRef": "Message"
18
+ }
19
+ ]
20
+ }
21
+ ]
22
+ }
23
+ }
24
+ }
25
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "unispecVersion": "0.1.0",
3
+ "service": {
4
+ "name": "invalid-websocket-api",
5
+ "description": "WebSocket API with invalid message",
6
+ "protocols": {
7
+ "websocket": {
8
+ "url": "/ws",
9
+ "channels": [
10
+ {
11
+ "name": "notifications",
12
+ "description": "Notification channel",
13
+ "messages": [
14
+ {
15
+ "description": "Message without name",
16
+ "direction": "subscribe",
17
+ "schemaRef": "Notification"
18
+ }
19
+ ]
20
+ }
21
+ ]
22
+ }
23
+ }
24
+ }
25
+ }
@@ -0,0 +1,61 @@
1
+ {
2
+ "unispecVersion": "0.1.0",
3
+ "service": {
4
+ "name": "complete-service",
5
+ "description": "Complete configuration with multiple services",
6
+ "version": "1.0.0",
7
+ "baseUrl": "https://api.example.com",
8
+ "servers": [
9
+ {
10
+ "url": "https://staging-api.example.com",
11
+ "description": "Staging environment"
12
+ },
13
+ {
14
+ "url": "https://prod-api.example.com",
15
+ "description": "Production environment"
16
+ }
17
+ ],
18
+ "contact": {
19
+ "name": "API Support",
20
+ "email": "support@example.com"
21
+ },
22
+ "license": {
23
+ "name": "MIT",
24
+ "url": "https://opensource.org/licenses/MIT"
25
+ },
26
+ "protocols": {
27
+ "rest": {
28
+ "routes": [
29
+ {
30
+ "name": "getUsers",
31
+ "summary": "List all users",
32
+ "path": "/users",
33
+ "method": "GET",
34
+ "responses": {
35
+ "200": {
36
+ "description": "List of users"
37
+ }
38
+ }
39
+ }
40
+ ]
41
+ },
42
+ "graphql": {
43
+ "url": "/graphql",
44
+ "schema": "type Query {\n users: [User!]!\n}\n\ntype User {\n id: ID!\n name: String!\n}\n"
45
+ }
46
+ },
47
+ "schemas": {
48
+ "User": {
49
+ "type": "object",
50
+ "properties": {
51
+ "id": {
52
+ "type": "string"
53
+ },
54
+ "name": {
55
+ "type": "string"
56
+ }
57
+ }
58
+ }
59
+ }
60
+ }
61
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "unispecVersion": "0.1.0",
3
+ "service": {
4
+ "name": "minimal-service",
5
+ "description": "Minimal configuration with single service",
6
+ "version": "1.0.0"
7
+ }
8
+ }
@@ -0,0 +1,348 @@
1
+ {
2
+ "unispecVersion": "0.1.0",
3
+ "service": {
4
+ "name": "user-graphql-api",
5
+ "description": "Complete user management GraphQL API",
6
+ "version": "1.0.0",
7
+ "baseUrl": "https://api.example.com",
8
+ "contact": {
9
+ "name": "GraphQL Support",
10
+ "email": "graphql@example.com"
11
+ },
12
+ "tags": ["users", "graphql", "authentication"],
13
+ "securitySchemes": {
14
+ "bearerAuth": {
15
+ "type": "http",
16
+ "scheme": "bearer",
17
+ "bearerFormat": "JWT",
18
+ "description": "JWT authentication token"
19
+ }
20
+ },
21
+ "protocols": {
22
+ "graphql": {
23
+ "url": "/graphql",
24
+ "schema": "type User {\n id: ID!\n email: String!\n firstName: String!\n lastName: String!\n phone: String\n createdAt: String!\n updatedAt: String!\n posts: [Post!]!\n}\n\ntype Post {\n id: ID!\n title: String!\n content: String!\n author: User!\n category: String!\n tags: [String!]!\n published: Boolean!\n createdAt: String!\n updatedAt: String!\n}\n\ntype AuthPayload {\n token: String!\n user: User!\n}\n\ntype Query {\n users(page: Int = 1, limit: Int = 20, search: String): UserConnection!\n user(id: ID!): User\n posts(category: String, published: Boolean = true, authorId: ID): PostConnection!\n post(id: ID!): Post\n me: User\n}\n\ntype Mutation {\n createUser(input: CreateUserInput!): User!\n updateUser(id: ID!, input: UpdateUserInput!): User!\n deleteUser(id: ID!): Boolean!\n createPost(input: CreatePostInput!): Post!\n updatePost(id: ID!, input: UpdatePostInput!): Post!\n deletePost(id: ID!): Boolean!\n login(email: String!, password: String!): AuthPayload!\n logout: Boolean!\n}\n\ntype Subscription {\n userCreated: User!\n userUpdated(id: ID): User!\n postCreated(authorId: ID): Post!\n postUpdated(id: ID): Post!\n}\n\ntype UserConnection {\n users: [User!]!\n pageInfo: PageInfo!\n totalCount: Int!\n}\n\ntype PostConnection {\n posts: [Post!]!\n pageInfo: PageInfo!\n totalCount: Int!\n}\n\ntype PageInfo {\n hasNextPage: Boolean!\n hasPreviousPage: Boolean!\n startCursor: String\n endCursor: String\n}\n\ninput CreateUserInput {\n email: String!\n password: String!\n firstName: String!\n lastName: String!\n phone: String\n}\n\ninput UpdateUserInput {\n firstName: String\n lastName: String\n phone: String\n}\n\ninput CreatePostInput {\n title: String!\n content: String!\n category: String!\n tags: [String!]\n published: Boolean = false\n}\n\ninput UpdatePostInput {\n title: String\n content: String\n category: String\n tags: [String!]\n published: Boolean\n}\n",
25
+ "headers": [
26
+ {
27
+ "name": "Authorization",
28
+ "description": "Bearer token for authentication",
29
+ "required": true
30
+ },
31
+ {
32
+ "name": "Content-Type",
33
+ "description": "Request content type",
34
+ "defaultValue": "application/json"
35
+ }
36
+ ],
37
+ "queries": [
38
+ {
39
+ "name": "users",
40
+ "description": "Get paginated list of users",
41
+ "args": [
42
+ {
43
+ "name": "page",
44
+ "type": "Int",
45
+ "description": "Page number for pagination",
46
+ "defaultValue": 1
47
+ },
48
+ {
49
+ "name": "limit",
50
+ "type": "Int",
51
+ "description": "Number of items per page",
52
+ "defaultValue": 20
53
+ },
54
+ {
55
+ "name": "search",
56
+ "type": "String",
57
+ "description": "Search term for filtering users"
58
+ }
59
+ ],
60
+ "returnType": "UserConnection!",
61
+ "security": [
62
+ {
63
+ "bearerAuth": []
64
+ }
65
+ ]
66
+ },
67
+ {
68
+ "name": "user",
69
+ "description": "Get user by ID",
70
+ "args": [
71
+ {
72
+ "name": "id",
73
+ "type": "ID!",
74
+ "description": "User ID"
75
+ }
76
+ ],
77
+ "returnType": "User!",
78
+ "security": [
79
+ {
80
+ "bearerAuth": []
81
+ }
82
+ ]
83
+ },
84
+ {
85
+ "name": "posts",
86
+ "description": "Get paginated list of posts",
87
+ "args": [
88
+ {
89
+ "name": "category",
90
+ "type": "String",
91
+ "description": "Filter by category"
92
+ },
93
+ {
94
+ "name": "published",
95
+ "type": "Boolean",
96
+ "description": "Filter by published status",
97
+ "defaultValue": true
98
+ },
99
+ {
100
+ "name": "authorId",
101
+ "type": "ID",
102
+ "description": "Filter by author ID"
103
+ }
104
+ ],
105
+ "returnType": "PostConnection!",
106
+ "security": [
107
+ {
108
+ "bearerAuth": []
109
+ }
110
+ ]
111
+ },
112
+ {
113
+ "name": "post",
114
+ "description": "Get post by ID",
115
+ "args": [
116
+ {
117
+ "name": "id",
118
+ "type": "ID!",
119
+ "description": "Post ID"
120
+ }
121
+ ],
122
+ "returnType": "Post!",
123
+ "security": [
124
+ {
125
+ "bearerAuth": []
126
+ }
127
+ ]
128
+ },
129
+ {
130
+ "name": "me",
131
+ "description": "Get current authenticated user",
132
+ "returnType": "User!",
133
+ "security": [
134
+ {
135
+ "bearerAuth": []
136
+ }
137
+ ]
138
+ }
139
+ ],
140
+ "mutations": [
141
+ {
142
+ "name": "createUser",
143
+ "description": "Create a new user",
144
+ "args": [
145
+ {
146
+ "name": "input",
147
+ "type": "CreateUserInput!",
148
+ "description": "User data for creation"
149
+ }
150
+ ],
151
+ "returnType": "User!",
152
+ "security": [
153
+ {
154
+ "bearerAuth": []
155
+ }
156
+ ]
157
+ },
158
+ {
159
+ "name": "updateUser",
160
+ "description": "Update an existing user",
161
+ "args": [
162
+ {
163
+ "name": "id",
164
+ "type": "ID!",
165
+ "description": "User ID"
166
+ },
167
+ {
168
+ "name": "input",
169
+ "type": "UpdateUserInput!",
170
+ "description": "Updated user data"
171
+ }
172
+ ],
173
+ "returnType": "User!",
174
+ "security": [
175
+ {
176
+ "bearerAuth": []
177
+ }
178
+ ]
179
+ },
180
+ {
181
+ "name": "deleteUser",
182
+ "description": "Delete a user",
183
+ "args": [
184
+ {
185
+ "name": "id",
186
+ "type": "ID!",
187
+ "description": "User ID"
188
+ }
189
+ ],
190
+ "returnType": "Boolean!",
191
+ "security": [
192
+ {
193
+ "bearerAuth": []
194
+ }
195
+ ]
196
+ },
197
+ {
198
+ "name": "createPost",
199
+ "description": "Create a new post",
200
+ "args": [
201
+ {
202
+ "name": "input",
203
+ "type": "CreatePostInput!",
204
+ "description": "Post data for creation"
205
+ }
206
+ ],
207
+ "returnType": "Post!",
208
+ "security": [
209
+ {
210
+ "bearerAuth": []
211
+ }
212
+ ]
213
+ },
214
+ {
215
+ "name": "updatePost",
216
+ "description": "Update an existing post",
217
+ "args": [
218
+ {
219
+ "name": "id",
220
+ "type": "ID!",
221
+ "description": "Post ID"
222
+ },
223
+ {
224
+ "name": "input",
225
+ "type": "UpdatePostInput!",
226
+ "description": "Updated post data"
227
+ }
228
+ ],
229
+ "returnType": "Post!",
230
+ "security": [
231
+ {
232
+ "bearerAuth": []
233
+ }
234
+ ]
235
+ },
236
+ {
237
+ "name": "deletePost",
238
+ "description": "Delete a post",
239
+ "args": [
240
+ {
241
+ "name": "id",
242
+ "type": "ID!",
243
+ "description": "Post ID"
244
+ }
245
+ ],
246
+ "returnType": "Boolean!",
247
+ "security": [
248
+ {
249
+ "bearerAuth": []
250
+ }
251
+ ]
252
+ },
253
+ {
254
+ "name": "login",
255
+ "description": "Authenticate user and return JWT token",
256
+ "args": [
257
+ {
258
+ "name": "email",
259
+ "type": "String!",
260
+ "description": "User email address"
261
+ },
262
+ {
263
+ "name": "password",
264
+ "type": "String!",
265
+ "description": "User password"
266
+ }
267
+ ],
268
+ "returnType": "AuthPayload!",
269
+ "security": []
270
+ },
271
+ {
272
+ "name": "logout",
273
+ "description": "Logout user",
274
+ "returnType": "Boolean!",
275
+ "security": [
276
+ {
277
+ "bearerAuth": []
278
+ }
279
+ ]
280
+ }
281
+ ],
282
+ "subscriptions": [
283
+ {
284
+ "name": "userCreated",
285
+ "description": "Subscribe to new user creation events",
286
+ "returnType": "User!",
287
+ "security": [
288
+ {
289
+ "bearerAuth": []
290
+ }
291
+ ]
292
+ },
293
+ {
294
+ "name": "userUpdated",
295
+ "description": "Subscribe to user update events",
296
+ "args": [
297
+ {
298
+ "name": "id",
299
+ "type": "ID",
300
+ "description": "Filter by specific user ID"
301
+ }
302
+ ],
303
+ "returnType": "User!",
304
+ "security": [
305
+ {
306
+ "bearerAuth": []
307
+ }
308
+ ]
309
+ },
310
+ {
311
+ "name": "postCreated",
312
+ "description": "Subscribe to new post creation events",
313
+ "args": [
314
+ {
315
+ "name": "authorId",
316
+ "type": "ID",
317
+ "description": "Filter by author ID"
318
+ }
319
+ ],
320
+ "returnType": "Post!",
321
+ "security": [
322
+ {
323
+ "bearerAuth": []
324
+ }
325
+ ]
326
+ },
327
+ {
328
+ "name": "postUpdated",
329
+ "description": "Subscribe to post update events",
330
+ "args": [
331
+ {
332
+ "name": "id",
333
+ "type": "ID",
334
+ "description": "Filter by specific post ID"
335
+ }
336
+ ],
337
+ "returnType": "Post!",
338
+ "security": [
339
+ {
340
+ "bearerAuth": []
341
+ }
342
+ ]
343
+ }
344
+ ]
345
+ }
346
+ }
347
+ }
348
+ }