├── .gitattributes
├── .gitignore
├── .gitmodules
├── Demos
├── Data
│ └── samples
│ │ ├── 1password.json
│ │ ├── ablyio.json
│ │ ├── authentiqio.json
│ │ ├── ipgeolocation.json
│ │ └── petstore.json
└── OpenAPI
│ ├── Demo.Form.Main.dfm
│ ├── Demo.Form.Main.pas
│ ├── DemoOpenAPI.dpr
│ ├── DemoOpenAPI.dproj
│ └── DemoOpenAPI.res
├── LICENSE
├── Packages
├── 10.2Tokyo
│ ├── OpenAPI.dpk
│ ├── OpenAPI.dproj
│ └── OpenAPI.res
├── 10.3Rio
│ ├── OpenAPI.dpk
│ ├── OpenAPI.dproj
│ └── OpenAPI.res
├── 10.4Sydney
│ ├── OpenAPI.dpk
│ ├── OpenAPI.dproj
│ └── OpenAPI.res
├── 11.0Alexandria
│ ├── OpenAPI.dpk
│ ├── OpenAPI.dproj
│ └── OpenAPI.res
└── 12.0Athens
│ ├── OpenAPI.dpk
│ ├── OpenAPI.dproj
│ └── OpenAPI.res
├── README.md
├── Source
├── OpenAPI.Core.Exceptions.pas
├── OpenAPI.Core.Interfaces.pas
├── OpenAPI.Model.Any.pas
├── OpenAPI.Model.Base.pas
├── OpenAPI.Model.Classes.pas
├── OpenAPI.Model.Expressions.pas
├── OpenAPI.Model.JsonPointer.pas
├── OpenAPI.Model.Reference.pas
├── OpenAPI.Model.Schema.pas
└── OpenAPI.Neon.Serializers.pas
└── openapi-delphi.png
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Set the default behavior, in case people don't have core.autocrlf set.
2 | * text=auto
3 |
4 | # Explicitly declare text files you want to always be normalized and converted
5 | # to native line endings on checkout.
6 | *.pas text
7 | *.dfm text
8 |
9 | # Declare files that will always have CRLF line endings on checkout.
10 |
11 | # Denote all files that are truly binary and should not be modified.
12 | *.exe binary
13 | *.res binary
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Uncomment these types if you want even more clean repository. But be careful.
2 | # It can make harm to an existing project source. Read explanations below.
3 | #
4 | # Resource files are binaries containing manifest, project icon and version info.
5 | # They can not be viewed as text or compared by diff-tools. Consider replacing them with .rc files.
6 | #*.res
7 | #
8 | # Type library file (binary). In old Delphi versions it should be stored.
9 | # Since Delphi 2009 it is produced from .ridl file and can safely be ignored.
10 | #*.tlb
11 | #
12 | # Diagram Portfolio file. Used by the diagram editor up to Delphi 7.
13 | # Uncomment this if you are not using diagrams or use newer Delphi version.
14 | #*.ddp
15 | #
16 | # Visual LiveBindings file. Added in Delphi XE2.
17 | # Uncomment this if you are not using LiveBindings Designer.
18 | #*.vlb
19 | #
20 | # Deployment Manager configuration file for your project. Added in Delphi XE2.
21 | # Uncomment this if it is not mobile development and you do not use remote debug feature.
22 | #*.deployproj
23 | #
24 | # C++ object files produced when C/C++ Output file generation is configured.
25 | # Uncomment this if you are not using external objects (zlib library for example).
26 | #*.obj
27 | #
28 |
29 | # Delphi compiler-generated binaries (safe to delete)
30 | *.exe
31 | *.dll
32 | *.bpl
33 | *.bpi
34 | *.dcp
35 | *.so
36 | *.apk
37 | *.drc
38 | *.map
39 | *.dres
40 | *.rsm
41 | *.tds
42 | *.dcu
43 | *.lib
44 | *.a
45 | *.o
46 | *.ocx
47 |
48 | # Delphi autogenerated files (duplicated info)
49 | *.cfg
50 | *.hpp
51 | *Resource.rc
52 |
53 | # Delphi local files (user-specific info)
54 | *.local
55 | *.identcache
56 | *.projdata
57 | *.tvsconfig
58 | *.dsk
59 |
60 | # Delphi history and backups
61 | __history/
62 | __recovery/
63 | *.~*
64 |
65 | # Castalia statistics file (since XE7 Castalia is distributed with Delphi)
66 | *.stat
67 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "Libs/Neon"]
2 | path = Libs/Neon
3 | url = https://github.com/paolo-rossi/delphi-neon
4 |
--------------------------------------------------------------------------------
/Demos/Data/samples/1password.json:
--------------------------------------------------------------------------------
1 | {
2 | "openapi": "3.0.0",
3 | "info": {
4 | "title": "Events API",
5 | "description": "1Password Events API Specification.",
6 | "version": "1.0.0",
7 | "x-apisguru-categories": [
8 | "security"
9 | ],
10 | "x-logo": {
11 | "url": "https://api.apis.guru/v2/cache/logo/https_upload.wikimedia.org_wikipedia_commons_thumb_e_e3_1password-logo.svg_1280px-1password-logo.svg.png"
12 | },
13 | "x-origin": [
14 | {
15 | "format": "openapi",
16 | "url": "https://i.1password.com/media/1password-events-reporting/1password-events-api.yaml",
17 | "version": "3.0"
18 | }
19 | ],
20 | "x-providerName": "1password.com",
21 | "x-serviceName": "events"
22 | },
23 | "servers": [
24 | {
25 | "description": "1Password",
26 | "url": "https://events.1password.com"
27 | },
28 | {
29 | "description": "1Password CA",
30 | "url": "https://events.1password.ca"
31 | },
32 | {
33 | "description": "1Password EU",
34 | "url": "https://events.1password.eu"
35 | },
36 | {
37 | "description": "1Password Enterprise",
38 | "url": "https://events.ent.1password.com"
39 | }
40 | ],
41 | "paths": {
42 | "/api/auth/introspect": {
43 | "get": {
44 | "summary": "Performs introspection of the provided Bearer JWT token",
45 | "operationId": "getAuthIntrospect",
46 | "responses": {
47 | "200": {
48 | "$ref": "#/components/responses/IntrospectResponse"
49 | },
50 | "401": {
51 | "$ref": "#/components/responses/UnauthorizedErrorResponse"
52 | },
53 | "default": {
54 | "$ref": "#/components/responses/GenericErrorResponse"
55 | }
56 | },
57 | "security": [
58 | {
59 | "jwtsa": []
60 | }
61 | ],
62 | "tags": [
63 | "auth"
64 | ]
65 | }
66 | },
67 | "/api/v1/itemusages": {
68 | "post": {
69 | "description": "This endpoint requires your JSON Web Token to have the *itemusages* feature.",
70 | "operationId": "getItemUsages",
71 | "requestBody": {
72 | "$ref": "#/components/requestBodies/ItemUsagesRequest"
73 | },
74 | "responses": {
75 | "200": {
76 | "$ref": "#/components/responses/ItemUsagesResponse"
77 | },
78 | "401": {
79 | "$ref": "#/components/responses/UnauthorizedErrorResponse"
80 | },
81 | "default": {
82 | "$ref": "#/components/responses/GenericErrorResponse"
83 | }
84 | },
85 | "security": [
86 | {
87 | "jwtsa": []
88 | }
89 | ],
90 | "summary": "Retrieves item usages",
91 | "tags": [
92 | "api-v1"
93 | ]
94 | }
95 | },
96 | "/api/v1/signinattempts": {
97 | "post": {
98 | "description": "This endpoint requires your JSON Web Token to have the *signinattempts* feature.",
99 | "operationId": "getSignInAttempts",
100 | "requestBody": {
101 | "$ref": "#/components/requestBodies/SignInAttemptsRequest"
102 | },
103 | "responses": {
104 | "200": {
105 | "$ref": "#/components/responses/SignInAttemptsResponse"
106 | },
107 | "401": {
108 | "$ref": "#/components/responses/UnauthorizedErrorResponse"
109 | },
110 | "default": {
111 | "$ref": "#/components/responses/GenericErrorResponse"
112 | }
113 | },
114 | "security": [
115 | {
116 | "jwtsa": []
117 | }
118 | ],
119 | "summary": "Retrieves sign-in attempts",
120 | "tags": [
121 | "api-v1"
122 | ]
123 | }
124 | }
125 | },
126 | "components": {
127 | "examples": {
128 | "Cursor": {
129 | "summary": "Used for continued calling with a cursor",
130 | "value": {
131 | "cursor": "aGVsbG8hIGlzIGl0IG1lIHlvdSBhcmUgbG9va2luZyBmb3IK"
132 | }
133 | },
134 | "ResetCursor": {
135 | "summary": "Used for reseting the cursor",
136 | "value": {
137 | "limit": 100,
138 | "start_time": "2021-06-11T16:32:50-03:00"
139 | }
140 | }
141 | },
142 | "requestBodies": {
143 | "CursorRequest": {
144 | "content": {
145 | "application/json": {
146 | "examples": {
147 | "Continuing cursor": {
148 | "$ref": "#/components/examples/Cursor"
149 | },
150 | "Resetting cursor": {
151 | "$ref": "#/components/examples/ResetCursor"
152 | }
153 | },
154 | "schema": {
155 | "oneOf": [
156 | {
157 | "$ref": "#/components/schemas/Cursor"
158 | },
159 | {
160 | "$ref": "#/components/schemas/ResetCursor"
161 | }
162 | ]
163 | }
164 | }
165 | }
166 | },
167 | "ItemUsagesRequest": {
168 | "$ref": "#/components/requestBodies/CursorRequest"
169 | },
170 | "SignInAttemptsRequest": {
171 | "$ref": "#/components/requestBodies/CursorRequest"
172 | }
173 | },
174 | "responses": {
175 | "GenericErrorResponse": {
176 | "content": {
177 | "application/json": {
178 | "schema": {
179 | "$ref": "#/components/schemas/Error"
180 | }
181 | }
182 | },
183 | "description": "Generic error"
184 | },
185 | "IntrospectResponse": {
186 | "content": {
187 | "application/json": {
188 | "schema": {
189 | "$ref": "#/components/schemas/Introspection"
190 | }
191 | }
192 | },
193 | "description": "Introspection object"
194 | },
195 | "ItemUsagesResponse": {
196 | "content": {
197 | "application/json": {
198 | "schema": {
199 | "$ref": "#/components/schemas/ItemUsageItems"
200 | }
201 | }
202 | },
203 | "description": "Item usages response object"
204 | },
205 | "SignInAttemptsResponse": {
206 | "content": {
207 | "application/json": {
208 | "schema": {
209 | "$ref": "#/components/schemas/SignInAttemptItems"
210 | }
211 | }
212 | },
213 | "description": "Sign-in attempts response object"
214 | },
215 | "UnauthorizedErrorResponse": {
216 | "content": {
217 | "application/json": {
218 | "schema": {
219 | "$ref": "#/components/schemas/Error"
220 | }
221 | }
222 | },
223 | "description": "Unauthorized"
224 | }
225 | },
226 | "schemas": {
227 | "Client": {
228 | "description": "Metadata gathered about the client",
229 | "properties": {
230 | "app_name": {
231 | "example": "1Password Extension",
232 | "type": "string"
233 | },
234 | "app_version": {
235 | "example": "20127",
236 | "type": "string"
237 | },
238 | "ip_address": {
239 | "example": "13.227.95.22",
240 | "type": "string"
241 | },
242 | "os_name": {
243 | "example": "MacOSX",
244 | "type": "string"
245 | },
246 | "os_version": {
247 | "example": "10.15.6",
248 | "type": "string"
249 | },
250 | "platform_name": {
251 | "example": "Chrome",
252 | "type": "string"
253 | },
254 | "platform_version": {
255 | "description": "Depending on the platform used, this can be the version of the browser that the client extension is installed, the model of computer that the native application is installed or the machine's CPU version that the CLI was installed",
256 | "type": "string"
257 | }
258 | }
259 | },
260 | "Cursor": {
261 | "description": "Cursor",
262 | "properties": {
263 | "cursor": {
264 | "description": "Cursor to fetch more data if available or continue the polling process if required",
265 | "example": "aGVsbG8hIGlzIGl0IG1lIHlvdSBhcmUgbG9va2luZyBmb3IK",
266 | "type": "string"
267 | }
268 | }
269 | },
270 | "CursorCollection": {
271 | "allOf": [
272 | {
273 | "$ref": "#/components/schemas/Cursor"
274 | },
275 | {
276 | "properties": {
277 | "has_more": {
278 | "description": "Whether there may still be more data to fetch using the returned cursor. If true, the subsequent request could still be empty.",
279 | "type": "boolean"
280 | }
281 | }
282 | }
283 | ],
284 | "description": "Common cursor properties for collection responses"
285 | },
286 | "DateTimeRFC3339": {
287 | "example": "2020-06-11T16:32:50-03:00",
288 | "format": "date-time",
289 | "type": "string"
290 | },
291 | "Details": {
292 | "description": "Additional information about the sign-in attempt",
293 | "properties": {
294 | "value": {
295 | "description": "For firewall prevented sign-ins, the value is the chosen continent, country, etc. that blocked the sign-in attempt",
296 | "example": "Europe",
297 | "type": "string"
298 | }
299 | }
300 | },
301 | "Error": {
302 | "properties": {
303 | "Error": {
304 | "properties": {
305 | "Message": {
306 | "description": "The error message.",
307 | "type": "string"
308 | }
309 | },
310 | "type": "object"
311 | }
312 | },
313 | "type": "object"
314 | },
315 | "Introspection": {
316 | "properties": {
317 | "Features": {
318 | "example": [
319 | "itemusages",
320 | "signinattempts"
321 | ],
322 | "items": {
323 | "type": "string"
324 | },
325 | "type": "array"
326 | },
327 | "IssuedAt": {
328 | "$ref": "#/components/schemas/DateTimeRFC3339"
329 | },
330 | "UUID": {
331 | "type": "string"
332 | }
333 | },
334 | "type": "object"
335 | },
336 | "ItemUsage": {
337 | "description": "A single item usage object",
338 | "properties": {
339 | "client": {
340 | "$ref": "#/components/schemas/Client"
341 | },
342 | "item_uuid": {
343 | "$ref": "#/components/schemas/UUID"
344 | },
345 | "timestamp": {
346 | "$ref": "#/components/schemas/DateTimeRFC3339"
347 | },
348 | "used_version": {
349 | "type": "integer"
350 | },
351 | "user": {
352 | "$ref": "#/components/schemas/User"
353 | },
354 | "uuid": {
355 | "$ref": "#/components/schemas/UUID"
356 | },
357 | "vault_uuid": {
358 | "$ref": "#/components/schemas/UUID"
359 | }
360 | }
361 | },
362 | "ItemUsageItems": {
363 | "allOf": [
364 | {
365 | "properties": {
366 | "items": {
367 | "items": {
368 | "$ref": "#/components/schemas/ItemUsage"
369 | },
370 | "type": "array"
371 | }
372 | }
373 | },
374 | {
375 | "$ref": "#/components/schemas/CursorCollection"
376 | }
377 | ],
378 | "description": "An object wrapping cursor properties and a list of items usages"
379 | },
380 | "ResetCursor": {
381 | "description": "Reset cursor",
382 | "properties": {
383 | "end_time": {
384 | "$ref": "#/components/schemas/DateTimeRFC3339"
385 | },
386 | "limit": {
387 | "maximum": 1000,
388 | "minimum": 1,
389 | "type": "number"
390 | },
391 | "start_time": {
392 | "$ref": "#/components/schemas/DateTimeRFC3339"
393 | }
394 | }
395 | },
396 | "SignInAttempt": {
397 | "description": "A single sign-in attempt object",
398 | "properties": {
399 | "category": {
400 | "enum": [
401 | "success",
402 | "credentials_failed",
403 | "mfa_failed",
404 | "modern_version_failed",
405 | "firewall_failed",
406 | "firewall_reported_success"
407 | ],
408 | "example": "firewall_failed",
409 | "type": "string"
410 | },
411 | "client": {
412 | "$ref": "#/components/schemas/Client"
413 | },
414 | "country": {
415 | "description": "Country ISO Code",
416 | "example": "France",
417 | "type": "string"
418 | },
419 | "details": {
420 | "$ref": "#/components/schemas/Details"
421 | },
422 | "session_uuid": {
423 | "$ref": "#/components/schemas/UUID"
424 | },
425 | "target_user": {
426 | "$ref": "#/components/schemas/User"
427 | },
428 | "timestamp": {
429 | "$ref": "#/components/schemas/DateTimeRFC3339"
430 | },
431 | "type": {
432 | "enum": [
433 | "credentials_ok",
434 | "mfa_ok",
435 | "password_secret_bad",
436 | "mfa_missing",
437 | "totp_disabled",
438 | "totp_bad",
439 | "totp_timeout",
440 | "u2f_disabled",
441 | "u2f_bad",
442 | "u2f_timout",
443 | "duo_disabled",
444 | "duo_bad",
445 | "duo_timeout",
446 | "duo_native_bad",
447 | "platform_secret_disabled",
448 | "platform_secret_bad",
449 | "platform_secret_proxy",
450 | "code_disabled",
451 | "code_bad",
452 | "code_timeout",
453 | "ip_blocked",
454 | "continent_blocked",
455 | "country_blocked",
456 | "anonymous_blocked",
457 | "all_blocked",
458 | "modern_version_missing",
459 | "modern_version_old"
460 | ],
461 | "example": "continent_blocked",
462 | "type": "string"
463 | },
464 | "uuid": {
465 | "$ref": "#/components/schemas/UUID"
466 | }
467 | }
468 | },
469 | "SignInAttemptItems": {
470 | "allOf": [
471 | {
472 | "properties": {
473 | "items": {
474 | "items": {
475 | "$ref": "#/components/schemas/SignInAttempt"
476 | },
477 | "type": "array"
478 | }
479 | }
480 | },
481 | {
482 | "$ref": "#/components/schemas/CursorCollection"
483 | }
484 | ],
485 | "description": "An object wrapping cursor properties and a list of sign-in attempts"
486 | },
487 | "UUID": {
488 | "example": "56YE2TYN2VFYRLNSHKPW5NVT5E",
489 | "type": "string"
490 | },
491 | "User": {
492 | "description": "User object",
493 | "properties": {
494 | "email": {
495 | "format": "email",
496 | "type": "string"
497 | },
498 | "name": {
499 | "description": "Full name",
500 | "example": "Jack O'Neill",
501 | "type": "string"
502 | },
503 | "uuid": {
504 | "$ref": "#/components/schemas/UUID"
505 | }
506 | }
507 | }
508 | },
509 | "securitySchemes": {
510 | "jwtsa": {
511 | "bearerFormat": "JWT-SA",
512 | "description": "A JWT SA token issued to this service",
513 | "scheme": "bearer",
514 | "type": "http"
515 | }
516 | }
517 | }
518 | }
--------------------------------------------------------------------------------
/Demos/Data/samples/ipgeolocation.json:
--------------------------------------------------------------------------------
1 | {
2 | "openapi": "3.0.1",
3 | "servers": [
4 | {
5 | "url": "https://ipgeolocation.abstractapi.com"
6 | }
7 | ],
8 | "info": {
9 | "description": "Abstract IP geolocation API allows developers to retrieve the region, country and city behind any IP worldwide. The API covers the geolocation of IPv4 and IPv6 addresses in 180+ countries worldwide. Extra information can be retrieved like the currency, flag or language associated to an IP.",
10 | "title": "IP geolocation API",
11 | "version": "1.0.0",
12 | "x-apisguru-categories": [
13 | "location"
14 | ],
15 | "x-logo": {
16 | "url": "https://api.apis.guru/v2/cache/logo/https_global-uploads.webflow.com_5ebbd0a566a3996636e55959_5ec2ba29feeeb05d69160e7b_webclip.png"
17 | },
18 | "x-origin": [
19 | {
20 | "format": "openapi",
21 | "url": "https://documentation.abstractapi.com/ip-geolocation-openapi.json",
22 | "version": "3.0"
23 | }
24 | ],
25 | "x-providerName": "abstractapi.com",
26 | "x-serviceName": "geolocation"
27 | },
28 | "externalDocs": {
29 | "description": "API Documentation",
30 | "url": "https://www.abstractapi.com/ip-geolocation-api#docs"
31 | },
32 | "paths": {
33 | "/v1/": {
34 | "get": {
35 | "description": "Retrieve the location of an IP address",
36 | "parameters": [
37 | {
38 | "explode": true,
39 | "in": "query",
40 | "name": "api_key",
41 | "required": true,
42 | "schema": {
43 | "type": "string"
44 | },
45 | "style": "form"
46 | },
47 | {
48 | "explode": true,
49 | "in": "query",
50 | "name": "ip_address",
51 | "required": false,
52 | "schema": {
53 | "example": "195.154.25.40",
54 | "type": "string"
55 | },
56 | "style": "form"
57 | },
58 | {
59 | "explode": true,
60 | "in": "query",
61 | "name": "fields",
62 | "required": false,
63 | "schema": {
64 | "example": "country,city,timezone",
65 | "type": "string"
66 | },
67 | "style": "form"
68 | }
69 | ],
70 | "responses": {
71 | "200": {
72 | "content": {
73 | "application/json": {
74 | "examples": {
75 | "0": {
76 | "value": "{\"ip_address\":\"195.154.25.40\",\"city\":\"Paris\",\"city_geoname_id\":2988507,\"region\":\"Île-de-France\",\"region_iso_code\":\"IDF\",\"region_geoname_id\":3012874,\"postal_code\":\"75008\",\"country\":\"France\",\"country_code\":\"FR\",\"country_geoname_id\":3017382,\"country_is_eu\":true,\"continent\":\"Europe\",\"continent_code\":\"EU\",\"continent_geoname_id\":6255148,\"longitude\":2.4075,\"latitude\":48.8323,\"security\":{\"is_vpn\":false},\"timezone\":{\"name\":\"Europe/Paris\",\"abbreviation\":\"CEST\",\"gmt_offset\":2,\"current_time\":\"15:42:18\",\"is_dst\":true},\"flag\":{\"emoji\":\"<ë<÷\",\"unicode\":\"U+1F1EB U+1F1F7\",\"png\":\"https://static.abstractapi.com/country-flags/FR_flag.png\",\"svg\":\"https://static.abstractapi.com/country-flags/FR_flag.svg\"},\"currency\":{\"currency_name\":\"Euros\",\"currency_code\":\"EUR\"},\"connection\":{\"autonomous_system_number\":12876,\"autonomous_system_organization\":\"Online S.a.s.\",\"connection_type\":\"Corporate\",\"isp_name\":\"Online S.A.S.\",\"organization_name\":\"ONLINE\"}}"
77 | }
78 | },
79 | "schema": {
80 | "$ref": "#/components/schemas/inline_response_200"
81 | }
82 | }
83 | },
84 | "description": "Location of geolocated IP"
85 | }
86 | },
87 | "servers": [
88 | {
89 | "url": "https://ipgeolocation.abstractapi.com"
90 | }
91 | ]
92 | },
93 | "servers": [
94 | {
95 | "url": "https://ipgeolocation.abstractapi.com"
96 | }
97 | ]
98 | }
99 | },
100 | "components": {
101 | "schemas": {
102 | "inline_response_200": {
103 | "properties": {
104 | "city": {
105 | "type": "string"
106 | },
107 | "city_geoname_id": {
108 | "type": "integer"
109 | },
110 | "connection": {
111 | "properties": {
112 | "autonomous_system_number": {
113 | "type": "integer"
114 | },
115 | "autonomous_system_organization": {
116 | "type": "string"
117 | },
118 | "connection_type": {
119 | "type": "string"
120 | },
121 | "isp_name": {
122 | "type": "string"
123 | },
124 | "organization_name": {
125 | "type": "string"
126 | }
127 | },
128 | "type": "object"
129 | },
130 | "continent": {
131 | "type": "string"
132 | },
133 | "continent_code": {
134 | "type": "string"
135 | },
136 | "continent_geoname_id": {
137 | "type": "integer"
138 | },
139 | "country": {
140 | "type": "string"
141 | },
142 | "country_code": {
143 | "type": "string"
144 | },
145 | "country_geoname_id": {
146 | "type": "integer"
147 | },
148 | "country_is_eu": {
149 | "type": "boolean"
150 | },
151 | "currency": {
152 | "properties": {
153 | "currency_code": {
154 | "type": "string"
155 | },
156 | "currency_name": {
157 | "type": "string"
158 | }
159 | },
160 | "type": "object"
161 | },
162 | "flag": {
163 | "properties": {
164 | "emoji": {
165 | "type": "string"
166 | },
167 | "png": {
168 | "type": "string"
169 | },
170 | "svg": {
171 | "type": "string"
172 | },
173 | "unicode": {
174 | "type": "string"
175 | }
176 | },
177 | "type": "object"
178 | },
179 | "ip_address": {
180 | "type": "string"
181 | },
182 | "latitude": {
183 | "type": "number"
184 | },
185 | "longitude": {
186 | "type": "number"
187 | },
188 | "postal_code": {
189 | "type": "string"
190 | },
191 | "region": {
192 | "type": "string"
193 | },
194 | "region_geoname_id": {
195 | "type": "integer"
196 | },
197 | "region_iso_code": {
198 | "type": "string"
199 | },
200 | "security": {
201 | "properties": {
202 | "is_vpn": {
203 | "type": "boolean"
204 | }
205 | },
206 | "type": "object"
207 | },
208 | "timezone": {
209 | "properties": {
210 | "abbreviation": {
211 | "type": "string"
212 | },
213 | "current_time": {
214 | "type": "string"
215 | },
216 | "gmt_offset": {
217 | "type": "integer"
218 | },
219 | "is_dst": {
220 | "type": "boolean"
221 | },
222 | "name": {
223 | "type": "string"
224 | }
225 | },
226 | "type": "object"
227 | }
228 | },
229 | "type": "object"
230 | }
231 | }
232 | }
233 | }
--------------------------------------------------------------------------------
/Demos/Data/samples/petstore.json:
--------------------------------------------------------------------------------
1 | {
2 | "openapi": "3.0.0",
3 | "info": {
4 | "version": "1.0.0",
5 | "title": "Swagger Petstore",
6 | "license": {
7 | "name": "MIT"
8 | }
9 | },
10 | "servers": [
11 | {
12 | "url": "http://petstore.swagger.io/v1"
13 | }
14 | ],
15 | "paths": {
16 | "/pets": {
17 | "get": {
18 | "summary": "List all pets",
19 | "operationId": "listPets",
20 | "tags": [
21 | "pets"
22 | ],
23 | "parameters": [
24 | {
25 | "name": "limit",
26 | "in": "query",
27 | "description": "How many items to return at one time (max 100)",
28 | "required": false,
29 | "schema": {
30 | "type": "integer",
31 | "format": "int32"
32 | }
33 | }
34 | ],
35 | "responses": {
36 | "200": {
37 | "description": "An paged array of pets",
38 | "headers": {
39 | "x-next": {
40 | "description": "A link to the next page of responses",
41 | "schema": {
42 | "type": "string"
43 | }
44 | }
45 | },
46 | "content": {
47 | "application/json": {
48 | "schema": {
49 | "$ref": "#/components/schemas/Pets"
50 | }
51 | }
52 | }
53 | },
54 | "default": {
55 | "description": "unexpected error",
56 | "content": {
57 | "application/json": {
58 | "schema": {
59 | "$ref": "#/components/schemas/Error"
60 | }
61 | }
62 | }
63 | }
64 | }
65 | },
66 | "post": {
67 | "summary": "Create a pet",
68 | "operationId": "createPets",
69 | "tags": [
70 | "pets"
71 | ],
72 | "responses": {
73 | "201": {
74 | "description": "Null response"
75 | },
76 | "default": {
77 | "description": "unexpected error",
78 | "content": {
79 | "application/json": {
80 | "schema": {
81 | "$ref": "#/components/schemas/Error"
82 | }
83 | }
84 | }
85 | }
86 | }
87 | }
88 | },
89 | "/pets/{petId}": {
90 | "get": {
91 | "summary": "Info for a specific pet",
92 | "operationId": "showPetById",
93 | "tags": [
94 | "pets"
95 | ],
96 | "parameters": [
97 | {
98 | "name": "petId",
99 | "in": "path",
100 | "required": true,
101 | "description": "The id of the pet to retrieve",
102 | "schema": {
103 | "type": "string"
104 | }
105 | }
106 | ],
107 | "responses": {
108 | "200": {
109 | "description": "Expected response to a valid request",
110 | "content": {
111 | "application/json": {
112 | "schema": {
113 | "$ref": "#/components/schemas/Pets"
114 | }
115 | }
116 | }
117 | },
118 | "default": {
119 | "description": "unexpected error",
120 | "content": {
121 | "application/json": {
122 | "schema": {
123 | "$ref": "#/components/schemas/Error"
124 | }
125 | }
126 | }
127 | }
128 | }
129 | }
130 | }
131 | },
132 | "components": {
133 | "schemas": {
134 | "Pet": {
135 | "required": [
136 | "id",
137 | "name"
138 | ],
139 | "properties": {
140 | "id": {
141 | "type": "integer",
142 | "format": "int64"
143 | },
144 | "name": {
145 | "type": "string"
146 | },
147 | "tag": {
148 | "type": "string"
149 | }
150 | }
151 | },
152 | "Pets": {
153 | "type": "array",
154 | "items": {
155 | "$ref": "#/components/schemas/Pet"
156 | }
157 | },
158 | "Error": {
159 | "required": [
160 | "code",
161 | "message"
162 | ],
163 | "properties": {
164 | "code": {
165 | "type": "integer",
166 | "format": "int32"
167 | },
168 | "message": {
169 | "type": "string"
170 | }
171 | }
172 | }
173 | }
174 | }
175 | }
--------------------------------------------------------------------------------
/Demos/OpenAPI/Demo.Form.Main.dfm:
--------------------------------------------------------------------------------
1 | object frmMain: TfrmMain
2 | Left = 0
3 | Top = 0
4 | Caption = 'OpenAPI Demo'
5 | ClientHeight = 580
6 | ClientWidth = 902
7 | Color = clBtnFace
8 | Font.Charset = DEFAULT_CHARSET
9 | Font.Color = clWindowText
10 | Font.Height = -11
11 | Font.Name = 'Tahoma'
12 | Font.Style = []
13 | OnCreate = FormCreate
14 | OnDestroy = FormDestroy
15 | TextHeight = 13
16 | object memoDocument: TMemo
17 | Left = 200
18 | Top = 0
19 | Width = 702
20 | Height = 580
21 | Align = alClient
22 | Font.Charset = ANSI_CHARSET
23 | Font.Color = clWindowText
24 | Font.Height = -16
25 | Font.Name = 'Consolas'
26 | Font.Style = []
27 | ParentFont = False
28 | ScrollBars = ssVertical
29 | TabOrder = 0
30 | ExplicitLeft = 203
31 | end
32 | object catMenu: TCategoryPanelGroup
33 | Left = 0
34 | Top = 0
35 | Height = 580
36 | VertScrollBar.Tracking = True
37 | HeaderFont.Charset = DEFAULT_CHARSET
38 | HeaderFont.Color = clWindowText
39 | HeaderFont.Height = -11
40 | HeaderFont.Name = 'Tahoma'
41 | HeaderFont.Style = []
42 | TabOrder = 1
43 | object pnlSections: TCategoryPanel
44 | Top = 192
45 | Height = 369
46 | Caption = 'Fill Document Sections'
47 | TabOrder = 0
48 | Visible = False
49 | object CategoryButtons1: TCategoryButtons
50 | Left = 0
51 | Top = 0
52 | Width = 194
53 | Height = 343
54 | Align = alClient
55 | ButtonFlow = cbfVertical
56 | ButtonOptions = [boFullSize, boGradientFill, boShowCaptions, boUsePlusMinus]
57 | Categories = <
58 | item
59 | Caption = 'General'
60 | Color = 15466474
61 | Collapsed = False
62 | Items = <
63 | item
64 | Action = actAddInfo
65 | end
66 | item
67 | Action = actAddInfoExtensions
68 | end
69 | item
70 | Action = actAddServers
71 | end>
72 | end
73 | item
74 | Caption = 'Components'
75 | Color = 16771818
76 | Collapsed = False
77 | Items = <
78 | item
79 | Action = actCompAddSchemas
80 | end
81 | item
82 | Action = actCompAddResponses
83 | end
84 | item
85 | Action = actCompAddSecurityDefs
86 | end
87 | item
88 | Action = actCompAddParameters
89 | end>
90 | end
91 | item
92 | Caption = 'Optional Sections'
93 | Color = 16771839
94 | Collapsed = False
95 | Items = <
96 | item
97 | Action = actAddPaths
98 | end
99 | item
100 | Action = actAddSecurity
101 | end>
102 | end
103 | item
104 | Caption = 'Serialization'
105 | Color = 16777194
106 | Collapsed = False
107 | Items = <
108 | item
109 | Action = actJSONGenerate
110 | end>
111 | end>
112 | RegularButtonColor = clWhite
113 | SelectedButtonColor = 15132390
114 | TabOrder = 0
115 | ExplicitHeight = 327
116 | end
117 | end
118 | object pnlDocument: TCategoryPanel
119 | Top = 0
120 | Height = 192
121 | Caption = 'OpenAPI Document'
122 | TabOrder = 1
123 | object CategoryButtons2: TCategoryButtons
124 | Left = 0
125 | Top = 0
126 | Width = 194
127 | Height = 166
128 | Align = alClient
129 | ButtonFlow = cbfVertical
130 | Categories = <>
131 | RegularButtonColor = clWhite
132 | SelectedButtonColor = 15132390
133 | TabOrder = 0
134 | end
135 | object catJSON: TCategoryButtons
136 | Left = 0
137 | Top = 0
138 | Width = 194
139 | Height = 166
140 | Align = alClient
141 | ButtonFlow = cbfVertical
142 | ButtonOptions = [boFullSize, boGradientFill, boShowCaptions, boUsePlusMinus]
143 | Categories = <
144 | item
145 | Caption = 'Document'
146 | Color = 15466474
147 | Collapsed = False
148 | Items = <
149 | item
150 | Action = actDocumentNew
151 | end
152 | item
153 | Action = actDocumentClose
154 | end
155 | item
156 | Action = actDocumentOpen
157 | end
158 | item
159 | Action = actDocumentSave
160 | end>
161 | end
162 | item
163 | Caption = 'General'
164 | Color = 16771818
165 | Collapsed = False
166 | Items = <
167 | item
168 | Action = actJSONReplace
169 | end>
170 | end>
171 | RegularButtonColor = clWhite
172 | SelectedButtonColor = 15132390
173 | TabOrder = 1
174 | end
175 | end
176 | end
177 | object aclCommands: TActionList
178 | Images = imgCommands
179 | Left = 176
180 | Top = 168
181 | object actAddInfo: TAction
182 | Caption = 'Add Info Object'
183 | OnExecute = actAddInfoExecute
184 | end
185 | object actAddInfoExtensions: TAction
186 | Caption = 'Add Info Object Extensions'
187 | OnExecute = actAddInfoExtensionsExecute
188 | end
189 | object actAddServers: TAction
190 | Caption = 'Add Servers'
191 | OnExecute = actAddServersExecute
192 | end
193 | object actAddPaths: TAction
194 | Caption = 'Add Paths && Params'
195 | OnExecute = actAddPathsExecute
196 | end
197 | object actAddSecurity: TAction
198 | Caption = 'Add Security'
199 | OnExecute = actAddSecurityExecute
200 | end
201 | object actCompAddSchemas: TAction
202 | Caption = 'Add Schemas'
203 | OnExecute = actCompAddSchemasExecute
204 | end
205 | object actCompAddResponses: TAction
206 | Caption = 'Add Responses'
207 | OnExecute = actCompAddResponsesExecute
208 | end
209 | object actCompAddSecurityDefs: TAction
210 | Caption = 'Add SecurityDefs'
211 | OnExecute = actCompAddSecurityDefsExecute
212 | end
213 | object actCompAddParameters: TAction
214 | Caption = 'Add Parameters'
215 | OnExecute = actCompAddParametersExecute
216 | end
217 | object actCompAddRequestBodies: TAction
218 | Caption = 'Add RequestBodies'
219 | end
220 | object actJSONGenerate: TAction
221 | Caption = 'Generate JSON Document'
222 | OnExecute = actJSONGenerateExecute
223 | end
224 | object actJSONReplace: TAction
225 | Caption = 'Replace Escaped Slash "/"'
226 | OnExecute = actJSONReplaceExecute
227 | end
228 | object actDocumentOpen: TAction
229 | Caption = 'Load Document (JSON)'
230 | OnExecute = actDocumentOpenExecute
231 | end
232 | object actDocumentSave: TAction
233 | Caption = 'Save Document (JSON)'
234 | OnExecute = actDocumentSaveExecute
235 | end
236 | object actDocumentNew: TAction
237 | Caption = 'New Document'
238 | OnExecute = actDocumentNewExecute
239 | end
240 | object actDocumentClose: TAction
241 | Caption = 'Close Document'
242 | OnExecute = actDocumentCloseExecute
243 | end
244 | end
245 | object imgCommands: TImageList
246 | Left = 184
247 | Top = 216
248 | end
249 | object dlgOpenJSON: TOpenDialog
250 | Filter = 'Schema Documents|*.json|All Files|*.*'
251 | Left = 440
252 | Top = 296
253 | end
254 | object dlgSaveDocument: TSaveDialog
255 | DefaultExt = 'json'
256 | Filter = 'OpenAPI Document|*.json'
257 | Left = 440
258 | Top = 360
259 | end
260 | end
261 |
--------------------------------------------------------------------------------
/Demos/OpenAPI/Demo.Form.Main.pas:
--------------------------------------------------------------------------------
1 | unit Demo.Form.Main;
2 |
3 | interface
4 |
5 | uses
6 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
7 | Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.CategoryButtons,
8 | Vcl.ExtCtrls, System.Actions, Vcl.ActnList, System.ImageList, Vcl.ImgList,
9 | System.Rtti, System.JSON,
10 |
11 | Neon.Core.Types,
12 | Neon.Core.Persistence,
13 | Neon.Core.Persistence.JSON,
14 | Neon.Core.Persistence.JSON.Schema,
15 | OpenAPI.Model.Classes,
16 | OpenAPI.Model.Schema,
17 | OpenAPI.Neon.Serializers;
18 |
19 | type
20 | TPerson = class
21 | private
22 | FAge: Integer;
23 | FName: string;
24 | public
25 | property Age: Integer read FAge write FAge;
26 | property Name: string read FName write FName;
27 | end;
28 |
29 | TfrmMain = class(TForm)
30 | memoDocument: TMemo;
31 | catMenu: TCategoryPanelGroup;
32 | pnlSections: TCategoryPanel;
33 | CategoryButtons1: TCategoryButtons;
34 | pnlDocument: TCategoryPanel;
35 | CategoryButtons2: TCategoryButtons;
36 | catJSON: TCategoryButtons;
37 | aclCommands: TActionList;
38 | imgCommands: TImageList;
39 | actAddInfo: TAction;
40 | actAddServers: TAction;
41 | actAddPaths: TAction;
42 | actAddSecurity: TAction;
43 | actCompAddSchemas: TAction;
44 | actCompAddResponses: TAction;
45 | actCompAddSecurityDefs: TAction;
46 | actJSONGenerate: TAction;
47 | actJSONReplace: TAction;
48 | actCompAddParameters: TAction;
49 | actCompAddRequestBodies: TAction;
50 | actAddInfoExtensions: TAction;
51 | actDocumentOpen: TAction;
52 | actDocumentSave: TAction;
53 | dlgOpenJSON: TOpenDialog;
54 | actDocumentNew: TAction;
55 | actDocumentClose: TAction;
56 | dlgSaveDocument: TSaveDialog;
57 | procedure FormCreate(Sender: TObject);
58 | procedure FormDestroy(Sender: TObject);
59 | procedure actAddInfoExecute(Sender: TObject);
60 | procedure actAddInfoExtensionsExecute(Sender: TObject);
61 | procedure actAddServersExecute(Sender: TObject);
62 | procedure actAddPathsExecute(Sender: TObject);
63 | procedure actCompAddResponsesExecute(Sender: TObject);
64 | procedure actCompAddSchemasExecute(Sender: TObject);
65 | procedure actCompAddSecurityDefsExecute(Sender: TObject);
66 | procedure actAddSecurityExecute(Sender: TObject);
67 | procedure actCompAddParametersExecute(Sender: TObject);
68 | procedure actDocumentCloseExecute(Sender: TObject);
69 | procedure actDocumentNewExecute(Sender: TObject);
70 | procedure actJSONGenerateExecute(Sender: TObject);
71 | procedure actDocumentOpenExecute(Sender: TObject);
72 | procedure actDocumentSaveExecute(Sender: TObject);
73 | procedure actJSONReplaceExecute(Sender: TObject);
74 | private
75 | FDocumentName: string;
76 | FDocument: TOpenAPIDocument;
77 | public
78 | { Public declarations }
79 | end;
80 |
81 | var
82 | frmMain: TfrmMain;
83 |
84 | implementation
85 |
86 | uses
87 | System.IOUtils;
88 |
89 | {$R *.dfm}
90 |
91 | procedure TfrmMain.FormCreate(Sender: TObject);
92 | begin
93 | dlgOpenJSON.InitialDir := TPath.GetDirectoryName(TPath.GetDirectoryName(Application.ExeName)) + '\Data\samples\';
94 | end;
95 |
96 | procedure TfrmMain.FormDestroy(Sender: TObject);
97 | begin
98 | FDocument.Free;
99 | end;
100 |
101 | procedure TfrmMain.actAddInfoExecute(Sender: TObject);
102 | begin
103 | FDocument.Info.Title := 'OpenAPI Demo';
104 | FDocument.Info.Version := '1.0.2';
105 | FDocument.Info.Description := 'OpenAPI Demo Description';
106 | FDocument.Info.Contact.Name := 'Paolo Rossi';
107 | FDocument.Info.Contact.URL := 'https://github.com/paolo-rossi';
108 | FDocument.Info.License.Name := 'Apache-2.0';
109 | FDocument.Info.License.URL := 'http://www.apache.org/licenses/';
110 | end;
111 |
112 | procedure TfrmMain.actAddInfoExtensionsExecute(Sender: TObject);
113 | var
114 | LJSON: TJSONObject;
115 | begin
116 | LJSON := TJSONObject.Create;
117 | LJSON.AddPair('url', '/images/wirl.png');
118 | LJSON.AddPair('backgroundColor', '#000000');
119 | LJSON.AddPair('altText', 'WiRL Logo');
120 |
121 | FDocument.Info.Extensions.Add('x-logo', LJSON);
122 |
123 | // Testing the Dictionary serialization for Extensions
124 | //FDocument.Info.Ext.Add('test', 'prova');
125 | //FDocument.Info.Ext.Add('xyz', TStringList.Create.Add('Prova Item 1'));
126 |
127 | end;
128 |
129 | procedure TfrmMain.actAddServersExecute(Sender: TObject);
130 | begin
131 | FDocument.Servers.Add(TOpenAPIServer.Create('https://api.wirl.com/rest/app/', 'Production Server'));
132 | FDocument.Servers.Add(TOpenAPIServer.Create('https://beta.wirl.com/rest/app/', 'Beta Server API v2'));
133 | FDocument.Servers.Add(TOpenAPIServer.Create('https://test.wirl.com/rest/app/', 'Testing Server'));
134 | end;
135 |
136 | procedure TfrmMain.actAddPathsExecute(Sender: TObject);
137 | var
138 | LPath: TOpenAPIPathItem;
139 | LOperation: TOpenAPIOperation;
140 | LParameter: TOpenAPIParameter;
141 | begin
142 | LPath := FDocument.AddPath('/customers');
143 | LPath.Description := 'Customers resource';
144 |
145 | LOperation := LPath.AddOperation(TOperationType.Get);
146 | LOperation.Summary := 'Get all customers';
147 | LOperation.OperationId := 'CustomerList';
148 |
149 | LParameter := LOperation.AddParameter('id', 'query');
150 | LParameter.Description := 'Customer ID';
151 | LParameter.Schema.Type_ := 'string';
152 |
153 | LParameter := LOperation.AddParameter('country', 'query');
154 | LParameter.Description := 'Country Code';
155 | LParameter.Schema.Type_ := 'string';
156 | LParameter.Schema.AddEnum('it');
157 | LParameter.Schema.AddEnum('br');
158 | LParameter.Schema.AddEnum('us');
159 | LParameter.Schema.AddEnum('uk');
160 |
161 | LParameter := LOperation.AddParameter('date', 'query');
162 | LParameter.Description := 'Date';
163 | LParameter.Schema.Type_ := 'string';
164 | LParameter.Schema.Format := 'date-time';
165 |
166 | // Uses a JSON schema already existing as a TJSONObject
167 | LParameter := LOperation.AddParameter('person', 'query');
168 | LParameter.Description := 'Person Entity';
169 | LParameter.Schema.SetJSONObject(TNeonSchemaGenerator.ClassToJSONSchema(TPerson));
170 |
171 | // Uses #ref
172 | LParameter := LOperation.AddParameter('order', 'query');
173 | LParameter.Description := 'Order Entity';
174 | LParameter.Schema.Reference.Ref := '#components/schemas/order';
175 | end;
176 |
177 | procedure TfrmMain.actCompAddResponsesExecute(Sender: TObject);
178 | var
179 | LResponse: TOpenAPIResponse;
180 | LMediaType: TOpenAPIMediaType;
181 | begin
182 | LResponse := FDocument.Components.AddResponse('200', 'Successful Response');
183 | LMediaType := LResponse.AddMediaType('application/json');
184 | LMediaType.Schema.Reference.Ref := '#components/schemas/country';
185 | end;
186 |
187 | procedure TfrmMain.actCompAddSchemasExecute(Sender: TObject);
188 | var
189 | LSchema: TOpenAPISchema;
190 | LProperty: TOpenAPISchema;
191 | begin
192 | LSchema := FDocument.Components.AddSchema('Person');
193 | LSchema.Type_ := 'object';
194 |
195 | LProperty := LSchema.AddProperty('id');
196 | LProperty.Title := 'ID Value';
197 | LProperty.Description := 'AutoInc **ID** value';
198 | LProperty.Type_ := 'integer';
199 | LProperty.Format := 'int64';
200 |
201 | LProperty := LSchema.AddProperty('firstname');
202 | LProperty.Type_ := 'string';
203 |
204 | LProperty := LSchema.AddProperty('lastname');
205 | LProperty.Type_ := 'string';
206 |
207 | LProperty := LSchema.AddProperty('birthdate');
208 | LProperty.Title := 'Birth Date';
209 | LProperty.Description := 'Birth Date';
210 | LProperty.Type_ := 'string';
211 | LProperty.Format := 'date-time';
212 | end;
213 |
214 | procedure TfrmMain.actCompAddSecurityDefsExecute(Sender: TObject);
215 | begin
216 | FDocument.Components.AddSecurityApiKey('key_auth', 'Key Standard Authentication', 'X-ApiKey', tapikeylocation.Header);
217 | FDocument.Components.AddSecurityHttp('basic_auth', 'Basic Authentication', 'Basic', '');
218 | FDocument.Components.AddSecurityHttp('jwt_auth', 'JWT (Bearer) Authentication', 'Bearer', 'JWT');
219 | end;
220 |
221 | procedure TfrmMain.actAddSecurityExecute(Sender: TObject);
222 | begin
223 | FDocument.AddSecurity('basic_auth', []);
224 | FDocument.AddSecurity('jwt_auth', []);
225 | end;
226 |
227 | procedure TfrmMain.actCompAddParametersExecute(Sender: TObject);
228 | var
229 | LParameter: TOpenAPIParameter;
230 | begin
231 | LParameter := FDocument.Components.AddParameter('idParam', 'id', 'query');
232 | LParameter.Description := 'Customer ID';
233 | LParameter.Schema.Type_ := 'string';
234 | LParameter.Schema.MaxLength := 20;
235 | end;
236 |
237 | procedure TfrmMain.actDocumentCloseExecute(Sender: TObject);
238 | begin
239 | FreeAndNil(FDocument);
240 | memoDocument.Clear;
241 | pnlSections.Visible := False;
242 | end;
243 |
244 | procedure TfrmMain.actDocumentNewExecute(Sender: TObject);
245 | begin
246 | FDocument := TOpenAPIDocument.Create(TOpenAPIVersion.v303);
247 | pnlSections.Visible := True;
248 | FDocumentName := 'MyAPI';
249 | end;
250 |
251 | procedure TfrmMain.actJSONGenerateExecute(Sender: TObject);
252 | begin
253 | memoDocument.Lines.Text :=
254 | TNeon.ObjectToJSONString(FDocument, TOpenAPISerializer.GetNeonConfig);
255 | end;
256 |
257 | procedure TfrmMain.actDocumentOpenExecute(Sender: TObject);
258 | var
259 | LDocument: TOpenAPIDocument;
260 | LJSON: TJSONObject;
261 | LConfig: INeonConfiguration;
262 | begin
263 | if not dlgOpenJSON.Execute() then
264 | Exit;
265 |
266 | LDocument := TOpenAPIDocument.Create(TOpenAPIVersion.v303);
267 | try
268 | LJSON := TJSONObject.ParseJSONValue(TFile.ReadAllText(dlgOpenJSON.FileName)) as TJSONObject;
269 | try
270 | LConfig := TOpenAPISerializer.GetNeonConfig;
271 |
272 | TNeon.JSONToObject(LDocument, LJSON, LConfig);
273 | finally
274 | LJSON.Free;
275 | end;
276 |
277 | // Serialization in order to see the document loaded
278 | memoDocument.Text := TNeon.ObjectToJSONString(LDocument, LConfig);
279 | finally
280 | LDocument.Free;
281 | end;
282 | FDocumentName := TPath.GetFileNameWithoutExtension(dlgOpenJSON.FileName);
283 | end;
284 |
285 | procedure TfrmMain.actDocumentSaveExecute(Sender: TObject);
286 | begin
287 | dlgSaveDocument.FileName := FDocumentName + '.json';
288 | if not dlgSaveDocument.Execute then
289 | Exit;
290 |
291 | memoDocument.Lines.SaveToFile(dlgSaveDocument.FileName, TEncoding.UTF8);
292 | end;
293 |
294 | procedure TfrmMain.actJSONReplaceExecute(Sender: TObject);
295 | begin
296 | memoDocument.Lines.Text :=
297 | StringReplace(memoDocument.Lines.Text, '\/', '/', [rfReplaceAll]);
298 | end;
299 |
300 | end.
301 |
--------------------------------------------------------------------------------
/Demos/OpenAPI/DemoOpenAPI.dpr:
--------------------------------------------------------------------------------
1 | program DemoOpenAPI;
2 |
3 | uses
4 | Vcl.Forms,
5 | Demo.Form.Main in 'Demo.Form.Main.pas' {frmMain},
6 | OpenAPI.Core.Interfaces in '..\..\Source\OpenAPI.Core.Interfaces.pas',
7 | OpenAPI.Core.Exceptions in '..\..\Source\OpenAPI.Core.Exceptions.pas',
8 | OpenAPI.Model.Any in '..\..\Source\OpenAPI.Model.Any.pas',
9 | OpenAPI.Model.Schema in '..\..\Source\OpenAPI.Model.Schema.pas',
10 | OpenAPI.Model.Classes in '..\..\Source\OpenAPI.Model.Classes.pas',
11 | OpenAPI.Model.Reference in '..\..\Source\OpenAPI.Model.Reference.pas',
12 | OpenAPI.Model.Expressions in '..\..\Source\OpenAPI.Model.Expressions.pas',
13 | OpenAPI.Model.JsonPointer in '..\..\Source\OpenAPI.Model.JsonPointer.pas',
14 | OpenAPI.Neon.Serializers in '..\..\Source\OpenAPI.Neon.Serializers.pas',
15 | OpenAPI.Model.Base in '..\..\Source\OpenAPI.Model.Base.pas';
16 |
17 | {$R *.res}
18 |
19 | begin
20 | ReportMemoryLeaksOnShutdown := True;
21 | Application.Initialize;
22 | Application.MainFormOnTaskbar := True;
23 | Application.CreateForm(TfrmMain, frmMain);
24 | Application.Run;
25 | end.
26 |
--------------------------------------------------------------------------------
/Demos/OpenAPI/DemoOpenAPI.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paolo-rossi/OpenAPI-Delphi/02c7fbeb4256e1606fbbc5b39e95629c59423df3/Demos/OpenAPI/DemoOpenAPI.res
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/Packages/10.2Tokyo/OpenAPI.dpk:
--------------------------------------------------------------------------------
1 | {******************************************************************************}
2 | { }
3 | { Delphi OpenAPI 3.0 Generator }
4 | { Copyright (c) 2018-2021 Paolo Rossi }
5 | { https://github.com/paolo-rossi/delphi-openapi }
6 | { }
7 | {******************************************************************************}
8 | { }
9 | { Licensed under the Apache License, Version 2.0 (the 'License"); }
10 | { you may not use this file except in compliance with the License. }
11 | { You may obtain a copy of the License at }
12 | { }
13 | { http://www.apache.org/licenses/LICENSE-2.0 }
14 | { }
15 | { Unless required by applicable law or agreed to in writing, software }
16 | { distributed under the License is distributed on an "AS IS" BASIS, }
17 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
18 | { See the License for the specific language governing permissions and }
19 | { limitations under the License. }
20 | { }
21 | {******************************************************************************}
22 | package OpenAPI;
23 |
24 | {$R *.res}
25 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users}
26 | {$ALIGN 8}
27 | {$ASSERTIONS ON}
28 | {$BOOLEVAL OFF}
29 | {$DEBUGINFO OFF}
30 | {$EXTENDEDSYNTAX ON}
31 | {$IMPORTEDDATA ON}
32 | {$IOCHECKS ON}
33 | {$LOCALSYMBOLS ON}
34 | {$LONGSTRINGS ON}
35 | {$OPENSTRINGS ON}
36 | {$OPTIMIZATION OFF}
37 | {$OVERFLOWCHECKS OFF}
38 | {$RANGECHECKS OFF}
39 | {$REFERENCEINFO ON}
40 | {$SAFEDIVIDE OFF}
41 | {$STACKFRAMES ON}
42 | {$TYPEDADDRESS OFF}
43 | {$VARSTRINGCHECKS ON}
44 | {$WRITEABLECONST OFF}
45 | {$MINENUMSIZE 1}
46 | {$IMAGEBASE $400000}
47 | {$DEFINE DEBUG}
48 | {$ENDIF IMPLICITBUILDING}
49 | {$DESCRIPTION 'Delphi OpenAPI 3 Library'}
50 | {$LIBSUFFIX '250'}
51 | {$RUNONLY}
52 | {$IMPLICITBUILD OFF}
53 |
54 | requires
55 | rtl,
56 | Neon;
57 |
58 | contains
59 | OpenAPI.Core.Exceptions in '..\..\Source\OpenAPI.Core.Exceptions.pas',
60 | OpenAPI.Core.Interfaces in '..\..\Source\OpenAPI.Core.Interfaces.pas',
61 | OpenAPI.Model.Any in '..\..\Source\OpenAPI.Model.Any.pas',
62 | OpenAPI.Model.Base in '..\..\Source\OpenAPI.Model.Base.pas',
63 | OpenAPI.Model.Classes in '..\..\Source\OpenAPI.Model.Classes.pas',
64 | OpenAPI.Model.Expressions in '..\..\Source\OpenAPI.Model.Expressions.pas',
65 | OpenAPI.Model.JsonPointer in '..\..\Source\OpenAPI.Model.JsonPointer.pas',
66 | OpenAPI.Model.Reference in '..\..\Source\OpenAPI.Model.Reference.pas',
67 | OpenAPI.Model.Schema in '..\..\Source\OpenAPI.Model.Schema.pas',
68 | OpenAPI.Neon.Serializers in '..\..\Source\OpenAPI.Neon.Serializers.pas';
69 |
70 | end.
71 |
72 |
--------------------------------------------------------------------------------
/Packages/10.2Tokyo/OpenAPI.dproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | {511659C1-0C7F-4B9E-BEDF-0B30D8057D8D}
4 | OpenAPI.dpk
5 | True
6 | Debug
7 | 131
8 | Package
9 | None
10 | 19.2
11 | Win32
12 |
13 |
14 | true
15 |
16 |
17 | true
18 | Base
19 | true
20 |
21 |
22 | true
23 | Base
24 | true
25 |
26 |
27 | true
28 | Base
29 | true
30 |
31 |
32 | true
33 | Cfg_1
34 | true
35 | true
36 |
37 |
38 | true
39 | Cfg_1
40 | true
41 | true
42 |
43 |
44 | true
45 | Base
46 | true
47 |
48 |
49 | true
50 | Cfg_2
51 | true
52 | true
53 |
54 |
55 | true
56 | Cfg_2
57 | true
58 | true
59 |
60 |
61 | true
62 | ..\..\Source;$(DCC_UnitSearchPath)
63 | OpenAPI
64 | 1040
65 | Delphi OpenAPI 3 Library
66 | true
67 | false
68 | false
69 | false
70 | 250
71 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=;CFBundleName=
72 | true
73 | false
74 | 00400000
75 | true
76 | false
77 | true
78 | ..\..\Lib\$(DLLSuffix)\$(Platform)\$(Config)
79 |
80 |
81 | /usr/bin/xterm -e "%debuggee%"
82 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=;CFBundleName=;CFBundleVersion=1.0.0.0;CFBundleShortVersionString=1.0.0.0
83 |
84 |
85 | rtl;dbrtl;inet;IndySystem;IndyProtocols;IndyCore;FireDAC;FireDACCommonDriver;FireDACCommon;bindengine;bindcomp;WiRLClient;$(DCC_UsePackage)
86 | 1033
87 | Debug
88 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName)
89 |
90 |
91 | 0
92 | 0
93 | false
94 | RELEASE;$(DCC_Define)
95 |
96 |
97 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=;CFBundleName=;CFBundleVersion=1.0.0.0;CFBundleShortVersionString=1.0.0.0
98 |
99 |
100 | 1033
101 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName)
102 |
103 |
104 | DEBUG;$(DCC_Define)
105 | false
106 | true
107 |
108 |
109 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=;CFBundleName=;CFBundleVersion=1.0.0.0;CFBundleShortVersionString=1.0.0.0
110 |
111 |
112 | 1033
113 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName)
114 |
115 |
116 |
117 | MainSource
118 |
119 |
120 |
121 |
122 | Cfg_2
123 | Base
124 |
125 |
126 | Base
127 |
128 |
129 | Cfg_1
130 | Base
131 |
132 |
133 |
134 | Delphi.Personality.12
135 | Package
136 |
137 |
138 |
139 | OpenAPI.dpk
140 |
141 |
142 |
143 |
144 | True
145 | True
146 | True
147 |
148 |
149 | 12
150 |
151 |
152 |
153 |
154 |
155 |
--------------------------------------------------------------------------------
/Packages/10.2Tokyo/OpenAPI.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paolo-rossi/OpenAPI-Delphi/02c7fbeb4256e1606fbbc5b39e95629c59423df3/Packages/10.2Tokyo/OpenAPI.res
--------------------------------------------------------------------------------
/Packages/10.3Rio/OpenAPI.dpk:
--------------------------------------------------------------------------------
1 | {******************************************************************************}
2 | { }
3 | { Delphi OpenAPI 3.0 Generator }
4 | { Copyright (c) 2018-2021 Paolo Rossi }
5 | { https://github.com/paolo-rossi/delphi-openapi }
6 | { }
7 | {******************************************************************************}
8 | { }
9 | { Licensed under the Apache License, Version 2.0 (the 'License"); }
10 | { you may not use this file except in compliance with the License. }
11 | { You may obtain a copy of the License at }
12 | { }
13 | { http://www.apache.org/licenses/LICENSE-2.0 }
14 | { }
15 | { Unless required by applicable law or agreed to in writing, software }
16 | { distributed under the License is distributed on an "AS IS" BASIS, }
17 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
18 | { See the License for the specific language governing permissions and }
19 | { limitations under the License. }
20 | { }
21 | {******************************************************************************}
22 | package OpenAPI;
23 |
24 | {$R *.res}
25 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users}
26 | {$ALIGN 8}
27 | {$ASSERTIONS ON}
28 | {$BOOLEVAL OFF}
29 | {$DEBUGINFO OFF}
30 | {$EXTENDEDSYNTAX ON}
31 | {$IMPORTEDDATA ON}
32 | {$IOCHECKS ON}
33 | {$LOCALSYMBOLS ON}
34 | {$LONGSTRINGS ON}
35 | {$OPENSTRINGS ON}
36 | {$OPTIMIZATION OFF}
37 | {$OVERFLOWCHECKS OFF}
38 | {$RANGECHECKS OFF}
39 | {$REFERENCEINFO ON}
40 | {$SAFEDIVIDE OFF}
41 | {$STACKFRAMES ON}
42 | {$TYPEDADDRESS OFF}
43 | {$VARSTRINGCHECKS ON}
44 | {$WRITEABLECONST OFF}
45 | {$MINENUMSIZE 1}
46 | {$IMAGEBASE $400000}
47 | {$DEFINE DEBUG}
48 | {$ENDIF IMPLICITBUILDING}
49 | {$DESCRIPTION 'Delphi OpenAPI 3 Library'}
50 | {$LIBSUFFIX '260'}
51 | {$RUNONLY}
52 | {$IMPLICITBUILD OFF}
53 |
54 | requires
55 | rtl,
56 | Neon;
57 |
58 | contains
59 | OpenAPI.Core.Exceptions in '..\..\Source\OpenAPI.Core.Exceptions.pas',
60 | OpenAPI.Core.Interfaces in '..\..\Source\OpenAPI.Core.Interfaces.pas',
61 | OpenAPI.Model.Any in '..\..\Source\OpenAPI.Model.Any.pas',
62 | OpenAPI.Model.Base in '..\..\Source\OpenAPI.Model.Base.pas',
63 | OpenAPI.Model.Classes in '..\..\Source\OpenAPI.Model.Classes.pas',
64 | OpenAPI.Model.Expressions in '..\..\Source\OpenAPI.Model.Expressions.pas',
65 | OpenAPI.Model.JsonPointer in '..\..\Source\OpenAPI.Model.JsonPointer.pas',
66 | OpenAPI.Model.Reference in '..\..\Source\OpenAPI.Model.Reference.pas',
67 | OpenAPI.Model.Schema in '..\..\Source\OpenAPI.Model.Schema.pas',
68 | OpenAPI.Neon.Serializers in '..\..\Source\OpenAPI.Neon.Serializers.pas';
69 |
70 | end.
71 |
72 |
--------------------------------------------------------------------------------
/Packages/10.3Rio/OpenAPI.dproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | {511659C1-0C7F-4B9E-BEDF-0B30D8057D8D}
4 | OpenAPI.dpk
5 | True
6 | Debug
7 | 131
8 | Package
9 | None
10 | 19.2
11 | Win32
12 |
13 |
14 | true
15 |
16 |
17 | true
18 | Base
19 | true
20 |
21 |
22 | true
23 | Base
24 | true
25 |
26 |
27 | true
28 | Base
29 | true
30 |
31 |
32 | true
33 | Cfg_1
34 | true
35 | true
36 |
37 |
38 | true
39 | Cfg_1
40 | true
41 | true
42 |
43 |
44 | true
45 | Base
46 | true
47 |
48 |
49 | true
50 | Cfg_2
51 | true
52 | true
53 |
54 |
55 | true
56 | Cfg_2
57 | true
58 | true
59 |
60 |
61 | true
62 | ..\..\Source;$(DCC_UnitSearchPath)
63 | OpenAPI
64 | 1040
65 | Delphi OpenAPI 3 Library
66 | true
67 | false
68 | false
69 | false
70 | 260
71 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=;CFBundleName=
72 | true
73 | false
74 | 00400000
75 | true
76 | false
77 | true
78 | ..\..\Lib\$(DLLSuffix)\$(Platform)\$(Config)
79 |
80 |
81 | /usr/bin/xterm -e "%debuggee%"
82 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=;CFBundleName=;CFBundleVersion=1.0.0.0;CFBundleShortVersionString=1.0.0.0
83 |
84 |
85 | rtl;dbrtl;inet;IndySystem;IndyProtocols;IndyCore;FireDAC;FireDACCommonDriver;FireDACCommon;bindengine;bindcomp;WiRLClient;$(DCC_UsePackage)
86 | 1033
87 | Debug
88 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName)
89 |
90 |
91 | 0
92 | 0
93 | false
94 | RELEASE;$(DCC_Define)
95 |
96 |
97 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=;CFBundleName=;CFBundleVersion=1.0.0.0;CFBundleShortVersionString=1.0.0.0
98 |
99 |
100 | 1033
101 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName)
102 |
103 |
104 | DEBUG;$(DCC_Define)
105 | false
106 | true
107 |
108 |
109 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=;CFBundleName=;CFBundleVersion=1.0.0.0;CFBundleShortVersionString=1.0.0.0
110 |
111 |
112 | 1033
113 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName)
114 |
115 |
116 |
117 | MainSource
118 |
119 |
120 |
121 |
122 | Cfg_2
123 | Base
124 |
125 |
126 | Base
127 |
128 |
129 | Cfg_1
130 | Base
131 |
132 |
133 |
134 | Delphi.Personality.12
135 | Package
136 |
137 |
138 |
139 | OpenAPI.dpk
140 |
141 |
142 |
143 |
144 | True
145 | True
146 | True
147 |
148 |
149 | 12
150 |
151 |
152 |
153 |
154 |
155 |
--------------------------------------------------------------------------------
/Packages/10.3Rio/OpenAPI.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paolo-rossi/OpenAPI-Delphi/02c7fbeb4256e1606fbbc5b39e95629c59423df3/Packages/10.3Rio/OpenAPI.res
--------------------------------------------------------------------------------
/Packages/10.4Sydney/OpenAPI.dpk:
--------------------------------------------------------------------------------
1 | {******************************************************************************}
2 | { }
3 | { Delphi OpenAPI 3.0 Generator }
4 | { Copyright (c) 2018-2021 Paolo Rossi }
5 | { https://github.com/paolo-rossi/delphi-openapi }
6 | { }
7 | {******************************************************************************}
8 | { }
9 | { Licensed under the Apache License, Version 2.0 (the 'License"); }
10 | { you may not use this file except in compliance with the License. }
11 | { You may obtain a copy of the License at }
12 | { }
13 | { http://www.apache.org/licenses/LICENSE-2.0 }
14 | { }
15 | { Unless required by applicable law or agreed to in writing, software }
16 | { distributed under the License is distributed on an "AS IS" BASIS, }
17 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
18 | { See the License for the specific language governing permissions and }
19 | { limitations under the License. }
20 | { }
21 | {******************************************************************************}
22 | package OpenAPI;
23 |
24 | {$R *.res}
25 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users}
26 | {$ALIGN 8}
27 | {$ASSERTIONS ON}
28 | {$BOOLEVAL OFF}
29 | {$DEBUGINFO OFF}
30 | {$EXTENDEDSYNTAX ON}
31 | {$IMPORTEDDATA ON}
32 | {$IOCHECKS ON}
33 | {$LOCALSYMBOLS ON}
34 | {$LONGSTRINGS ON}
35 | {$OPENSTRINGS ON}
36 | {$OPTIMIZATION OFF}
37 | {$OVERFLOWCHECKS OFF}
38 | {$RANGECHECKS OFF}
39 | {$REFERENCEINFO ON}
40 | {$SAFEDIVIDE OFF}
41 | {$STACKFRAMES ON}
42 | {$TYPEDADDRESS OFF}
43 | {$VARSTRINGCHECKS ON}
44 | {$WRITEABLECONST OFF}
45 | {$MINENUMSIZE 1}
46 | {$IMAGEBASE $400000}
47 | {$DEFINE DEBUG}
48 | {$ENDIF IMPLICITBUILDING}
49 | {$DESCRIPTION 'Delphi OpenAPI 3 Library'}
50 | {$LIBSUFFIX '270'}
51 | {$RUNONLY}
52 | {$IMPLICITBUILD OFF}
53 |
54 | requires
55 | rtl,
56 | Neon;
57 |
58 | contains
59 | OpenAPI.Core.Exceptions in '..\..\Source\OpenAPI.Core.Exceptions.pas',
60 | OpenAPI.Core.Interfaces in '..\..\Source\OpenAPI.Core.Interfaces.pas',
61 | OpenAPI.Model.Any in '..\..\Source\OpenAPI.Model.Any.pas',
62 | OpenAPI.Model.Base in '..\..\Source\OpenAPI.Model.Base.pas',
63 | OpenAPI.Model.Classes in '..\..\Source\OpenAPI.Model.Classes.pas',
64 | OpenAPI.Model.Expressions in '..\..\Source\OpenAPI.Model.Expressions.pas',
65 | OpenAPI.Model.JsonPointer in '..\..\Source\OpenAPI.Model.JsonPointer.pas',
66 | OpenAPI.Model.Reference in '..\..\Source\OpenAPI.Model.Reference.pas',
67 | OpenAPI.Model.Schema in '..\..\Source\OpenAPI.Model.Schema.pas',
68 | OpenAPI.Neon.Serializers in '..\..\Source\OpenAPI.Neon.Serializers.pas';
69 |
70 | end.
71 |
72 |
--------------------------------------------------------------------------------
/Packages/10.4Sydney/OpenAPI.dproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | {511659C1-0C7F-4B9E-BEDF-0B30D8057D8D}
4 | OpenAPI.dpk
5 | True
6 | Debug
7 | 131
8 | Package
9 | None
10 | 19.2
11 | Win32
12 |
13 |
14 | true
15 |
16 |
17 | true
18 | Base
19 | true
20 |
21 |
22 | true
23 | Base
24 | true
25 |
26 |
27 | true
28 | Base
29 | true
30 |
31 |
32 | true
33 | Cfg_1
34 | true
35 | true
36 |
37 |
38 | true
39 | Cfg_1
40 | true
41 | true
42 |
43 |
44 | true
45 | Base
46 | true
47 |
48 |
49 | true
50 | Cfg_2
51 | true
52 | true
53 |
54 |
55 | true
56 | Cfg_2
57 | true
58 | true
59 |
60 |
61 | true
62 | ..\..\Source;$(DCC_UnitSearchPath)
63 | OpenAPI
64 | 1040
65 | Delphi OpenAPI 3 Library
66 | true
67 | false
68 | false
69 | false
70 | 270
71 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=;CFBundleName=
72 | true
73 | false
74 | 00400000
75 | true
76 | false
77 | true
78 | ..\..\Lib\$(DLLSuffix)\$(Platform)\$(Config)
79 |
80 |
81 | /usr/bin/xterm -e "%debuggee%"
82 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=;CFBundleName=;CFBundleVersion=1.0.0.0;CFBundleShortVersionString=1.0.0.0
83 |
84 |
85 | rtl;dbrtl;inet;IndySystem;IndyProtocols;IndyCore;FireDAC;FireDACCommonDriver;FireDACCommon;bindengine;bindcomp;WiRLClient;$(DCC_UsePackage)
86 | 1033
87 | Debug
88 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName)
89 |
90 |
91 | 0
92 | 0
93 | false
94 | RELEASE;$(DCC_Define)
95 |
96 |
97 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=;CFBundleName=;CFBundleVersion=1.0.0.0;CFBundleShortVersionString=1.0.0.0
98 |
99 |
100 | 1033
101 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName)
102 |
103 |
104 | DEBUG;$(DCC_Define)
105 | false
106 | true
107 |
108 |
109 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=;CFBundleName=;CFBundleVersion=1.0.0.0;CFBundleShortVersionString=1.0.0.0
110 |
111 |
112 | 1033
113 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName)
114 |
115 |
116 |
117 | MainSource
118 |
119 |
120 |
121 |
122 | Cfg_2
123 | Base
124 |
125 |
126 | Base
127 |
128 |
129 | Cfg_1
130 | Base
131 |
132 |
133 |
134 | Delphi.Personality.12
135 | Package
136 |
137 |
138 |
139 | OpenAPI.dpk
140 |
141 |
142 |
143 |
144 | True
145 | True
146 | True
147 |
148 |
149 | 12
150 |
151 |
152 |
153 |
154 |
155 |
--------------------------------------------------------------------------------
/Packages/10.4Sydney/OpenAPI.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paolo-rossi/OpenAPI-Delphi/02c7fbeb4256e1606fbbc5b39e95629c59423df3/Packages/10.4Sydney/OpenAPI.res
--------------------------------------------------------------------------------
/Packages/11.0Alexandria/OpenAPI.dpk:
--------------------------------------------------------------------------------
1 | {******************************************************************************}
2 | { }
3 | { Delphi OpenAPI 3.0 Generator }
4 | { Copyright (c) 2018-2023 Paolo Rossi }
5 | { https://github.com/paolo-rossi/delphi-openapi }
6 | { }
7 | {******************************************************************************}
8 | { }
9 | { Licensed under the Apache License, Version 2.0 (the 'License"); }
10 | { you may not use this file except in compliance with the License. }
11 | { You may obtain a copy of the License at }
12 | { }
13 | { http://www.apache.org/licenses/LICENSE-2.0 }
14 | { }
15 | { Unless required by applicable law or agreed to in writing, software }
16 | { distributed under the License is distributed on an "AS IS" BASIS, }
17 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
18 | { See the License for the specific language governing permissions and }
19 | { limitations under the License. }
20 | { }
21 | {******************************************************************************}
22 | package OpenAPI;
23 |
24 | {$R *.res}
25 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users}
26 | {$ALIGN 8}
27 | {$ASSERTIONS ON}
28 | {$BOOLEVAL OFF}
29 | {$DEBUGINFO OFF}
30 | {$EXTENDEDSYNTAX ON}
31 | {$IMPORTEDDATA ON}
32 | {$IOCHECKS ON}
33 | {$LOCALSYMBOLS ON}
34 | {$LONGSTRINGS ON}
35 | {$OPENSTRINGS ON}
36 | {$OPTIMIZATION OFF}
37 | {$OVERFLOWCHECKS OFF}
38 | {$RANGECHECKS OFF}
39 | {$REFERENCEINFO ON}
40 | {$SAFEDIVIDE OFF}
41 | {$STACKFRAMES ON}
42 | {$TYPEDADDRESS OFF}
43 | {$VARSTRINGCHECKS ON}
44 | {$WRITEABLECONST OFF}
45 | {$MINENUMSIZE 1}
46 | {$IMAGEBASE $400000}
47 | {$DEFINE DEBUG}
48 | {$ENDIF IMPLICITBUILDING}
49 | {$DESCRIPTION 'Delphi OpenAPI 3 Library'}
50 | {$LIBSUFFIX AUTO}
51 | {$RUNONLY}
52 | {$IMPLICITBUILD OFF}
53 |
54 | requires
55 | rtl,
56 | Neon;
57 |
58 | contains
59 | OpenAPI.Core.Exceptions in '..\..\Source\OpenAPI.Core.Exceptions.pas',
60 | OpenAPI.Core.Interfaces in '..\..\Source\OpenAPI.Core.Interfaces.pas',
61 | OpenAPI.Model.Any in '..\..\Source\OpenAPI.Model.Any.pas',
62 | OpenAPI.Model.Base in '..\..\Source\OpenAPI.Model.Base.pas',
63 | OpenAPI.Model.Classes in '..\..\Source\OpenAPI.Model.Classes.pas',
64 | OpenAPI.Model.Expressions in '..\..\Source\OpenAPI.Model.Expressions.pas',
65 | OpenAPI.Model.JsonPointer in '..\..\Source\OpenAPI.Model.JsonPointer.pas',
66 | OpenAPI.Model.Reference in '..\..\Source\OpenAPI.Model.Reference.pas',
67 | OpenAPI.Model.Schema in '..\..\Source\OpenAPI.Model.Schema.pas',
68 | OpenAPI.Neon.Serializers in '..\..\Source\OpenAPI.Neon.Serializers.pas';
69 |
70 | end.
71 |
--------------------------------------------------------------------------------
/Packages/11.0Alexandria/OpenAPI.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paolo-rossi/OpenAPI-Delphi/02c7fbeb4256e1606fbbc5b39e95629c59423df3/Packages/11.0Alexandria/OpenAPI.res
--------------------------------------------------------------------------------
/Packages/12.0Athens/OpenAPI.dpk:
--------------------------------------------------------------------------------
1 | {******************************************************************************}
2 | { }
3 | { Delphi OpenAPI 3.0 Generator }
4 | { Copyright (c) 2018-2023 Paolo Rossi }
5 | { https://github.com/paolo-rossi/delphi-openapi }
6 | { }
7 | {******************************************************************************}
8 | { }
9 | { Licensed under the Apache License, Version 2.0 (the 'License"); }
10 | { you may not use this file except in compliance with the License. }
11 | { You may obtain a copy of the License at }
12 | { }
13 | { http://www.apache.org/licenses/LICENSE-2.0 }
14 | { }
15 | { Unless required by applicable law or agreed to in writing, software }
16 | { distributed under the License is distributed on an "AS IS" BASIS, }
17 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
18 | { See the License for the specific language governing permissions and }
19 | { limitations under the License. }
20 | { }
21 | {******************************************************************************}
22 | package OpenAPI;
23 |
24 | {$R *.res}
25 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users}
26 | {$ALIGN 8}
27 | {$ASSERTIONS ON}
28 | {$BOOLEVAL OFF}
29 | {$DEBUGINFO OFF}
30 | {$EXTENDEDSYNTAX ON}
31 | {$IMPORTEDDATA ON}
32 | {$IOCHECKS ON}
33 | {$LOCALSYMBOLS ON}
34 | {$LONGSTRINGS ON}
35 | {$OPENSTRINGS ON}
36 | {$OPTIMIZATION OFF}
37 | {$OVERFLOWCHECKS OFF}
38 | {$RANGECHECKS OFF}
39 | {$REFERENCEINFO ON}
40 | {$SAFEDIVIDE OFF}
41 | {$STACKFRAMES ON}
42 | {$TYPEDADDRESS OFF}
43 | {$VARSTRINGCHECKS ON}
44 | {$WRITEABLECONST OFF}
45 | {$MINENUMSIZE 1}
46 | {$IMAGEBASE $400000}
47 | {$DEFINE DEBUG}
48 | {$ENDIF IMPLICITBUILDING}
49 | {$DESCRIPTION 'Delphi OpenAPI 3 Library'}
50 | {$LIBSUFFIX AUTO}
51 | {$RUNONLY}
52 | {$IMPLICITBUILD OFF}
53 |
54 | requires
55 | rtl,
56 | Neon;
57 |
58 | contains
59 | OpenAPI.Core.Exceptions in '..\..\Source\OpenAPI.Core.Exceptions.pas',
60 | OpenAPI.Core.Interfaces in '..\..\Source\OpenAPI.Core.Interfaces.pas',
61 | OpenAPI.Model.Any in '..\..\Source\OpenAPI.Model.Any.pas',
62 | OpenAPI.Model.Base in '..\..\Source\OpenAPI.Model.Base.pas',
63 | OpenAPI.Model.Classes in '..\..\Source\OpenAPI.Model.Classes.pas',
64 | OpenAPI.Model.Expressions in '..\..\Source\OpenAPI.Model.Expressions.pas',
65 | OpenAPI.Model.JsonPointer in '..\..\Source\OpenAPI.Model.JsonPointer.pas',
66 | OpenAPI.Model.Reference in '..\..\Source\OpenAPI.Model.Reference.pas',
67 | OpenAPI.Model.Schema in '..\..\Source\OpenAPI.Model.Schema.pas',
68 | OpenAPI.Neon.Serializers in '..\..\Source\OpenAPI.Neon.Serializers.pas';
69 |
70 | end.
71 |
--------------------------------------------------------------------------------
/Packages/12.0Athens/OpenAPI.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paolo-rossi/OpenAPI-Delphi/02c7fbeb4256e1606fbbc5b39e95629c59423df3/Packages/12.0Athens/OpenAPI.res
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # OpenAPI for Delphi - OpenAPI 3.0 for Delphi
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | ## What is OpenAPI-Delphi
10 |
11 | **OpenAPI-Delphi** is an OpenAPI 3.0 library for [Delphi](https://www.embarcadero.com/products/delphi) that helps you to generate (and load) OpenAPI 3.0 documentation (in JSON) starting from plain Delphi classes. Delphi-OpenAPI uses the [Neon](https://github.com/paolo-rossi/delphi-neon) serialization library to transform the OpenAPI models from Delphi classes to JSON and to load a OpenAPI document into a Delphi (OpenAPI) object. Please take a look at the Demo to see OpenAPI-Delphi in action.
12 |
13 | ## General Features
14 |
15 | - OpenAPI document generation (JSON) from a Delphi (OpenAPI) object
16 | - OpenAPI loading and parsing into a Delphi (OpenAPI) object (:star2: new in 2.0)
17 | - Use plain Delphi classes to set the OpenAPI specification sections & fields
18 | - Support for JSON Schema (the OpenAPI version)
19 | - Support for Schema field recursion (:star2: new in 2.0)
20 | - Full Support for enum of any type (:star2: new in 2.0)
21 | - Use 1-line code (using the [Neon](https://github.com/paolo-rossi/delphi-neon) library) to transform from and to JSON documents
22 |
23 | ## Delphi Compatibility
24 | This library has been tested with **Delphi 12 Athens**, **Delphi 11 Alexandria**, **Delphi 10.4 Sydney**, **Delphi 10.3 Rio**, **Delphi 10.2 Tokyo**.
25 |
26 |
27 | ## Todo
28 | - Full validation for the OpenAPI models
29 |
30 |
--------------------------------------------------------------------------------
/Source/OpenAPI.Core.Exceptions.pas:
--------------------------------------------------------------------------------
1 | {******************************************************************************}
2 | { }
3 | { Delphi OpenAPI 3.0 Generator }
4 | { Copyright (c) 2018-2021 Paolo Rossi }
5 | { https://github.com/paolo-rossi/delphi-openapi }
6 | { }
7 | {******************************************************************************}
8 | { }
9 | { Licensed under the Apache License, Version 2.0 (the 'License"); }
10 | { you may not use this file except in compliance with the License. }
11 | { You may obtain a copy of the License at }
12 | { }
13 | { http://www.apache.org/licenses/LICENSE-2.0 }
14 | { }
15 | { Unless required by applicable law or agreed to in writing, software }
16 | { distributed under the License is distributed on an "AS IS" BASIS, }
17 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
18 | { See the License for the specific language governing permissions and }
19 | { limitations under the License. }
20 | { }
21 | {******************************************************************************}
22 | unit OpenAPI.Core.Exceptions;
23 |
24 | interface
25 |
26 | uses
27 | System.SysUtils, System.Classes;
28 |
29 | type
30 | EOpenAPIException = class(Exception);
31 |
32 | implementation
33 |
34 | end.
35 |
--------------------------------------------------------------------------------
/Source/OpenAPI.Core.Interfaces.pas:
--------------------------------------------------------------------------------
1 | {******************************************************************************}
2 | { }
3 | { Delphi OpenAPI 3.0 Generator }
4 | { Copyright (c) 2018-2021 Paolo Rossi }
5 | { https://github.com/paolo-rossi/delphi-openapi }
6 | { }
7 | {******************************************************************************}
8 | { }
9 | { Licensed under the Apache License, Version 2.0 (the 'License"); }
10 | { you may not use this file except in compliance with the License. }
11 | { You may obtain a copy of the License at }
12 | { }
13 | { http://www.apache.org/licenses/LICENSE-2.0 }
14 | { }
15 | { Unless required by applicable law or agreed to in writing, software }
16 | { distributed under the License is distributed on an "AS IS" BASIS, }
17 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
18 | { See the License for the specific language governing permissions and }
19 | { limitations under the License. }
20 | { }
21 | {******************************************************************************}
22 | unit OpenAPI.Core.Interfaces;
23 |
24 | interface
25 |
26 | implementation
27 |
28 | type
29 | IOpenAPIElement = interface
30 | ['{F7230DE3-B52E-4A2A-8A32-FF409E4ADD49}']
31 | end;
32 |
33 | IOpenAPICheckable = interface
34 | ['{0B22E054-370D-46AF-BB53-3A8827EE6907}']
35 | function CheckModel: Boolean;
36 | end;
37 |
38 | end.
39 |
--------------------------------------------------------------------------------
/Source/OpenAPI.Model.Any.pas:
--------------------------------------------------------------------------------
1 | {******************************************************************************}
2 | { }
3 | { Delphi OpenAPI 3.0 Generator }
4 | { Copyright (c) 2018-2023 Paolo Rossi }
5 | { https://github.com/paolo-rossi/delphi-openapi }
6 | { }
7 | {******************************************************************************}
8 | { }
9 | { Licensed under the Apache License, Version 2.0 (the 'License"); }
10 | { you may not use this file except in compliance with the License. }
11 | { You may obtain a copy of the License at }
12 | { }
13 | { http://www.apache.org/licenses/LICENSE-2.0 }
14 | { }
15 | { Unless required by applicable law or agreed to in writing, software }
16 | { distributed under the License is distributed on an "AS IS" BASIS, }
17 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
18 | { See the License for the specific language governing permissions and }
19 | { limitations under the License. }
20 | { }
21 | {******************************************************************************}
22 | unit OpenAPI.Model.Any;
23 |
24 | interface
25 |
26 | uses
27 | System.Rtti,
28 |
29 | Neon.Core.Attributes,
30 | Neon.Core.Nullables,
31 | OpenAPI.Model.Base;
32 |
33 | {$SCOPEDENUMS ON}
34 |
35 | type
36 |
37 | {$REGION 'Enum Types'}
38 | ///
39 | /// Type of an
40 | ///
41 | TAny = (
42 | TypePrimitive,
43 | TypeNull,
44 | TypeArray,
45 | TypeObject
46 | );
47 |
48 | ///
49 | /// Primitive type.
50 | ///
51 | TPrimitive = (
52 | TypeInteger,
53 | TypeLong,
54 | TypeFloat,
55 | TypeDouble,
56 | TypeString,
57 | TypeBytes,
58 | TypeBinary,
59 | TypeBoolean,
60 | TypeDate,
61 | TypeDateTime,
62 | TypePassword
63 | );
64 |
65 | {$ENDREGION}
66 |
67 |
68 | ///
69 | /// Represents an Open API element.
70 | ///
71 | IOpenApiElement = interface
72 | ['{F7230DE3-B52E-4A2A-8A32-FF409E4ADD49}']
73 | end;
74 |
75 | ///
76 | /// Base interface for all the types that represent Open API Any.
77 | ///
78 | IOpenApiAny = interface(IOpenApiElement)
79 | ['{AB82F994-F48C-4D24-89A7-7EDC2854ED62}']
80 | ///
81 | /// Type of an .
82 | ///
83 | function GetAny: TAny;
84 | property Any: TAny read GetAny;
85 | end;
86 |
87 | ///
88 | /// Base interface for the Primitive type.
89 | ///
90 | IOpenApiPrimitive = interface(IOpenApiAny)
91 | ['{193D437C-682E-457D-B24F-C1C15EDFAD67}']
92 | ///
93 | /// Primitive type.
94 | ///
95 | function GetPrimitive: TPrimitive;
96 | property Primitive: TPrimitive read GetPrimitive;
97 | end;
98 |
99 | ///
100 | /// Open API primitive class.
101 | ///
102 | ///
103 | TOpenAPIAnyValue = class(TInterfacedObject, IOpenApiPrimitive)
104 | private
105 | FValue: T;
106 | function GetAny: TAny;
107 | protected
108 | function GetPrimitive: TPrimitive; virtual; abstract;
109 | public
110 | ///
111 | /// Initializes the class with the given value.
112 | ///
113 | ///
114 | constructor Create(const AValue: T);
115 |
116 | ///
117 | /// The kind of .
118 | ///
119 | property Any: TAny read GetAny;
120 |
121 | ///
122 | /// The primitive class this object represents.
123 | ///
124 | property PrimitiveType: TPrimitive read GetPrimitive;
125 |
126 | ///
127 | /// Value of this
128 | ///
129 | property Value: T read FValue;
130 | end;
131 |
132 | ///
133 | /// Open API boolean.
134 | ///
135 | TOpenAPIInteger = class(TOpenAPIAnyValue)
136 | protected
137 | ///
138 | /// Primitive type this object represents.
139 | ///
140 | function GetPrimitive: TPrimitive; override;
141 | public
142 | ///
143 | /// Initializes the class.
144 | ///
145 | ///
146 | constructor Create(const AValue: Integer);
147 | end;
148 |
149 | ///
150 | /// Open API boolean.
151 | ///
152 | TOpenAPIBoolean = class(TOpenAPIAnyValue)
153 | protected
154 | ///
155 | /// Primitive type this object represents.
156 | ///
157 | function GetPrimitive: TPrimitive; override;
158 | public
159 | ///
160 | /// Initializes the class.
161 | ///
162 | ///
163 | constructor Create(const AValue: Boolean);
164 | end;
165 |
166 | ///
167 | /// Open API boolean.
168 | ///
169 | TOpenAPIString = class(TOpenAPIAnyValue)
170 | protected
171 | ///
172 | /// Primitive type this object represents.
173 | ///
174 | function GetPrimitive: TPrimitive; override;
175 | public
176 | ///
177 | /// Initializes the class.
178 | ///
179 | ///
180 | constructor Create(const AValue: string);
181 | end;
182 |
183 | ///
184 | /// Class for representing... any value
185 | ///
186 | TOpenAPIAny = class
187 | private
188 | FValue: TValue;
189 | public
190 | procedure ValueFrom(const Value: T);
191 |
192 | [NeonInclude(IncludeIf.NotEmpty)]
193 | property Value: TValue read FValue write FValue;
194 | end;
195 |
196 | TOpenAPIAnyValue = TValue;
197 | TOpenAPIAnyValues = TOpenAPIList;
198 |
199 | implementation
200 |
201 | { TOpenAPIAnyValue }
202 |
203 | constructor TOpenAPIAnyValue.Create(const AValue: T);
204 | begin
205 | FValue := AValue;
206 | end;
207 |
208 | function TOpenAPIAnyValue.GetAny: TAny;
209 | begin
210 | Result := TAny.TypePrimitive;
211 | end;
212 |
213 | { TOpenAPIBoolean }
214 |
215 | constructor TOpenAPIBoolean.Create(const AValue: Boolean);
216 | begin
217 | inherited Create(AValue);
218 | end;
219 |
220 | function TOpenAPIBoolean.GetPrimitive: TPrimitive;
221 | begin
222 | Result := TPrimitive.TypeBoolean;
223 | end;
224 |
225 | { TOpenAPIString }
226 |
227 | constructor TOpenAPIString.Create(const AValue: string);
228 | begin
229 | FValue := AValue;
230 | end;
231 |
232 | function TOpenAPIString.GetPrimitive: TPrimitive;
233 | begin
234 | Result := TPrimitive.TypeString;
235 | end;
236 |
237 | { TOpenAPIInteger }
238 |
239 | constructor TOpenAPIInteger.Create(const AValue: Integer);
240 | begin
241 | FValue := AValue;
242 | end;
243 |
244 | function TOpenAPIInteger.GetPrimitive: TPrimitive;
245 | begin
246 | Result := TPrimitive.TypeInteger;
247 | end;
248 |
249 | { TOpenAPIAny }
250 |
251 | procedure TOpenAPIAny.ValueFrom(const Value: T);
252 | begin
253 | FValue := TValue.From(Value);
254 | end;
255 |
256 | end.
257 |
--------------------------------------------------------------------------------
/Source/OpenAPI.Model.Base.pas:
--------------------------------------------------------------------------------
1 | {******************************************************************************}
2 | { }
3 | { Delphi OpenAPI 3.0 Generator }
4 | { Copyright (c) 2018-2023 Paolo Rossi }
5 | { https://github.com/paolo-rossi/delphi-openapi }
6 | { }
7 | {******************************************************************************}
8 | { }
9 | { Licensed under the Apache License, Version 2.0 (the 'License"); }
10 | { you may not use this file except in compliance with the License. }
11 | { You may obtain a copy of the License at }
12 | { }
13 | { http://www.apache.org/licenses/LICENSE-2.0 }
14 | { }
15 | { Unless required by applicable law or agreed to in writing, software }
16 | { distributed under the License is distributed on an "AS IS" BASIS, }
17 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
18 | { See the License for the specific language governing permissions and }
19 | { limitations under the License. }
20 | { }
21 | {******************************************************************************}
22 | unit OpenAPI.Model.Base;
23 |
24 | interface
25 |
26 | uses
27 | System.SysUtils, System.Classes, System.Rtti, System.Generics.Collections,
28 | System.JSON,
29 |
30 | Neon.Core.Types,
31 | Neon.Core.Nullables,
32 | Neon.Core.Attributes,
33 | OpenAPI.Core.Exceptions,
34 | OpenAPI.Model.Reference;
35 |
36 | type
37 | ///
38 | /// Base class for OpenAPI model classes
39 | ///
40 | TOpenAPIModel = class
41 | protected
42 | FSubObjects: TObjectList;
43 | function InternalCheckModel: Boolean; virtual;
44 | public
45 | constructor Create;
46 | destructor Destroy; override;
47 | function CreateSubObject: T;
48 | function AddSubObject(Value: T): T;
49 | function RemoveSubObject(const Value: T): Integer;
50 | public
51 | function CheckModel: Boolean; inline;
52 | end;
53 |
54 | ///
55 | /// Class for OpenAPI Extensions. Extensions are custom properties
56 | /// and they can be used to describe extra functionality that is not
57 | /// covered by the standard OpenAPI Specification.
58 | ///
59 | TOpenAPIExtensions = class(TOpenAPIModel)
60 | private
61 | FValues: TJSONObject;
62 | procedure CheckName(const AName: string);
63 | public
64 | constructor Create;
65 |
66 | procedure Add(const AName: string; const AValue: NullString); overload;
67 | procedure Add(const AName: string; const AValue: NullDouble); overload;
68 | procedure Add(const AName: string; const AValue: NullInteger); overload;
69 | procedure Add(const AName: string; const AValue: NullBoolean); overload;
70 | procedure Add(const AName: string; const AValue: TJSONValue; AOWned: Boolean = True); overload;
71 | public
72 | [NeonUnwrapped] [NeonInclude(IncludeIf.NotEmpty)]
73 | property Values: TJSONObject read FValues write FValues;
74 | end;
75 |
76 | ///
77 | /// Class for a property extension
78 | ///
79 | ///
80 | /// Deprecated, use TOpenAPIExtensions
81 | ///
82 | TOpenAPIExtension = class(TObjectDictionary)
83 | public
84 | constructor Create;
85 | end;
86 |
87 | ///
88 | /// Base class for OpenAPI classes that are Extensible ( OpenAPIInfo,
89 | /// OpenAPIPaths, OpenAPIPathItem, OpenAPIOperation, OpenAPIParameter,
90 | /// OpenAPIResponses, OpenAPITag, OpenAPISecurityScheme)
91 | ///
92 | TOpenAPIExtensible = class(TOpenAPIModel)
93 | protected
94 | FExtensions: TOpenAPIExtensions;
95 | public
96 | constructor Create;
97 |
98 | ///
99 | /// This object MAY be extended with Specification Extensions.
100 | ///
101 | [NeonUnwrapped] [NeonInclude(IncludeIf.NotEmpty)]
102 | property Extensions: TOpenAPIExtensions read FExtensions write FExtensions;
103 | end;
104 |
105 | ///
106 | /// Class for the Reference Object
107 | ///
108 | TOpenAPIModelReference = class(TOpenAPIExtensible)
109 | protected
110 | FUnresolvedReference: NullBoolean;
111 | FReference: TOpenAPIReference;
112 | public
113 | constructor Create;
114 |
115 | function IsReference: Boolean;
116 |
117 | ///
118 | /// Indicates object is a placeholder reference to an actual object and does not contain valid data.
119 | ///
120 | [NeonIgnore]
121 | property UnresolvedReference: NullBoolean read FUnresolvedReference write FUnresolvedReference;
122 |
123 | ///
124 | /// Reference object.
125 | ///
126 | [NeonProperty('$ref')][NeonInclude(IncludeIf.NotEmpty)]
127 | property Reference: TOpenAPIReference read FReference write FReference;
128 | end;
129 |
130 |
131 | ///
132 | /// Base class for the value-based lists
133 | ///
134 | TOpenAPIList = class(TList)
135 | public
136 | function IsEmpty: Boolean;
137 | end;
138 |
139 | ///
140 | /// Base class for the OpenAPI lists
141 | ///
142 | TOpenAPIModelList = class(TObjectList)
143 | public
144 | constructor Create;
145 | function IsEmpty: Boolean;
146 | end;
147 |
148 | ///
149 | /// Value-owned Map
150 | ///
151 | TOpenAPIOwnedMap = class(TObjectDictionary)
152 | public
153 | constructor Create;
154 | end;
155 |
156 | ///
157 | /// Base class for the OpenAPI Maps
158 | ///
159 | TOpenAPIModelMap = class(TOpenAPIOwnedMap)
160 | public
161 | function IsEmpty: Boolean;
162 | end;
163 |
164 | ///
165 | /// Base class for the OpenAPI maps extensible with the Extension
166 | /// Specifications
167 | ///
168 | TOpenAPIModelExtensibleMap = class(TOpenAPIModelMap)
169 | private
170 | FExtensions: TOpenAPIExtensions;
171 | public
172 | constructor Create;
173 | destructor Destroy; override;
174 |
175 | ///
176 | /// This object MAY be extended with Specification Extensions.
177 | ///
178 | [NeonUnwrapped] [NeonInclude(IncludeIf.NotEmpty)]
179 | property Extensions: TOpenAPIExtensions read FExtensions write FExtensions;
180 | end;
181 |
182 | implementation
183 |
184 | { TOpenAPIModel }
185 |
186 | function TOpenAPIModel.AddSubObject(Value: T): T;
187 | begin
188 | FSubObjects.Add(Value);
189 | Result := Value;
190 | end;
191 |
192 | function TOpenAPIModel.CheckModel: Boolean;
193 | begin
194 | Result := InternalCheckModel;
195 | end;
196 |
197 | constructor TOpenAPIModel.Create;
198 | begin
199 | FSubObjects := TObjectList.Create(True);
200 | end;
201 |
202 | function TOpenAPIModel.CreateSubObject: T;
203 | begin
204 | Result := T.Create;
205 | FSubObjects.Add(Result);
206 | end;
207 |
208 | destructor TOpenAPIModel.Destroy;
209 | begin
210 | FSubObjects.Free;
211 | inherited;
212 | end;
213 |
214 | function TOpenAPIModel.InternalCheckModel: Boolean;
215 | begin
216 | Result := True;
217 | end;
218 |
219 | function TOpenAPIModel.RemoveSubObject(const Value: T): Integer;
220 | begin
221 | Result := FSubObjects.Remove(Value);
222 | end;
223 |
224 | { TOpenAPIExtension }
225 |
226 | constructor TOpenAPIExtension.Create;
227 | begin
228 | inherited Create();
229 | end;
230 |
231 | procedure TOpenAPIExtensions.Add(const AName: string; const AValue: NullString);
232 | begin
233 | CheckName(AName);
234 | FValues.AddPair(AName, AValue.Value);
235 | end;
236 |
237 | procedure TOpenAPIExtensions.Add(const AName: string; const AValue: NullDouble);
238 | begin
239 | CheckName(AName);
240 | FValues.AddPair(AName, TJSONNumber.Create(AValue.Value));
241 | end;
242 |
243 | procedure TOpenAPIExtensions.Add(const AName: string; const AValue: NullInteger);
244 | begin
245 | CheckName(AName);
246 | FValues.AddPair(AName, TJSONNumber.Create(AValue.Value));
247 | end;
248 |
249 | procedure TOpenAPIExtensions.Add(const AName: string; const AValue: NullBoolean);
250 | begin
251 | CheckName(AName);
252 | FValues.AddPair(AName, TJSONBool.Create(AValue.Value));
253 | end;
254 |
255 | procedure TOpenAPIExtensions.CheckName(const AName: string);
256 | begin
257 | if not AName.StartsWith('x-') then
258 | raise EOpenAPIException.Create('An extension must start with "x-"');
259 | end;
260 |
261 | constructor TOpenAPIExtensions.Create;
262 | begin
263 | inherited Create;
264 | FValues := CreateSubObject;
265 | end;
266 |
267 | procedure TOpenAPIExtensions.Add(const AName: string; const AValue: TJSONValue; AOWned: Boolean);
268 | begin
269 | CheckName(AName);
270 | if AOWned then
271 | FValues.AddPair(AName, AValue)
272 | else
273 | FValues.AddPair(AName, AValue.Clone as TJSONValue);
274 | end;
275 |
276 | { TOpenAPIExtensible }
277 |
278 | constructor TOpenAPIExtensible.Create;
279 | begin
280 | inherited Create;
281 | FExtensions := CreateSubObject;
282 | end;
283 |
284 | { TOpenAPIModelReference }
285 |
286 | constructor TOpenAPIModelReference.Create;
287 | begin
288 | inherited Create;
289 | FReference := CreateSubObject;
290 | end;
291 |
292 | function TOpenAPIModelReference.IsReference: Boolean;
293 | begin
294 | Result := not FReference.Ref.IsEmpty;
295 | end;
296 |
297 | { TOpenAPIModelExtensibleMap }
298 |
299 | constructor TOpenAPIModelExtensibleMap.Create;
300 | begin
301 | inherited Create;
302 | FExtensions := TOpenAPIExtensions.Create;
303 | end;
304 |
305 | destructor TOpenAPIModelExtensibleMap.Destroy;
306 | begin
307 | FExtensions.Free;
308 | inherited;
309 | end;
310 |
311 | { TOpenAPIModelList }
312 |
313 | constructor TOpenAPIModelList.Create;
314 | begin
315 | inherited Create(True);
316 | end;
317 |
318 | function TOpenAPIModelList.IsEmpty: Boolean;
319 | begin
320 | Result := Count = 0;
321 | end;
322 |
323 | { TOpenAPIOwnedMap }
324 |
325 | constructor TOpenAPIOwnedMap.Create;
326 | begin
327 | inherited Create([doOwnsValues]);
328 | end;
329 |
330 | { TOpenAPIModelMap }
331 |
332 | function TOpenAPIModelMap.IsEmpty: Boolean;
333 | begin
334 | Result := Count = 0;
335 | end;
336 |
337 | { TOpenAPIList }
338 |
339 | function TOpenAPIList.IsEmpty: Boolean;
340 | begin
341 | Result := Count = 0;
342 | end;
343 |
344 | end.
345 |
--------------------------------------------------------------------------------
/Source/OpenAPI.Model.Expressions.pas:
--------------------------------------------------------------------------------
1 | {******************************************************************************}
2 | { }
3 | { Delphi OpenAPI 3.0 Generator }
4 | { Copyright (c) 2018-2019 Paolo Rossi }
5 | { https://github.com/paolo-rossi/delphi-openapi }
6 | { }
7 | {******************************************************************************}
8 | { }
9 | { Licensed under the Apache License, Version 2.0 (the "License"); }
10 | { you may not use this file except in compliance with the License. }
11 | { You may obtain a copy of the License at }
12 | { }
13 | { http://www.apache.org/licenses/LICENSE-2.0 }
14 | { }
15 | { Unless required by applicable law or agreed to in writing, software }
16 | { distributed under the License is distributed on an "AS IS" BASIS, }
17 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
18 | { See the License for the specific language governing permissions and }
19 | { limitations under the License. }
20 | { }
21 | {******************************************************************************}
22 | unit OpenAPI.Model.Expressions;
23 |
24 | interface
25 |
26 | uses
27 | System.SysUtils, System.Classes, System.Generics.Collections, System.RegularExpressions,
28 | OpenAPI.Model.JsonPointer,
29 | OpenAPI.Model.Reference;
30 |
31 | type
32 | ///
33 | /// Base class for the Open API runtime expression.
34 | ///
35 | TRuntimeExpression = class abstract
36 | public const
37 | PREFIX = '$';
38 | protected
39 | FExpression: string;
40 | function GetExpression: string; virtual; abstract;
41 | public
42 | class function Build(const AExpression: string): TRuntimeExpression; virtual;
43 |
44 | function ToString: string; override;
45 | procedure FromString(const AValue: string);
46 |
47 | property Expression: string read GetExpression;
48 | end;
49 |
50 | TRuntimeExpressions = class(TObjectList)
51 | end;
52 |
53 | TRuntimeExpressionMap = class(TObjectDictionary)
54 | end;
55 |
56 |
57 | ///
58 | /// String literal with embedded expressions
59 | ///
60 | TCompositeExpression = class(TRuntimeExpression)
61 | private const
62 | REGEX_PATTERN = '@"{(?\$[^}]*)"';
63 | private
64 | FTemplate: string;
65 | FExpressionPattern: TRegEx;
66 | FContainedExpressions: TObjectList;
67 | protected
68 | function GetExpression: string; override;
69 | public
70 | ///
71 | /// Create a composite expression from a string literal with an embedded expression
72 | ///
73 | ///
74 | constructor Create(const AExpression: string);
75 | destructor Destroy; override;
76 |
77 | ///
78 | /// Expressions embedded into string literal
79 | ///
80 | property ContainedExpressions: TObjectList read FContainedExpressions write FContainedExpressions;
81 | end;
82 |
83 | ///
84 | /// Source expression.
85 | ///
86 | TSourceExpression = class(TRuntimeExpression)
87 | protected
88 | ///
89 | /// Gets the expression string.
90 | ///
91 | FValue: string;
92 |
93 | ///
94 | /// Initializes a new instance of the class.
95 | ///
96 | /// The value string.
97 | constructor Create(const AValue: string);
98 | public
99 | ///
100 | /// Build the source expression from input string.
101 | ///
102 | /// The source expression.
103 | /// The built source expression.
104 | class function Build(const AExpression: string): TSourceExpression; reintroduce;
105 | end;
106 |
107 | ///
108 | /// URL expression.
109 | ///
110 | TURLExpression = class sealed(TRuntimeExpression)
111 | public
112 | ///
113 | /// $url string.
114 | ///
115 | const URL = '$url';
116 | public
117 | ///
118 | /// Gets the expression string.
119 | ///
120 | function GetExpression: string; override;
121 | end;
122 |
123 | ///
124 | /// Method expression.
125 | ///
126 | TMethodExpression = class sealed(TRuntimeExpression)
127 | public
128 | ///
129 | /// $method. string
130 | ///
131 | const METHOD = '$method';
132 | public
133 | ///
134 | /// Gets the expression string.
135 | ///
136 | function GetExpression: string; override;
137 | end;
138 |
139 | ///
140 | /// StatusCode expression.
141 | ///
142 | TStatusCodeExpression = class sealed(TRuntimeExpression)
143 | public
144 | ///
145 | /// $statusCode. string
146 | ///
147 | const STATUSCODE = '$statusCode';
148 | public
149 | ///
150 | /// Gets the expression string.
151 | ///
152 | function GetExpression: string; override;
153 | end;
154 |
155 | ///
156 | /// Request expression.
157 | ///
158 | TRequestExpression = class sealed(TRuntimeExpression)
159 | public
160 | ///
161 | /// $request. string
162 | ///
163 | const REQUEST = '$request.';
164 | private
165 | FSource: TSourceExpression;
166 | function GetSource: TSourceExpression;
167 | public
168 | ///
169 | /// Initializes a new instance of the class.
170 | ///
171 | /// The source of the request.
172 | constructor Create(ASource: TSourceExpression);
173 |
174 | ///
175 | /// Gets the expression string.
176 | ///
177 | function GetExpression: string; override;
178 |
179 | ///
180 | /// The expression.
181 | ///
182 | property Source: TSourceExpression read GetSource;
183 | end;
184 |
185 | TResponseExpression = class(TRuntimeExpression)
186 | ///
187 | /// $response. string
188 | ///
189 | public const RESPONSE = '$response.';
190 | private
191 | FSource: TSourceExpression;
192 | public
193 | ///
194 | /// Create a new instance of the class.
195 | ///
196 | /// The source of the response.
197 | constructor Create(ASource: TSourceExpression);
198 |
199 | ///
200 | /// Gets the expression string.
201 | ///
202 | function GetExpression: string; override;
203 | //public override string Expression => Response + Source.Expression;
204 |
205 | ///
206 | /// The expression.
207 | ///
208 | property Source: TSourceExpression read FSource;
209 | end;
210 |
211 | ///
212 | /// Body expression.
213 | ///
214 | TBodyExpression = class sealed(TSourceExpression)
215 | public
216 | ///
217 | /// body string
218 | ///
219 | const BODY = 'body';
220 |
221 | ///
222 | /// Prefix for a pointer
223 | ///
224 | const POINTER_PREFIX = '#';
225 | private
226 | function GetFragment: string;
227 | protected
228 | ///
229 | /// Gets the expression string.
230 | ///
231 | function GetExpression: string; override;
232 | public
233 | ///
234 | /// Initializes a new instance of the class.
235 | ///
236 | /// a JSON Pointer [RFC 6901](https://tools.ietf.org/html/rfc6901).
237 | constructor Create(APointer: TJsonPointer);
238 |
239 | ///
240 | /// Gets the fragment string.
241 | ///
242 | property Fragment: string read GetFragment;
243 | end;
244 |
245 | ///
246 | /// Header expression, The token identifier in header is case-insensitive.
247 | ///
248 | THeaderExpression = class(TSourceExpression)
249 | ///
250 | /// header. string
251 | ///
252 | public const HEADER = 'header.';
253 | private
254 | function GetToken: string;
255 | protected
256 | ///
257 | /// Gets the expression string.
258 | ///
259 | function GetExpression: string; override;
260 | public
261 | ///
262 | /// Initializes a new instance of the class.
263 | ///
264 | /// The token string, it's case-insensitive.
265 | constructor Create(const AToken: string);
266 | {
267 | if (string.IsNullOrWhiteSpace(token))
268 | throw Error.ArgumentNullOrWhiteSpace(nameof(token));
269 | }
270 |
271 | ///
272 | /// Gets the expression string.
273 | ///
274 | //public override string Expression
275 | {
276 | return Header + Value;
277 | }
278 |
279 | ///
280 | /// Gets the token string.
281 | ///
282 | property Token: string read GetToken;
283 | {
284 | return Value;
285 | }
286 | end;
287 |
288 | implementation
289 |
290 | uses
291 | OpenAPI.Core.Exceptions;
292 |
293 | { TRuntimeExpression }
294 |
295 | class function TRuntimeExpression.Build(const AExpression: string): TRuntimeExpression;
296 | var
297 | LSubString: string;
298 | LSource: TSourceExpression;
299 | begin
300 | if AExpression.IsEmpty then
301 | raise Exception.Create('Expression empty');
302 |
303 | if not AExpression.StartsWith(PREFIX) then
304 | Exit(TCompositeExpression.Create(AExpression));
305 |
306 | // $url
307 | if AExpression = TURLExpression.URL then
308 | Exit(TURLExpression.Create);
309 |
310 | // $method
311 | if AExpression = TMethodExpression.METHOD then
312 | Exit(TMethodExpression.Create);
313 |
314 | // $statusCode
315 | if AExpression = TStatusCodeExpression.STATUSCODE then
316 | Exit(TStatusCodeExpression.Create);
317 |
318 | // $request.
319 | if AExpression.StartsWith(TRequestExpression.REQUEST) then
320 | begin
321 | LSubString := AExpression.Substring(TRequestExpression.REQUEST.Length);
322 | LSource := TSourceExpression.Build(LSubString);
323 | Exit(TRequestExpression(LSource));
324 | end;
325 |
326 | // $response.
327 | if AExpression.StartsWith(TResponseExpression.RESPONSE) then
328 | begin
329 | LSubString := AExpression.Substring(TResponseExpression.RESPONSE.Length);
330 | LSource := TSourceExpression.Build(LSubString);
331 | Exit(TResponseExpression(LSource));
332 | end;
333 |
334 | raise EOpenAPIException.Create(Format('Runtime Expression Has Invalid Format: %s', [AExpression]));
335 | end;
336 |
337 | procedure TRuntimeExpression.FromString(const AValue: string);
338 | begin
339 | FExpression := AValue;
340 | end;
341 |
342 | function TRuntimeExpression.ToString: string;
343 | begin
344 | Result := Expression;
345 | end;
346 |
347 | { TCompositeExpression }
348 |
349 | constructor TCompositeExpression.Create(const AExpression: string);
350 | var
351 | LValue: string;
352 | LMatch: TMatch;
353 | LMatches: TMatchCollection;
354 | begin
355 | FContainedExpressions := TObjectList.Create(True);
356 |
357 | FTemplate := AExpression;
358 |
359 | // Extract subexpressions and convert to RuntimeExpressions
360 | LMatches := FExpressionPattern.Matches(AExpression);
361 |
362 | for LMatch in LMatches do
363 | begin
364 | if LMatch.Success then
365 | begin
366 | LValue := LMatch.Groups['exp'].Value;
367 | FContainedExpressions.Add(TRuntimeExpression.Build(LValue));
368 | end;
369 | end;
370 | end;
371 |
372 | destructor TCompositeExpression.Destroy;
373 | begin
374 | FContainedExpressions.Free;
375 | inherited;
376 | end;
377 |
378 | function TCompositeExpression.GetExpression: string;
379 | begin
380 | Result := FTemplate;
381 | end;
382 |
383 | { TSourceExpression }
384 |
385 | class function TSourceExpression.Build(const AExpression: string): TSourceExpression;
386 | var
387 | LSubString: string;
388 | LExpressions: TArray;
389 | begin
390 | { TODO -opaolo -c : to finish 31/03/2019 11:15:25 }
391 | if not string.IsNullOrWhiteSpace(AExpression) then
392 | begin
393 | LExpressions := AExpression.Split(['.']);
394 | if Length(LExpressions) = 2 then
395 | begin
396 | if AExpression.StartsWith(THeaderExpression.HEADER) then
397 | // header.
398 | Exit(THeaderExpression(LExpressions[1]));
399 | {
400 | if AExpression.StartsWith(TQueryExpression.QUERY) then
401 | // query.
402 | Exit(TQueryExpression(LExpressions[1]));
403 |
404 | if AExpression.StartsWith(TPathExpression.PATH) then
405 | // path.
406 | Exit(PathExpression(LExpressions[1]));
407 | }
408 | end;
409 |
410 | // body
411 | if AExpression.StartsWith(TBodyExpression.BODY) then
412 | begin
413 | LSubString := AExpression.Substring(Length(TBodyExpression.BODY));
414 | if string.IsNullOrEmpty(LSubString) then
415 | Exit(TBodyExpression.Create(nil));
416 |
417 | Exit(TBodyExpression.Create(TJsonPointer.Create(LSubString)));
418 | end;
419 | end;
420 | raise EOpenAPIException.Create('Source Expression invalid format');
421 | end;
422 |
423 | constructor TSourceExpression.Create(const AValue: string);
424 | begin
425 | FValue := AValue;
426 | end;
427 |
428 | { TURLExpression }
429 |
430 | function TURLExpression.GetExpression: string;
431 | begin
432 | Result := URL;
433 | end;
434 |
435 | { TRequestExpression }
436 |
437 | constructor TRequestExpression.Create(ASource: TSourceExpression);
438 | begin
439 | Assert(ASource <> nil);
440 | FSource := ASource;
441 | end;
442 |
443 | function TRequestExpression.GetExpression: string;
444 | begin
445 | Result := REQUEST + Source.Expression;
446 | end;
447 |
448 | function TRequestExpression.GetSource: TSourceExpression;
449 | begin
450 | Result := FSource;
451 | end;
452 |
453 | { TMethodExpression }
454 |
455 | function TMethodExpression.GetExpression: string;
456 | begin
457 | Result := METHOD;
458 | end;
459 |
460 | { TStatusCodeExpression }
461 |
462 | function TStatusCodeExpression.GetExpression: string;
463 | begin
464 | Result := STATUSCODE;
465 | end;
466 |
467 | { TBodyExpression }
468 |
469 | constructor TBodyExpression.Create(APointer: TJsonPointer);
470 | begin
471 | // : base(pointer?.ToString())
472 | if not Assigned(APointer) then
473 | raise EArgumentNilException.Create('JsonPointer is null');
474 |
475 | inherited Create(APointer.ToString);
476 | end;
477 |
478 | function TBodyExpression.GetExpression: string;
479 | begin
480 | if string.IsNullOrWhiteSpace(FValue) then
481 | Exit(BODY);
482 |
483 | Result := BODY + POINTER_PREFIX + FValue;
484 | end;
485 |
486 | function TBodyExpression.GetFragment: string;
487 | begin
488 | Result := FValue;
489 | end;
490 |
491 | { TResponseExpression }
492 |
493 | constructor TResponseExpression.Create(ASource: TSourceExpression);
494 | begin
495 | FSource := ASource;
496 | end;
497 |
498 | function TResponseExpression.GetExpression: string;
499 | begin
500 | Result := RESPONSE + Source.Expression;
501 | end;
502 |
503 | { THeaderExpression }
504 |
505 | constructor THeaderExpression.Create(const AToken: string);
506 | begin
507 | if string.IsNullOrWhiteSpace(AToken) then
508 | raise Exception.Create('Argument null or whitespace');
509 |
510 | inherited Create(AToken);
511 | end;
512 |
513 | function THeaderExpression.GetExpression: string;
514 | begin
515 | Result := HEADER + FValue;
516 | end;
517 |
518 | function THeaderExpression.GetToken: string;
519 | begin
520 | Result := FValue;
521 | end;
522 |
523 | end.
524 |
525 |
--------------------------------------------------------------------------------
/Source/OpenAPI.Model.JsonPointer.pas:
--------------------------------------------------------------------------------
1 | {******************************************************************************}
2 | { }
3 | { Delphi OpenAPI 3.0 Generator }
4 | { Copyright (c) 2018-2019 Paolo Rossi }
5 | { https://github.com/paolo-rossi/delphi-openapi }
6 | { }
7 | {******************************************************************************}
8 | { }
9 | { Licensed under the Apache License, Version 2.0 (the "License"); }
10 | { you may not use this file except in compliance with the License. }
11 | { You may obtain a copy of the License at }
12 | { }
13 | { http://www.apache.org/licenses/LICENSE-2.0 }
14 | { }
15 | { Unless required by applicable law or agreed to in writing, software }
16 | { distributed under the License is distributed on an "AS IS" BASIS, }
17 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
18 | { See the License for the specific language governing permissions and }
19 | { limitations under the License. }
20 | { }
21 | {******************************************************************************}
22 | unit OpenAPI.Model.JsonPointer;
23 |
24 | interface
25 |
26 | uses
27 | System.SysUtils, System.Classes, System.Generics.Collections, System.NetEncoding;
28 |
29 | type
30 | ///
31 | /// JSON pointer expression
32 | ///
33 | TJSONPointer = class
34 | private
35 | FTokens: TArray;
36 | public
37 | ///
38 | /// Initializes the class.
39 | ///
40 | /// Pointer as string.
41 | constructor Create(APointer: string); overload;
42 | constructor Create(ATokens: TArray); overload;
43 |
44 | ///
45 | /// Decode the string.
46 | ///
47 | function Decode(const AToken: string): string;
48 |
49 | ///
50 | /// Gets the parent pointer.
51 | ///
52 | function ParentPointer: TJsonPointer;
53 |
54 | ///
55 | /// Gets the string representation of this JSON pointer.
56 | ///
57 | function ToString: string; override;
58 |
59 | ///
60 | /// Tokens.
61 | ///
62 | property Tokens: TArray read FTokens;
63 | end;
64 |
65 | implementation
66 |
67 | { TJSONPointer }
68 |
69 | constructor TJSONPointer.Create(APointer: string);
70 | var
71 | LArr: TArray;
72 | LIndex: Integer;
73 | begin
74 | LArr := APointer.Split(['/']);
75 |
76 | FTokens := [];
77 | for LIndex := Low(LArr) to High(LArr) do
78 | begin
79 | if LIndex = Low(LArr) then
80 | Continue;
81 | FTokens := FTokens + [LArr[LIndex]];
82 | end;
83 |
84 | for LIndex := Low(FTokens) to High(FTokens) do
85 | FTokens[LIndex] := Decode(FTokens[LIndex]);
86 | end;
87 |
88 | constructor TJSONPointer.Create(ATokens: TArray);
89 | begin
90 | FTokens := ATokens;
91 | end;
92 |
93 | function TJSONPointer.Decode(const AToken: string): string;
94 | begin
95 | Result := TNetEncoding.URL.Decode(AToken).Replace('~1', '/').Replace('~0', '~');
96 | end;
97 |
98 | function TJSONPointer.ParentPointer: TJsonPointer;
99 | var
100 | LParent: TArray;
101 | LIndex: Integer;
102 | begin
103 | if Length(FTokens) = 0 then
104 | Result := nil
105 | else
106 | begin
107 | for LIndex := Low(FTokens) to High(FTokens) - 1 do
108 | LParent := LParent + [FTokens[LIndex]];
109 |
110 | Result := TJSONPointer.Create(LParent);
111 | end;
112 | end;
113 |
114 | function TJSONPointer.ToString: string;
115 | begin
116 | Result := '/' + string.join('/', FTokens);
117 | end;
118 |
119 | end.
120 |
121 |
--------------------------------------------------------------------------------
/Source/OpenAPI.Model.Reference.pas:
--------------------------------------------------------------------------------
1 | {******************************************************************************}
2 | { }
3 | { Delphi OpenAPI 3.0 Generator }
4 | { Copyright (c) 2018-2019 Paolo Rossi }
5 | { https://github.com/paolo-rossi/delphi-openapi }
6 | { }
7 | {******************************************************************************}
8 | { }
9 | { Licensed under the Apache License, Version 2.0 (the "License"); }
10 | { you may not use this file except in compliance with the License. }
11 | { You may obtain a copy of the License at }
12 | { }
13 | { http://www.apache.org/licenses/LICENSE-2.0 }
14 | { }
15 | { Unless required by applicable law or agreed to in writing, software }
16 | { distributed under the License is distributed on an "AS IS" BASIS, }
17 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
18 | { See the License for the specific language governing permissions and }
19 | { limitations under the License. }
20 | { }
21 | {******************************************************************************}
22 | unit OpenAPI.Model.Reference;
23 |
24 | interface
25 |
26 | uses
27 | System.SysUtils, System.Classes, System.Generics.Collections, System.JSON,
28 |
29 | Neon.Core.Attributes;
30 |
31 | type
32 | ///
33 | /// A simple object to allow referencing other components in the specification, internally and externally.
34 | ///
35 | TOpenAPIReference = class
36 | private
37 | FId: string;
38 | FRef: string;
39 | FRefType: string;
40 | FExternalResource: string;
41 | public
42 | ///
43 | /// Gets a flag indicating whether this reference is an external reference.
44 | ///
45 | function IsExternal: Boolean;
46 |
47 | ///
48 | /// Gets a flag indicating whether this reference is a local reference.
49 | ///
50 | function IsLocal: Boolean;
51 | public
52 | ///
53 | /// The identifier of the reusable component of one particular ReferenceType.
54 | /// If ExternalResource is present, this is the path to the component after the '#/'.
55 | /// For example, if the reference is 'example.json#/path/to/component', the Id is 'path/to/component'.
56 | /// If ExternalResource is not present, this is the name of the component without the reference type name.
57 | /// For example, if the reference is '#/components/schemas/componentName', the Id is 'componentName'.
58 | ///
59 | [NeonIgnore]
60 | property Id: string read FId write FId;
61 |
62 | ///
63 | /// The element type referenced.
64 | ///
65 | /// This must be present if is not present.
66 | [NeonIgnore]
67 | property RefType: string read FRefType write FRefType;
68 |
69 | ///
70 | /// External resource in the reference.
71 | /// It maybe:
72 | /// 1. a absolute/relative file path, for example: ../commons/pet.json
73 | /// 2. a Url, for example: http://localhost/pet.json
74 | ///
75 | [NeonIgnore]
76 | property ExternalResource: string read FExternalResource write FExternalResource;
77 |
78 | [NeonProperty('$ref')][NeonInclude(IncludeIf.NotEmpty)]
79 | property Ref: string read FRef write FRef;
80 | end;
81 |
82 | implementation
83 |
84 | { TOpenAPIReference }
85 |
86 | function TOpenAPIReference.IsExternal: Boolean;
87 | begin
88 | { TODO -opaolo -c : to finish 31/03/2019 18:47:51 }
89 | Result := not FExternalResource.IsEmpty;
90 | end;
91 |
92 | function TOpenAPIReference.IsLocal: Boolean;
93 | begin
94 | { TODO -opaolo -c : to finish 31/03/2019 18:47:51 }
95 | Result := FExternalResource.IsEmpty;
96 | end;
97 |
98 | end.
99 |
--------------------------------------------------------------------------------
/Source/OpenAPI.Model.Schema.pas:
--------------------------------------------------------------------------------
1 | {******************************************************************************}
2 | { }
3 | { Delphi OpenAPI 3.0 Generator }
4 | { Copyright (c) 2018-2023 Paolo Rossi }
5 | { https://github.com/paolo-rossi/delphi-openapi }
6 | { }
7 | {******************************************************************************}
8 | { }
9 | { Licensed under the Apache License, Version 2.0 (the "License"); }
10 | { you may not use this file except in compliance with the License. }
11 | { You may obtain a copy of the License at }
12 | { }
13 | { http://www.apache.org/licenses/LICENSE-2.0 }
14 | { }
15 | { Unless required by applicable law or agreed to in writing, software }
16 | { distributed under the License is distributed on an "AS IS" BASIS, }
17 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
18 | { See the License for the specific language governing permissions and }
19 | { limitations under the License. }
20 | { }
21 | {******************************************************************************}
22 | unit OpenAPI.Model.Schema;
23 |
24 | interface
25 |
26 | uses
27 | System.SysUtils, System.Classes, System.Generics.Collections,
28 | System.JSON, System.Rtti, System.TypInfo,
29 |
30 | Neon.Core.Types,
31 | Neon.Core.Attributes,
32 | Neon.Core.Nullables,
33 | Neon.Core.Persistence,
34 | Neon.Core.Persistence.JSON.Schema,
35 |
36 | OpenAPI.Model.Any,
37 | OpenAPI.Model.Base,
38 | OpenAPI.Model.Reference;
39 |
40 | type
41 | TOpenAPISchema = class;
42 |
43 | TOpenAPIDiscriminator = class
44 | private
45 | FPropertyName: NullString;
46 | FMapping: TDictionary;
47 | public
48 | constructor Create;
49 | destructor Destroy; override;
50 |
51 | ///
52 | /// REQUIRED. The name of the property in the payload that will hold the discriminator value.
53 | ///
54 | property PropertyName: NullString read FPropertyName write FPropertyName;
55 |
56 | ///
57 | /// An object to hold mappings between payload values and schema names or references.
58 | ///
59 | [NeonInclude(IncludeIf.NotEmpty)]
60 | property Mapping: TDictionary read FMapping write FMapping;
61 | end;
62 |
63 | TOpenAPISchemaBase = class
64 | protected
65 | FType_: NullString;
66 | FTitle: NullString;
67 | FDescription: NullString;
68 | FFormat: NullString;
69 | public
70 | ///
71 | /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
72 | /// While relying on JSON Schema's defined formats,
73 | /// the OAS offers a few additional predefined formats.
74 | ///
75 | property Format: NullString read FFormat write FFormat;
76 |
77 | ///
78 | /// Follow JSON Schema definition. Short text providing information about the data.
79 | ///
80 | property Title: NullString read FTitle write FTitle;
81 |
82 | ///
83 | /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
84 | /// Value MUST be a string. Multiple types via an array are not supported.
85 | ///
86 | [NeonProperty('type')]
87 | property Type_: NullString read FType_ write FType_;
88 |
89 | ///
90 | /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
91 | /// CommonMark syntax MAY be used for rich text representation.
92 | ///
93 | property Description: NullString read FDescription write FDescription;
94 | end;
95 |
96 | TOpenAPISchemas = class(TOpenAPIModelList);
97 | TOpenAPISchemaMap = class(TOpenAPIModelMap);
98 |
99 | TOpenAPIEnum = class(TOpenAPIModelList);
100 |
101 | ///
102 | /// JSON Schema Object: https://json-schema.org/
103 | ///
104 | TOpenAPISchema = class(TOpenAPIModelReference)
105 | private
106 | FNeonConfig: INeonConfiguration;
107 | FJSONObject: TJSONObject;
108 | FJSONOwned: Boolean;
109 | private
110 | FFormat: NullString;
111 | FTitle: NullString;
112 | FType_: NullString;
113 | FDescription: NullString;
114 | FMaximum: NullDouble;
115 | FExclusiveMaximum: NullBoolean;
116 | FMinimum: NullDouble;
117 | FExclusiveMinimum: NullBoolean;
118 | FMaxLength: NullInteger;
119 | FMinLength: NullInteger;
120 | FPattern: NullString;
121 | FMultipleOf: NullDouble;
122 | FReadOnly_: NullBoolean;
123 | FWriteOnly_: NullBoolean;
124 | FAllOf: TOpenAPISchemas;
125 | FOneOf: TOpenAPISchemas;
126 | FAnyOf: TOpenAPISchemas;
127 | FNot_: TOpenAPISchema;
128 | FRequired: TArray;
129 | FItems: TOpenAPISchema;
130 | FMaxItems: NullInteger;
131 | FMinItems: NullInteger;
132 | FUniqueItems: NullBoolean;
133 | FProperties: TOpenAPISchemaMap;
134 | FMaxProperties: NullInteger;
135 | FMinProperties: NullInteger;
136 | FAdditionalPropertiesAllowed: NullBoolean;
137 | FAdditionalProperties: TOpenAPISchema;
138 | FNullable: NullBoolean;
139 | FDefault_: TOpenAPIAny;
140 | FEnum: TOpenAPIEnum;
141 | FDiscriminator: TOpenAPIDiscriminator;
142 | private
143 | function GetNeonConfig: INeonConfiguration;
144 | public
145 | constructor Create;
146 | destructor Destroy; override;
147 | public
148 | function WithNeonConfig(AConfig: INeonConfiguration): TOpenAPISchema;
149 |
150 | function AddProperty(const AKeyName: string): TOpenAPISchema;
151 | function AddEnum(const AValue: TValue): TOpenAPIAny;
152 |
153 | procedure SetJSONObject(AJSON: TJSONObject; AOwned: Boolean = True);
154 |
155 | procedure SetJSONFromType(AType: TRttiType);
156 | procedure SetJSONFromClass(AClass: TClass);
157 |
158 | procedure SetSchemaReference(const AReference: string);
159 | function IsEmpty: Boolean;
160 |
161 | [NeonIgnore]
162 | property JSONObject: TJSONObject read FJSONObject write FJSONObject;
163 | public
164 | ///
165 | /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
166 | /// While relying on JSON Schema's defined formats,
167 | /// the OAS offers a few additional predefined formats.
168 | ///
169 | property Format: NullString read FFormat write FFormat;
170 |
171 | ///
172 | /// Follow JSON Schema definition. Short text providing information about the data.
173 | ///
174 | property Title: NullString read FTitle write FTitle;
175 |
176 | ///
177 | /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
178 | /// Value MUST be a string. Multiple types via an array are not supported.
179 | ///
180 | [NeonProperty('type')]
181 | property Type_: NullString read FType_ write FType_;
182 |
183 | ///
184 | /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
185 | /// CommonMark syntax MAY be used for rich text representation.
186 | ///
187 | property Description: NullString read FDescription write FDescription;
188 |
189 | ///
190 | /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
191 | ///
192 | property Maximum: NullDouble read FMaximum write FMaximum;
193 |
194 | ///
195 | /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
196 | ///
197 | property ExclusiveMaximum: NullBoolean read FExclusiveMaximum write FExclusiveMaximum;
198 |
199 | ///
200 | /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
201 | ///
202 | property Minimum: NullDouble read FMinimum write FMinimum;
203 |
204 | ///
205 | /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
206 | ///
207 | property ExclusiveMinimum: NullBoolean read FExclusiveMinimum write FExclusiveMinimum;
208 |
209 | ///
210 | /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
211 | ///
212 | property MaxLength: NullInteger read FMaxLength write FMaxLength;
213 |
214 | ///
215 | /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
216 | ///
217 | property MinLength: NullInteger read FMinLength write FMinLength;
218 |
219 | ///
220 | /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
221 | /// This string SHOULD be a valid regular expression, according to the ECMA 262 regular expression dialect
222 | ///
223 | property Pattern: NullString read FPattern write FPattern;
224 |
225 | ///
226 | /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
227 | ///
228 | property MultipleOf: NullDouble read FMultipleOf write FMultipleOf;
229 |
230 | ///
231 | /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
232 | /// The default value represents what would be assumed by the consumer of the input as the value of the schema if one is not provided.
233 | /// Unlike JSON Schema, the value MUST conform to the defined type for the Schema Object defined at the same level.
234 | /// For example, if type is string, then default can be "foo" but cannot be 1.
235 | ///
236 | [NeonProperty('default')] [NeonInclude(IncludeIf.NotEmpty)]
237 | property Default_: TOpenAPIAny read FDefault_ write FDefault_;
238 |
239 | ///
240 | /// Relevant only for Schema "properties" definitions. Declares the property as "read only".
241 | /// This means that it MAY be sent as part of a response but SHOULD NOT be sent as part of the request.
242 | /// If the property is marked as ReadOnly_ being true and is in the required list,
243 | /// the required will take effect on the response only.
244 | /// A property MUST NOT be marked as both ReadOnly_ and WriteOnly_ being true.
245 | /// Default value is false.
246 | ///
247 | [NeonProperty('readOnly')]
248 | property ReadOnly_: NullBoolean read FReadOnly_ write FReadOnly_;
249 |
250 | ///
251 | /// Relevant only for Schema "properties" definitions. Declares the property as "write only".
252 | /// Therefore, it MAY be sent as part of a request but SHOULD NOT be sent as part of the response.
253 | /// If the property is marked as WriteOnly_ being true and is in the required list,
254 | /// the required will take effect on the request only.
255 | /// A property MUST NOT be marked as both ReadOnly_ and WriteOnly_ being true.
256 | /// Default value is false.
257 | ///
258 | [NeonProperty('writeOnly')]
259 | property WriteOnly_: NullBoolean read FWriteOnly_ write FWriteOnly_;
260 |
261 | ///
262 | /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
263 | /// Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema.
264 | ///
265 | [NeonInclude(IncludeIf.NotEmpty)]
266 | property AllOf: TOpenAPISchemas read FAllOf write FAllOf;
267 |
268 | ///
269 | /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
270 | /// Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema.
271 | ///
272 | [NeonInclude(IncludeIf.NotEmpty)]
273 | property OneOf: TOpenAPISchemas read FOneOf write FOneOf;
274 |
275 | ///
276 | /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
277 | /// Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema.
278 | ///
279 | [NeonInclude(IncludeIf.NotEmpty)]
280 | property AnyOf: TOpenAPISchemas read FAnyOf write FAnyOf;
281 |
282 | ///
283 | /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
284 | /// Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema.
285 | ///
286 | [NeonInclude(IncludeIf.NotNull)]
287 | [NeonProperty('not')]
288 | [NeonAutoCreate]
289 | property Not_: TOpenAPISchema read FNot_ write FNot_;
290 |
291 | ///
292 | /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
293 | ///
294 | [NeonInclude(IncludeIf.NotEmpty)]
295 | property Required: TArray read FRequired write FRequired;
296 |
297 | ///
298 | /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
299 | /// Value MUST be an object and not an array. Inline or referenced schema MUST be of a Schema Object
300 | /// and not a standard JSON Schema. items MUST be present if the type is array.
301 | ///
302 | [NeonInclude(IncludeIf.NotNull)]
303 | [NeonAutoCreate]
304 | property Items: TOpenAPISchema read FItems write FItems;
305 |
306 | ///
307 | /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
308 | ///
309 | property MaxItems: NullInteger read FMaxItems write FMaxItems;
310 |
311 | ///
312 | /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
313 | ///
314 | property MinItems: NullInteger read FMinItems write FMinItems;
315 |
316 | ///
317 | /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
318 | ///
319 | property UniqueItems: NullBoolean read FUniqueItems write FUniqueItems;
320 |
321 | ///
322 | /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
323 | /// Property definitions MUST be a Schema Object and not a standard JSON Schema (inline or referenced).
324 | ///
325 | [NeonInclude(IncludeIf.NotEmpty)]
326 | property Properties: TOpenAPISchemaMap read FProperties write FProperties;
327 |
328 | ///
329 | /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
330 | ///
331 | property MaxProperties: NullInteger read FMaxProperties write FMaxProperties;
332 |
333 | ///
334 | /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
335 | ///
336 | property MinProperties: NullInteger read FMinProperties write FMinProperties;
337 |
338 | ///
339 | /// Indicates if the schema can contain properties other than those defined by the properties map.
340 | ///
341 | property AdditionalPropertiesAllowed: NullBoolean read FAdditionalPropertiesAllowed write FAdditionalPropertiesAllowed;
342 |
343 | ///
344 | /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
345 | /// Value can be boolean or object. Inline or referenced schema
346 | /// MUST be of a Schema Object and not a standard JSON Schema.
347 | ///
348 | [NeonInclude(IncludeIf.NotNull)]
349 | [NeonAutoCreate]
350 | property AdditionalProperties: TOpenAPISchema read FAdditionalProperties write FAdditionalProperties;
351 |
352 | ///
353 | /// Adds support for polymorphism. The discriminator is an object name that is used to differentiate
354 | /// between other schemas which may satisfy the payload description.
355 | ///
356 | [NeonInclude(IncludeIf.NotEmpty)]
357 | property Discriminator: TOpenAPIDiscriminator read FDiscriminator write FDiscriminator;
358 |
359 | ///
360 | /// A free-form property to include an example of an instance for this schema.
361 | /// To represent examples that cannot be naturally represented in JSON or YAML,
362 | /// a string value can be used to contain the example with escaping where necessary.
363 | ///
364 | //property Example IOpenApiAny
365 |
366 | ///
367 | /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
368 | ///
369 | [NeonInclude(IncludeIf.NotEmpty)]
370 | //property Enum: TOpenAPIAny read FEnum write FEnum;
371 | property Enum: TOpenAPIEnum read FEnum write FEnum;
372 |
373 | ///
374 | /// Allows sending a null value for the defined schema. Default value is false.
375 | ///
376 | property Nullable: NullBoolean read FNullable write FNullable;
377 |
378 | ///
379 | /// Additional external documentation for this schema.
380 | ///
381 | //ExternalDocs: TOpenApiExternalDocs;
382 | end;
383 |
384 | implementation
385 |
386 | { TOpenAPIDiscriminator }
387 |
388 | constructor TOpenAPIDiscriminator.Create;
389 | begin
390 | FMapping := TDictionary.Create;
391 | end;
392 |
393 | destructor TOpenAPIDiscriminator.Destroy;
394 | begin
395 | FMapping.Free;
396 | inherited;
397 | end;
398 |
399 | { TOpenAPISchema }
400 |
401 | function TOpenAPISchema.AddEnum(const AValue: TValue): TOpenAPIAny;
402 | begin
403 | Result := TOpenAPIAny.Create;
404 | Result.Value := AValue;
405 | FEnum.Add(Result);
406 | end;
407 |
408 | function TOpenAPISchema.AddProperty(const AKeyName: string): TOpenAPISchema;
409 | begin
410 | if not FProperties.TryGetValue(AKeyName, Result) then
411 | begin
412 | Result := TOpenAPISchema.Create;
413 | FProperties.Add(AKeyName, Result);
414 | end;
415 | end;
416 |
417 | constructor TOpenAPISchema.Create;
418 | begin
419 | inherited Create;
420 |
421 | FAllOf := CreateSubObject;
422 | FOneOf := CreateSubObject;
423 | FAnyOf := CreateSubObject;
424 | //FNot_ := CreateSubObject;
425 | //FItems := CreateSubObject;
426 | FProperties := CreateSubObject;
427 | FDiscriminator := CreateSubObject;
428 | //FAdditionalProperties := CreateSubObject;
429 | FDefault_ := CreateSubObject;
430 | FEnum := CreateSubObject;
431 | end;
432 |
433 | destructor TOpenAPISchema.Destroy;
434 | begin
435 | // You need to destroy these in case Neon creates them
436 | FNot_.Free;
437 | FItems.Free;
438 | FAdditionalProperties.Free;
439 | if FJSONOwned then
440 | FJSONObject.Free;
441 |
442 | inherited;
443 | end;
444 |
445 | function TOpenAPISchema.GetNeonConfig: INeonConfiguration;
446 | begin
447 | if not Assigned(FNeonConfig) then
448 | FNeonConfig := TNeonConfiguration.Camel;
449 | Result := FNeonConfig;
450 | end;
451 |
452 | function TOpenAPISchema.IsEmpty: Boolean;
453 | begin
454 | Result := not Assigned(FJSONObject) and FType_.IsNull and FTitle.IsNull and FFormat.IsNull and
455 | FAllOf.IsEmpty and FAnyOf.IsEmpty and FOneOf.IsEmpty and FProperties.IsEmpty and
456 | not IsReference();
457 | end;
458 |
459 | procedure TOpenAPISchema.SetJSONObject(AJSON: TJSONObject; AOwned: Boolean);
460 | begin
461 | if Assigned(FJSONObject) and FJSONOwned then
462 | FJSONObject.Free;
463 |
464 | FJSONObject := AJSON;
465 | FJSONOwned := AOwned;
466 | end;
467 |
468 | procedure TOpenAPISchema.SetJSONFromClass(AClass: TClass);
469 | begin
470 | SetJSONObject(TNeonSchemaGenerator.ClassToJSONSchema(AClass, GetNeonConfig));
471 | end;
472 |
473 | procedure TOpenAPISchema.SetJSONFromType(AType: TRttiType);
474 | begin
475 | SetJSONObject(TNeonSchemaGenerator.TypeToJSONSchema(AType, GetNeonConfig));
476 | end;
477 |
478 | procedure TOpenAPISchema.SetSchemaReference(const AReference: string);
479 | begin
480 | Reference.Ref := '#/components/schemas/' + AReference;
481 | end;
482 |
483 | function TOpenAPISchema.WithNeonConfig(AConfig: INeonConfiguration): TOpenAPISchema;
484 | begin
485 | FNeonConfig := AConfig;
486 | Result := Self;
487 | end;
488 |
489 | end.
490 |
--------------------------------------------------------------------------------
/Source/OpenAPI.Neon.Serializers.pas:
--------------------------------------------------------------------------------
1 | {******************************************************************************}
2 | { }
3 | { Delphi OpenAPI 3.0 Generator }
4 | { Copyright (c) 2018-2023 Paolo Rossi }
5 | { https://github.com/paolo-rossi/delphi-openapi }
6 | { }
7 | {******************************************************************************}
8 | { }
9 | { Licensed under the Apache License, Version 2.0 (the 'License"); }
10 | { you may not use this file except in compliance with the License. }
11 | { You may obtain a copy of the License at }
12 | { }
13 | { http://www.apache.org/licenses/LICENSE-2.0 }
14 | { }
15 | { Unless required by applicable law or agreed to in writing, software }
16 | { distributed under the License is distributed on an "AS IS" BASIS, }
17 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
18 | { See the License for the specific language governing permissions and }
19 | { limitations under the License. }
20 | { }
21 | {******************************************************************************}
22 | unit OpenAPI.Neon.Serializers;
23 |
24 | interface
25 |
26 | uses
27 | System.SysUtils, System.Generics.Defaults, System.Rtti, System.TypInfo, System.JSON,
28 |
29 | Neon.Core.Attributes,
30 | Neon.Core.Persistence,
31 | Neon.Core.Types,
32 | Neon.Core.Nullables,
33 | Neon.Core.Serializers.RTL,
34 |
35 | OpenAPI.Model.Any,
36 | OpenAPI.Model.Base,
37 | OpenAPI.Model.Classes,
38 | OpenAPI.Model.Reference,
39 | OpenAPI.Model.Schema;
40 |
41 | type
42 | TOpenAPISerializer = class
43 | class function GetNeonConfig: INeonConfiguration; static;
44 | end;
45 |
46 | TNullableStringSerializer = class(TCustomSerializer)
47 | protected
48 | class function GetTargetInfo: PTypeInfo; override;
49 | class function CanHandle(AType: PTypeInfo): Boolean; override;
50 | public
51 | function Serialize(const AValue: TValue; ANeonObject: TNeonRttiObject; AContext: ISerializerContext): TJSONValue; override;
52 | function Deserialize(AValue: TJSONValue; const AData: TValue; ANeonObject: TNeonRttiObject; AContext: IDeserializerContext): TValue; override;
53 | end;
54 |
55 | TNullableBooleanSerializer = class(TCustomSerializer)
56 | protected
57 | class function GetTargetInfo: PTypeInfo; override;
58 | class function CanHandle(AType: PTypeInfo): Boolean; override;
59 | public
60 | function Serialize(const AValue: TValue; ANeonObject: TNeonRttiObject; AContext: ISerializerContext): TJSONValue; override;
61 | function Deserialize(AValue: TJSONValue; const AData: TValue; ANeonObject: TNeonRttiObject; AContext: IDeserializerContext): TValue; override;
62 | end;
63 |
64 | TNullableIntegerSerializer = class(TCustomSerializer)
65 | protected
66 | class function GetTargetInfo: PTypeInfo; override;
67 | class function CanHandle(AType: PTypeInfo): Boolean; override;
68 | public
69 | function Serialize(const AValue: TValue; ANeonObject: TNeonRttiObject; AContext: ISerializerContext): TJSONValue; override;
70 | function Deserialize(AValue: TJSONValue; const AData: TValue; ANeonObject: TNeonRttiObject; AContext: IDeserializerContext): TValue; override;
71 | end;
72 |
73 | TNullableInt64Serializer = class(TCustomSerializer)
74 | protected
75 | class function GetTargetInfo: PTypeInfo; override;
76 | class function CanHandle(AType: PTypeInfo): Boolean; override;
77 | public
78 | function Serialize(const AValue: TValue; ANeonObject: TNeonRttiObject; AContext: ISerializerContext): TJSONValue; override;
79 | function Deserialize(AValue: TJSONValue; const AData: TValue; ANeonObject: TNeonRttiObject; AContext: IDeserializerContext): TValue; override;
80 | end;
81 |
82 | TNullableDoubleSerializer = class(TCustomSerializer)
83 | protected
84 | class function GetTargetInfo: PTypeInfo; override;
85 | class function CanHandle(AType: PTypeInfo): Boolean; override;
86 | public
87 | function Serialize(const AValue: TValue; ANeonObject: TNeonRttiObject; AContext: ISerializerContext): TJSONValue; override;
88 | function Deserialize(AValue: TJSONValue; const AData: TValue; ANeonObject: TNeonRttiObject; AContext: IDeserializerContext): TValue; override;
89 | end;
90 |
91 | TNullableTDateTimeSerializer = class(TCustomSerializer)
92 | protected
93 | class function GetTargetInfo: PTypeInfo; override;
94 | class function CanHandle(AType: PTypeInfo): Boolean; override;
95 | public
96 | function Serialize(const AValue: TValue; ANeonObject: TNeonRttiObject; AContext: ISerializerContext): TJSONValue; override;
97 | function Deserialize(AValue: TJSONValue; const AData: TValue; ANeonObject: TNeonRttiObject; AContext: IDeserializerContext): TValue; override;
98 | end;
99 |
100 | TOpenAPIAnySerializer = class(TCustomSerializer)
101 | protected
102 | class function GetTargetInfo: PTypeInfo; override;
103 | class function CanHandle(AType: PTypeInfo): Boolean; override;
104 | public
105 | function Serialize(const AValue: TValue; ANeonObject: TNeonRttiObject; AContext: ISerializerContext): TJSONValue; override;
106 | function Deserialize(AValue: TJSONValue; const AData: TValue; ANeonObject: TNeonRttiObject; AContext: IDeserializerContext): TValue; override;
107 | end;
108 |
109 | TOpenAPIReferenceSerializer = class(TCustomSerializer)
110 | protected
111 | class function GetTargetInfo: PTypeInfo; override;
112 | class function CanHandle(AType: PTypeInfo): Boolean; override;
113 | public
114 | function Serialize(const AValue: TValue; ANeonObject: TNeonRttiObject; AContext: ISerializerContext): TJSONValue; override;
115 | function Deserialize(AValue: TJSONValue; const AData: TValue; ANeonObject: TNeonRttiObject; AContext: IDeserializerContext): TValue; override;
116 | end;
117 |
118 | TOpenAPIPathItemSerializer = class(TCustomSerializer)
119 | protected
120 | class function GetTargetInfo: PTypeInfo; override;
121 | class function CanHandle(AType: PTypeInfo): Boolean; override;
122 | public
123 | function Serialize(const AValue: TValue; ANeonObject: TNeonRttiObject; AContext: ISerializerContext): TJSONValue; override;
124 | function Deserialize(AValue: TJSONValue; const AData: TValue; ANeonObject: TNeonRttiObject; AContext: IDeserializerContext): TValue; override;
125 | end;
126 |
127 | TOpenAPIExtensionsSerializer = class(TCustomSerializer)
128 | protected
129 | class function GetTargetInfo: PTypeInfo; override;
130 | class function CanHandle(AType: PTypeInfo): Boolean; override;
131 | public
132 | function Serialize(const AValue: TValue; ANeonObject: TNeonRttiObject; AContext: ISerializerContext): TJSONValue; override;
133 | function Deserialize(AValue: TJSONValue; const AData: TValue; ANeonObject: TNeonRttiObject; AContext: IDeserializerContext): TValue; override;
134 | end;
135 |
136 | TOpenAPISchemaSerializer = class(TCustomSerializer)
137 | protected
138 | class function GetTargetInfo: PTypeInfo; override;
139 | class function CanHandle(AType: PTypeInfo): Boolean; override;
140 | public
141 | function Serialize(const AValue: TValue; ANeonObject: TNeonRttiObject; AContext: ISerializerContext): TJSONValue; override;
142 | function Deserialize(AValue: TJSONValue; const AData: TValue; ANeonObject: TNeonRttiObject; AContext: IDeserializerContext): TValue; override;
143 | end;
144 |
145 | procedure RegisterOpenAPISerializers(ARegistry: TNeonSerializerRegistry);
146 |
147 | implementation
148 |
149 | uses
150 | Neon.Core.Utils;
151 |
152 | { TNullableStringSerializer }
153 |
154 | class function TNullableStringSerializer.CanHandle(AType: PTypeInfo): Boolean;
155 | begin
156 | if AType = GetTargetInfo then
157 | Result := True
158 | else
159 | Result := False;
160 | end;
161 |
162 | function TNullableStringSerializer.Deserialize(AValue: TJSONValue; const AData:
163 | TValue; ANeonObject: TNeonRttiObject; AContext: IDeserializerContext): TValue;
164 | var
165 | LNullValue: NullString;
166 | begin
167 | LNullValue := AValue.Value;
168 | Result := TValue.From(LNullValue);
169 | end;
170 |
171 | class function TNullableStringSerializer.GetTargetInfo: PTypeInfo;
172 | begin
173 | Result := TypeInfo(NullString);
174 | end;
175 |
176 | function TNullableStringSerializer.Serialize(const AValue: TValue; ANeonObject:
177 | TNeonRttiObject; AContext: ISerializerContext): TJSONValue;
178 | var
179 | LValue: NullString;
180 | begin
181 | Result := nil;
182 | LValue := AValue.AsType;
183 | if LValue.HasValue then
184 | Result := TJSONString.Create(LValue.Value);
185 | end;
186 |
187 | { TNullableBooleanSerializer }
188 |
189 | class function TNullableBooleanSerializer.CanHandle(AType: PTypeInfo): Boolean;
190 | begin
191 | if AType = GetTargetInfo then
192 | Result := True
193 | else
194 | Result := False;
195 | end;
196 |
197 | function TNullableBooleanSerializer.Deserialize(AValue: TJSONValue; const
198 | AData: TValue; ANeonObject: TNeonRttiObject; AContext: IDeserializerContext): TValue;
199 | var
200 | LNullValue: NullBoolean;
201 | begin
202 | LNullValue := (AValue as TJSONBool).AsBoolean;
203 | Result := TValue.From(LNullValue);
204 | end;
205 |
206 | class function TNullableBooleanSerializer.GetTargetInfo: PTypeInfo;
207 | begin
208 | Result := TypeInfo(NullBoolean);
209 | end;
210 |
211 | function TNullableBooleanSerializer.Serialize(const AValue: TValue;
212 | ANeonObject: TNeonRttiObject; AContext: ISerializerContext): TJSONValue;
213 | var
214 | LValue: NullBoolean;
215 | begin
216 | Result := nil;
217 | LValue := AValue.AsType;
218 | if LValue.HasValue then
219 | Result := TJSONBool.Create(LValue.Value);
220 | end;
221 |
222 | { TNullableIntegerSerializer }
223 |
224 | class function TNullableIntegerSerializer.CanHandle(AType: PTypeInfo): Boolean;
225 | begin
226 | if AType = GetTargetInfo then
227 | Result := True
228 | else
229 | Result := False;
230 | end;
231 |
232 | function TNullableIntegerSerializer.Deserialize(AValue: TJSONValue; const
233 | AData: TValue; ANeonObject: TNeonRttiObject; AContext: IDeserializerContext): TValue;
234 | var
235 | LNullValue: NullInteger;
236 | begin
237 | LNullValue := (AValue as TJSONNumber).AsInt;
238 | Result := TValue.From(LNullValue);
239 | end;
240 |
241 | class function TNullableIntegerSerializer.GetTargetInfo: PTypeInfo;
242 | begin
243 | Result := TypeInfo(NullInteger);
244 | end;
245 |
246 | function TNullableIntegerSerializer.Serialize(const AValue: TValue;
247 | ANeonObject: TNeonRttiObject; AContext: ISerializerContext): TJSONValue;
248 | var
249 | LValue: NullInteger;
250 | begin
251 | Result := nil;
252 | LValue := AValue.AsType;
253 | if LValue.HasValue then
254 | Result := TJSONNumber.Create(LValue.Value);
255 | end;
256 |
257 | { TNullableInt64Serializer }
258 |
259 | class function TNullableInt64Serializer.CanHandle(AType: PTypeInfo): Boolean;
260 | begin
261 | if AType = GetTargetInfo then
262 | Result := True
263 | else
264 | Result := False;
265 | end;
266 |
267 | function TNullableInt64Serializer.Deserialize(AValue: TJSONValue; const AData: TValue;
268 | ANeonObject: TNeonRttiObject; AContext: IDeserializerContext): TValue;
269 | var
270 | LNullValue: NullInt64;
271 | begin
272 | LNullValue := (AValue as TJSONNumber).AsInt64;
273 | Result := TValue.From(LNullValue);
274 | end;
275 |
276 | class function TNullableInt64Serializer.GetTargetInfo: PTypeInfo;
277 | begin
278 | Result := TypeInfo(NullInt64);
279 | end;
280 |
281 | function TNullableInt64Serializer.Serialize(const AValue: TValue; ANeonObject:
282 | TNeonRttiObject; AContext: ISerializerContext): TJSONValue;
283 | var
284 | LValue: NullInt64;
285 | begin
286 | Result := nil;
287 | LValue := AValue.AsType;
288 | if LValue.HasValue then
289 | Result := TJSONNumber.Create(LValue.Value);
290 | end;
291 |
292 | { TNullableDoubleSerializer }
293 |
294 | class function TNullableDoubleSerializer.CanHandle(AType: PTypeInfo): Boolean;
295 | begin
296 | if AType = GetTargetInfo then
297 | Result := True
298 | else
299 | Result := False;
300 | end;
301 |
302 | function TNullableDoubleSerializer.Deserialize(AValue: TJSONValue; const AData: TValue;
303 | ANeonObject: TNeonRttiObject; AContext: IDeserializerContext): TValue;
304 | var
305 | LNullValue: NullDouble;
306 | begin
307 | LNullValue := (AValue as TJSONNumber).AsDouble;
308 | Result := TValue.From(LNullValue);
309 | end;
310 |
311 | class function TNullableDoubleSerializer.GetTargetInfo: PTypeInfo;
312 | begin
313 | Result := TypeInfo(NullDouble);
314 | end;
315 |
316 | function TNullableDoubleSerializer.Serialize(const AValue: TValue; ANeonObject:
317 | TNeonRttiObject; AContext: ISerializerContext): TJSONValue;
318 | var
319 | LValue: NullDouble;
320 | begin
321 | Result := nil;
322 | LValue := AValue.AsType;
323 | if LValue.HasValue then
324 | Result := TJSONNumber.Create(LValue.Value);
325 | end;
326 |
327 | { TNullableTDateTimeSerializer }
328 |
329 | class function TNullableTDateTimeSerializer.CanHandle(AType: PTypeInfo): Boolean;
330 | begin
331 | if AType = GetTargetInfo then
332 | Result := True
333 | else
334 | Result := False;
335 | end;
336 |
337 | function TNullableTDateTimeSerializer.Deserialize(AValue: TJSONValue; const AData: TValue;
338 | ANeonObject: TNeonRttiObject; AContext: IDeserializerContext): TValue;
339 | var
340 | LNullValue: NullDateTime;
341 | begin
342 | LNullValue := TJSONUtils.JSONToDateTime(AValue.Value, AContext.GetConfiguration.GetUseUTCDate);
343 | Result := TValue.From(LNullValue);
344 | end;
345 |
346 | class function TNullableTDateTimeSerializer.GetTargetInfo: PTypeInfo;
347 | begin
348 | Result := TypeInfo(NullDateTime);
349 | end;
350 |
351 | function TNullableTDateTimeSerializer.Serialize(const AValue: TValue;
352 | ANeonObject: TNeonRttiObject; AContext: ISerializerContext): TJSONValue;
353 | var
354 | LValue: NullDateTime;
355 | begin
356 | Result := nil;
357 | LValue := AValue.AsType;
358 | if LValue.HasValue then
359 | Result := TJSONString.Create(TJSONUtils.DateTimeToJSON(LValue.Value, AContext.GetConfiguration.GetUseUTCDate));
360 | end;
361 |
362 | { TOpenAPISerializer }
363 |
364 | class function TOpenAPISerializer.GetNeonConfig: INeonConfiguration;
365 | begin
366 | Result := TNeonConfiguration.Create;
367 |
368 | Result.SetMemberCase(TNeonCase.CamelCase)
369 | .SetPrettyPrint(True)
370 | .GetSerializers
371 | //Neon Serializers
372 | .RegisterSerializer(TJSONValueSerializer)
373 | //Neon Serializers
374 | .RegisterSerializer(TNullableStringSerializer)
375 | .RegisterSerializer(TNullableBooleanSerializer)
376 | .RegisterSerializer(TNullableIntegerSerializer)
377 | .RegisterSerializer(TNullableInt64Serializer)
378 | .RegisterSerializer(TNullableDoubleSerializer)
379 | .RegisterSerializer(TNullableTDateTimeSerializer)
380 | // OpenAPI Models
381 | .RegisterSerializer(TOpenAPIReferenceSerializer)
382 | .RegisterSerializer(TOpenAPISchemaSerializer)
383 | .RegisterSerializer(TOpenAPIAnySerializer)
384 | .RegisterSerializer(TOpenAPIPathItemSerializer)
385 | .RegisterSerializer(TOpenAPIExtensionsSerializer)
386 | ;
387 | end;
388 |
389 | { TOpenAPIAnySerializer }
390 |
391 | class function TOpenAPIAnySerializer.CanHandle(AType: PTypeInfo): Boolean;
392 | begin
393 | if AType = GetTargetInfo then
394 | Result := True
395 | else
396 | Result := False;
397 | end;
398 |
399 | function TOpenAPIAnySerializer.Deserialize(AValue: TJSONValue; const AData: TValue;
400 | ANeonObject: TNeonRttiObject; AContext: IDeserializerContext): TValue;
401 | var
402 | LAny: TOpenAPIAny;
403 | begin
404 | Result := AData;
405 | LAny := AData.AsObject as TOpenAPIAny;
406 |
407 | if AValue is TJSONNumber then
408 | LAny.ValueFrom((AValue as TJSONNumber).AsDouble)
409 | else if AValue is TJSONString then
410 | LAny.ValueFrom((AValue as TJSONString).Value)
411 | else if AValue is TJSONBool then
412 | LAny.ValueFrom((AValue as TJSONBool).AsBoolean);
413 | end;
414 |
415 | class function TOpenAPIAnySerializer.GetTargetInfo: PTypeInfo;
416 | begin
417 | Result := TypeInfo(TOpenAPIAny);
418 | end;
419 |
420 | function TOpenAPIAnySerializer.Serialize(const AValue: TValue;
421 | ANeonObject: TNeonRttiObject; AContext: ISerializerContext): TJSONValue;
422 | var
423 | LValue: TOpenAPIAny;
424 | begin
425 | LValue := AValue.AsType;
426 | if LValue = nil then
427 | Exit(nil);
428 |
429 | if LValue.Value.IsEmpty then
430 | Exit(nil);
431 |
432 | Result := AContext.WriteDataMember(LValue.Value);
433 | case ANeonObject.NeonInclude.Value of
434 | IncludeIf.NotEmpty, IncludeIf.NotDefault:
435 | begin
436 | if not TJSONUtils.IsNotDefault(Result) then
437 | FreeAndNil(Result);
438 | end;
439 | end;
440 | end;
441 |
442 | { TOpenAPIReferenceSerializer }
443 |
444 | class function TOpenAPIReferenceSerializer.CanHandle(AType: PTypeInfo): Boolean;
445 | begin
446 | Result := TypeInfoIs(AType);
447 | end;
448 |
449 | function TOpenAPIReferenceSerializer.Deserialize(AValue: TJSONValue; const AData: TValue;
450 | ANeonObject: TNeonRttiObject; AContext: IDeserializerContext): TValue;
451 | var
452 | LType: TRttiType;
453 | LRef: TOpenAPIModelReference;
454 | LJSON: TJSONObject;
455 | begin
456 | Result := AData;
457 | LRef := AData.AsObject as TOpenAPIModelReference;
458 | LJSON := AValue as TJSONObject;
459 |
460 | if Assigned(LJSON.Values['$ref']) then
461 | begin
462 | LType := TRttiUtils.Context.GetType(TOpenAPIReference);
463 | AContext.ReadDataMember(AValue, LType, LRef.Reference, False);
464 | end
465 | else
466 | begin
467 | LType := TRttiUtils.Context.GetType(AData.AsObject.ClassType);
468 | AContext.ReadDataMember(AValue, LType, AData, False);
469 | end;
470 | end;
471 |
472 | class function TOpenAPIReferenceSerializer.GetTargetInfo: PTypeInfo;
473 | begin
474 | Result := TOpenAPIModelReference.ClassInfo;
475 | end;
476 |
477 | function TOpenAPIReferenceSerializer.Serialize(const AValue: TValue;
478 | ANeonObject: TNeonRttiObject; AContext: ISerializerContext): TJSONValue;
479 | var
480 | LRefObj: TOpenAPIModelReference;
481 | LType: TRttiType;
482 | begin
483 | LRefObj := AValue.AsType;
484 | if LRefObj = nil then
485 | Exit(nil);
486 |
487 | if Assigned(LRefObj.Reference) and not (LRefObj.Reference.Ref.IsEmpty) then
488 | Exit(TJSONString.Create(LRefObj.Reference.Ref))
489 | else
490 | begin
491 | LType := TRttiUtils.Context.GetType(AValue.TypeInfo);
492 | Result := TJSONObject.Create;
493 | AContext.WriteMembers(LType, AValue.AsObject, Result);
494 | end;
495 |
496 | case ANeonObject.NeonInclude.Value of
497 | IncludeIf.NotEmpty, IncludeIf.NotDefault:
498 | begin
499 | if (Result as TJSONObject).Count = 0 then
500 | FreeAndNil(Result);
501 | end;
502 | end;
503 |
504 | end;
505 |
506 | { TOpenAPISchemaSerializer }
507 |
508 | class function TOpenAPISchemaSerializer.CanHandle(AType: PTypeInfo): Boolean;
509 | begin
510 | Result := TypeInfoIs(AType);
511 | end;
512 |
513 | function TOpenAPISchemaSerializer.Deserialize(AValue: TJSONValue;
514 | const AData: TValue; ANeonObject: TNeonRttiObject;
515 | AContext: IDeserializerContext): TValue;
516 | var
517 | LType: TRttiType;
518 | LSchema: TOpenAPISchema;
519 | LJSONSchema: TJSONObject;
520 | begin
521 | Result := AData;
522 |
523 | LSchema := Result.AsObject as TOpenAPISchema;
524 | LJSONSchema := AValue as TJSONObject;
525 |
526 | if Assigned(LJSONSchema.Values['$ref']) then
527 | begin
528 | LType := TRttiUtils.Context.GetType(TOpenAPIReference);
529 | AContext.ReadDataMember(AValue, LType, LSchema.Reference, False);
530 | end
531 | else
532 | begin
533 | LType := TRttiUtils.Context.GetType(TOpenAPISchema);
534 | //AContext.ReadDataMember(AValue, LType, Result, True);
535 | AContext.ReadMembers(LType, LSchema, LJSONSchema);
536 | end;
537 | end;
538 |
539 | class function TOpenAPISchemaSerializer.GetTargetInfo: PTypeInfo;
540 | begin
541 | Result := TOpenAPISchema.ClassInfo;
542 | end;
543 |
544 | function TOpenAPISchemaSerializer.Serialize(const AValue: TValue;
545 | ANeonObject: TNeonRttiObject; AContext: ISerializerContext): TJSONValue;
546 | var
547 | LSchema: TOpenAPISchema;
548 | LType: TRttiType;
549 | begin
550 | LSchema := AValue.AsType;
551 |
552 | if LSchema = nil then
553 | Exit(nil);
554 |
555 | if LSchema.IsEmpty then
556 | Exit(nil);
557 |
558 | // The Schema has a reference
559 | if LSchema.IsReference then
560 | Exit(AContext.WriteDataMember(LSchema.Reference, False));
561 |
562 | if Assigned(LSchema.JSONObject) then
563 | Result := LSchema.JSONObject.Clone as TJSONObject
564 | else
565 | begin
566 | LType := TRttiUtils.Context.GetType(AValue.TypeInfo);
567 | Result := TJSONObject.Create;
568 | AContext.WriteMembers(LType, AValue.AsObject, Result);
569 | end;
570 |
571 | case ANeonObject.NeonInclude.Value of
572 | IncludeIf.NotEmpty, IncludeIf.NotDefault:
573 | begin
574 | if (Result as TJSONObject).Count = 0 then
575 | FreeAndNil(Result);
576 | end;
577 | end;
578 | end;
579 |
580 | { TOpenAPIPathItemSerializer }
581 |
582 | class function TOpenAPIPathItemSerializer.CanHandle(AType: PTypeInfo): Boolean;
583 | begin
584 | Result := TypeInfoIs(AType);
585 | end;
586 |
587 | function TOpenAPIPathItemSerializer.Deserialize(AValue: TJSONValue;
588 | const AData: TValue; ANeonObject: TNeonRttiObject;
589 | AContext: IDeserializerContext): TValue;
590 | var
591 | LPath: TOpenAPIPathItem;
592 | LOperation: TOpenAPIOperation;
593 | LJSONPath: TJSONObject;
594 | LOpType: TOperationType;
595 | LType: TRttiType;
596 | LJSONVal: TJSONValue;
597 | begin
598 | Result := AData;
599 | LPath := AData.AsObject as TOpenAPIPathItem;
600 | LJSONPath := AValue as TJSONObject;
601 | LType := TRttiUtils.Context.GetType(TOpenAPIOperation);
602 |
603 | for LOpType := Low(TOperationType) to High(TOperationType) do
604 | begin
605 | LJSONVal := LJSONPath.Values[LOpType.ToString];
606 | if Assigned(LJSONVal) then
607 | begin
608 | LOperation := LPath.AddOperation(LOpType);
609 | AContext.ReadMembers(LType, LOperation, LJSONVal as TJSONObject);
610 | end;
611 | end;
612 | end;
613 |
614 | class function TOpenAPIPathItemSerializer.GetTargetInfo: PTypeInfo;
615 | begin
616 | Result := TOpenAPIPathItem.ClassInfo;
617 | end;
618 |
619 | function TOpenAPIPathItemSerializer.Serialize(const AValue: TValue;
620 | ANeonObject: TNeonRttiObject; AContext: ISerializerContext): TJSONValue;
621 | begin
622 | Result := AContext.WriteDataMember(AValue, False);
623 | end;
624 |
625 | { TOpenAPIExtensionsSerializer }
626 |
627 | class function TOpenAPIExtensionsSerializer.CanHandle(AType: PTypeInfo): Boolean;
628 | begin
629 | Result := TypeInfoIs(AType);
630 | end;
631 |
632 | function TOpenAPIExtensionsSerializer.Deserialize(AValue: TJSONValue;
633 | const AData: TValue; ANeonObject: TNeonRttiObject;
634 | AContext: IDeserializerContext): TValue;
635 | var
636 | LExt: TOpenAPIExtensions;
637 | LJSONValues: TJSONObject;
638 | LPair: TJSONPair;
639 | begin
640 | Result := AData;
641 | LExt := AData.AsObject as TOpenAPIExtensions;
642 | LJSONValues := AValue as TJSONObject;
643 |
644 | for LPair in LJSONValues do
645 | begin
646 | if LPair.JsonString.Value.StartsWith('x-') then
647 | LExt.Values.AddPair(LPair.Clone as TJSONPair);
648 | end;
649 | end;
650 |
651 | class function TOpenAPIExtensionsSerializer.GetTargetInfo: PTypeInfo;
652 | begin
653 | Result := TOpenAPIExtensions.ClassInfo;
654 | end;
655 |
656 | function TOpenAPIExtensionsSerializer.Serialize(const AValue: TValue;
657 | ANeonObject: TNeonRttiObject; AContext: ISerializerContext): TJSONValue;
658 | var
659 | LExt: TOpenAPIExtensions;
660 | begin
661 | LExt := AValue.AsType;
662 |
663 | if LExt = nil then
664 | Exit(nil);
665 |
666 | if LExt.Values.Count = 0 then
667 | Exit(nil);
668 |
669 | Result := AContext.WriteDataMember(LExt.Values, True);
670 | end;
671 |
672 | procedure RegisterOpenAPISerializers(ARegistry: TNeonSerializerRegistry);
673 | begin
674 | //Neon Serializers
675 | ARegistry.RegisterSerializer(TJSONValueSerializer);
676 | //ARegistry.RegisterSerializer(TTValueSerializer);
677 |
678 | //Nullable Serializers
679 | ARegistry.RegisterSerializer(TNullableStringSerializer);
680 | ARegistry.RegisterSerializer(TNullableBooleanSerializer);
681 | ARegistry.RegisterSerializer(TNullableIntegerSerializer);
682 | ARegistry.RegisterSerializer(TNullableInt64Serializer);
683 | ARegistry.RegisterSerializer(TNullableDoubleSerializer);
684 | ARegistry.RegisterSerializer(TNullableTDateTimeSerializer);
685 |
686 | //OpenAPI Serializers
687 | ARegistry.RegisterSerializer(TOpenAPIAnySerializer);
688 | ARegistry.RegisterSerializer(TOpenAPIPathItemSerializer);
689 | ARegistry.RegisterSerializer(TOpenAPIReferenceSerializer);
690 | ARegistry.RegisterSerializer(TOpenAPISchemaSerializer);
691 | ARegistry.RegisterSerializer(TOpenAPIExtensionsSerializer);
692 | end;
693 |
694 | end.
695 |
--------------------------------------------------------------------------------
/openapi-delphi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paolo-rossi/OpenAPI-Delphi/02c7fbeb4256e1606fbbc5b39e95629c59423df3/openapi-delphi.png
--------------------------------------------------------------------------------