Skip to content

Commit 7152da5

Browse files
πŸ“ Update documentation on implemented OpenAPI and JSON Schema features.
1 parent d6308ad commit 7152da5

File tree

2 files changed

+80
-19
lines changed

2 files changed

+80
-19
lines changed

β€Ždocs/json-schema.mdβ€Ž

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ Simplified, JSON Schemas can be transformed to python model with the following f
3232

3333
dict | list | float | int | str | bool
3434

35+
2. pydantic provides type `JsonValue` type that reflects the type of any JSON data, except it also includes None for compatibility with JSON Schema.
36+
3537

3638
## Type-specific constraints
3739

@@ -86,7 +88,8 @@ That means most constraints can be processed separately, which is useful when th
8688

8789
1. If `enum` is in `anyOf` sub-schemas, the values are summed as sets.
8890

89-
1. If `enum` is in `oneOf` sub-schemas, only the values that occur once can be validated.
91+
1. If `enum` is in `oneOf` sub-schemas, only the values that occur once can be validated
92+
(not implemented, since Lapidary treats as just another anyOf).
9093

9194

9295
## `enum` as `Literal`
@@ -199,8 +202,8 @@ The problem with this solution is that the name changes when keys or any value c
199202
=>
200203
201204
Union[
202-
Annotated[int, Field(ge=10)],
203-
Annotated[int, Field(le=20)],
205+
Annotated[int, Field(le=10)],
206+
Annotated[int, Field(ge=20)],
204207
]
205208
206209
1. The above is different than this, which is a bottom type (no object can validate against it, since no number can be greater than 20 _and_ smaller than 10):
@@ -905,6 +908,67 @@ class Alice:
905908
prop1: Annotated[int, Le(20)]
906909
```
907910

911+
# Generic types
912+
913+
1. JSON Schema only supports generic arrays and maps:
914+
915+
```yaml
916+
sequence:
917+
type: array
918+
items:
919+
type: string
920+
map:
921+
type: object
922+
additionalProperties:
923+
type: number
924+
```
925+
926+
=>
927+
928+
```python
929+
sequence: list[str]
930+
map: dict[float]
931+
```
932+
933+
There's no way of directly representing a generic python class:
934+
935+
```python
936+
class Envelope[T]:
937+
id: uuid.UUID
938+
payload: T
939+
940+
941+
class Customer:
942+
...
943+
944+
945+
data: Envelope[Customer]
946+
```
947+
948+
can only be represented as concretised schemas:
949+
950+
```yaml
951+
952+
Customer:
953+
type: object
954+
955+
Envelope:
956+
type: object
957+
properties:
958+
id:
959+
type: string
960+
format: uuid
961+
payload:
962+
type: object
963+
964+
CustomerEnvelope:
965+
allOf:
966+
- $ref: '#/schemas/Envelope'
967+
- properties:
968+
payload:
969+
$ref: '#/schemas/Customer'
970+
```
971+
908972
# References
909973

910974
1. https://apis.guru/ - a directory of OpenAPI/swagger descriptions.

β€Ždocs/openapi.mdβ€Ž

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,29 +16,29 @@ OpenAPI compatibility
1616
- βœ… `schemas`:
1717
- πŸ—“οΈ `title`: planned as part of class docstr
1818
- `type`
19-
- πŸ—“οΈ [no value]: planned as primitive JSON-compatible object.
20-
- βœ… `object`: implemented as pydantic models
19+
- βœ… [no value]: implemented as `pydantic.JsonValue`
20+
- ⚠️ caveat: it which includes `None`
21+
- βœ… `object`: implemented as pydantic model
2122
- βœ… `array`: implemented as list
2223
- βœ… `string`, `integer`, `number`, `boolean`: implemented as `str`, `int`, `float` and `bool`
23-
- πŸ—“οΈ `format`: planned, including custom formats
24-
- βœ… assertion keywords: as supported by pydantic
25-
- ⚠️ `allOf`: needs improvement
24+
- ⚠️ `format`: Implemented for string types: `uuid`, `date`, `date-time`, `time` and `decimal`
25+
- βœ… assertion keywords: as supported by [annotated-types](https://github.com/annotated-types/annotated-types)
26+
- βœ… `allOf`: implemented
2627
- βœ… `anyOf`: implemented as union
2728
- ⚠️ `oneOf`: treated as `anyOf` and implemented as `Union`
28-
- πŸ—“οΈ `not`: planned for objects
29+
- πŸ—“οΈ `not`: planned
2930
- βœ… `required`: non-required properties are turned to `Union[None, $type]`
3031
- `additionalProperties`:
31-
- βœ… boolean: supported as pydantic `extra: 'allow'` or `'forbid'`
32-
- πŸ—“οΈ schema: planned as a `Mapping` field
33-
- πŸ—“οΈ `patternProperties`: planned as `Mapping` field
32+
- βœ… boolean: supported as pydantic `extra: 'allow'` or `'forbid'`
33+
- πŸ—“οΈ schema: planned as either a `Mapping` type or a `__pydantic_extra__` field
3434
- πŸ” `enum`: ignored; might be implemented for simple types as `Literal`
3535
- πŸ“„ `description`: planned as part of docstr
3636
- βœ… `default`: if present, the property type turned to `Union[None, $type]` and has default value `None`
37-
- πŸ” caveat: default values are not to be sent between Web API client and server, instead they are implied by the receiving side. Lapidary could potentially implement generating default values for some cases but they don't necessary need to validate against the schema.
37+
- πŸ” caveat: default values are not to be sent between Web API client and server, instead they are implied by the receiving side. Lapidary could potentially implement generating default values for some cases but they don't necessary need to validate against the schema.
3838
- βœ… `nullable`: if true, the property type is turned to `Union[None, $type]`
3939
- βœ… `readOnly` & `writeOnly`: if either is true, the property type is turned to `Union[None, $type]` and has default value `None`; planned as part of docstr
4040
- ⚠️ caveat: readOnly properties are only to be sent to API server, and writeOnly only to be received by the client. A property might be both required one way, and invalid the other way, which could not be directly represented in Python, except with two or three classes for every schema.
41-
- ❌ `discriminator`: ignored
41+
- πŸ“„ `discriminator`: planed for use with pydantic discriminated unions
4242
- πŸ” `example`: might be used as part of docstr
4343
- πŸ—“οΈ `externalDocs`: planned as part of docstr
4444
- πŸ—“οΈ `deprecated`: planned
@@ -58,7 +58,7 @@ OpenAPI compatibility
5858
- ⚠️ `securitySchemes`: implemented with httpx_auth
5959
- ❌ `refreshUrl`: not supported
6060
- πŸ—“οΈ `links`: planned
61-
- ❌ `callbacks`: not planned
61+
- πŸ—“οΈ `callbacks`: only planning to generate models from referenced schemas
6262
- `paths`: πŸ—“οΈ planned as keys in a TypedDict
6363
- operations: βœ… mapped to operation methods
6464
- `operationId`: βœ… used as method name
@@ -74,7 +74,4 @@ OpenAPI compatibility
7474
- ⚠️ `style`: partially implemented
7575
- πŸ—“οΈ `allowReserved`: planned
7676
- βœ… `schema`: implemented
77-
- πŸ” `example` & examples: considered
78-
- πŸ”§ `x-lapidary-name`: name of a parameter in the python
79-
- πŸ”§ `x-lapidary-responses-global`: responses that might come from any operation
80-
- πŸ”§ `x-lapidary-headers-global`: headers accepted by any operation
77+
- πŸ” `example` & `examples`: considered

0 commit comments

Comments
Β (0)