or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

errors.mdindex.mdinterfaces.mdjwa.mdjwk.mdjws.mdutilities.md

interfaces.mddocs/

0

# JSON Serialization Interfaces

1

2

Core interfaces and base classes providing JSON serialization and deserialization functionality for all JOSE objects. These interfaces define the contract for converting Python objects to/from JSON representations with proper error handling and type safety.

3

4

## Capabilities

5

6

### JSON Serialization Interface

7

8

Base interface implemented by all JOSE objects for JSON serialization and deserialization with support for partial and full serialization modes.

9

10

```python { .api }

11

class JSONDeSerializable:

12

"""Interface for JSON serializable/deserializable objects"""

13

14

def to_partial_json(self) -> Any:

15

"""

16

Perform partial serialization to JSON-compatible objects.

17

18

Partial serialization may include other JSONDeSerializable objects

19

that need further processing for full serialization.

20

21

Returns:

22

Any: Partially serialized object (may contain JSONDeSerializable instances)

23

24

Raises:

25

josepy.errors.SerializationError: If serialization fails

26

"""

27

28

def to_json(self) -> Any:

29

"""

30

Perform full serialization to basic Python types only.

31

32

Recursively serializes all JSONDeSerializable objects to basic types

33

suitable for JSON encoding (dict, list, str, int, float, bool, None).

34

35

Returns:

36

Any: Fully serialized object containing only basic Python types

37

38

Raises:

39

josepy.errors.SerializationError: If serialization fails

40

"""

41

42

@classmethod

43

def from_json(cls, jobj: Any) -> 'JSONDeSerializable':

44

"""

45

Deserialize from JSON-compatible Python object.

46

47

Parameters:

48

- jobj: Python object from json.loads() or equivalent

49

50

Returns:

51

JSONDeSerializable: Deserialized object instance

52

53

Raises:

54

josepy.errors.DeserializationError: If deserialization fails

55

"""

56

57

@classmethod

58

def json_loads(cls, json_string: Union[str, bytes]) -> 'JSONDeSerializable':

59

"""

60

Deserialize from JSON document string.

61

62

Parameters:

63

- json_string: JSON document as string or bytes

64

65

Returns:

66

JSONDeSerializable: Deserialized object instance

67

68

Raises:

69

josepy.errors.DeserializationError: If JSON parsing or deserialization fails

70

"""

71

72

def json_dumps(self, **kwargs) -> str:

73

"""

74

Serialize to JSON document string.

75

76

Parameters:

77

- **kwargs: Additional arguments passed to json.dumps()

78

79

Returns:

80

str: JSON document string

81

"""

82

83

def json_dumps_pretty(self) -> str:

84

"""

85

Serialize to pretty-formatted JSON string.

86

87

Returns:

88

str: Pretty-formatted JSON document with indentation and sorting

89

"""

90

91

@classmethod

92

def json_dump_default(cls, python_object: 'JSONDeSerializable') -> Any:

93

"""

94

Default serializer function for json.dumps().

95

96

This method is used as the 'default' parameter for json.dumps()

97

to handle JSONDeSerializable objects.

98

99

Parameters:

100

- python_object: Object to serialize

101

102

Returns:

103

Any: Serialized representation

104

105

Raises:

106

TypeError: If object is not JSONDeSerializable

107

"""

108

```

109

110

## Usage Examples

111

112

### Basic Serialization

113

114

```python

115

from josepy import JWK, JWKRSA

116

from cryptography.hazmat.primitives.asymmetric import rsa

117

from cryptography.hazmat.backends import default_backend

118

119

# Create a JWK (which implements JSONDeSerializable)

120

private_key = rsa.generate_private_key(65537, 2048, default_backend())

121

jwk = JWKRSA(key=private_key)

122

123

# Serialize to JSON string

124

jwk_json = jwk.json_dumps()

125

print(f"JWK JSON: {jwk_json}")

126

127

# Pretty print

128

pretty_json = jwk.json_dumps_pretty()

129

print(f"Pretty JWK:\n{pretty_json}")

130

131

# Deserialize from JSON

132

loaded_jwk = JWKRSA.json_loads(jwk_json)

133

assert jwk.thumbprint() == loaded_jwk.thumbprint()

134

```

135

136

### Custom JSON Encoding

137

138

```python

139

import json

140

from josepy import JWS, Header, RS256

141

142

# Create JWS (JSONDeSerializable object)

143

payload = b'{"user": "alice", "role": "admin"}'

144

jws = JWS.sign(payload, key=jwk, alg=RS256)

145

146

# Use custom JSON encoder

147

custom_json = json.dumps(jws, default=JWS.json_dump_default, indent=2)

148

print(f"Custom encoded JWS:\n{custom_json}")

149

150

# Load back

151

loaded_jws = JWS.from_json(json.loads(custom_json))

152

```

153

154

### Partial vs Full Serialization

155

156

```python

157

# Demonstrate the difference between partial and full serialization

158

header = Header(alg=RS256, jwk=jwk.public_key())

159

160

# Partial serialization may contain JSONDeSerializable objects

161

partial = header.to_partial_json()

162

print(f"Partial serialization type of 'jwk': {type(partial.get('jwk'))}")

163

# Output: <class 'josepy.jwk.JWKRSA'>

164

165

# Full serialization contains only basic Python types

166

full = header.to_json()

167

print(f"Full serialization type of 'jwk': {type(full.get('jwk'))}")

168

# Output: <class 'dict'>

169

```

170

171

### Error Handling

172

173

```python

174

from josepy.errors import DeserializationError, SerializationError

175

176

try:

177

# Invalid JSON structure

178

invalid_jwk = JWKRSA.json_loads('{"invalid": "structure"}')

179

except DeserializationError as e:

180

print(f"Deserialization failed: {e}")

181

182

try:

183

# Malformed JSON string

184

malformed_jwk = JWKRSA.json_loads('invalid json')

185

except DeserializationError as e:

186

print(f"JSON parsing failed: {e}")

187

```

188

189

### Integration with Standard JSON Module

190

191

```python

192

import json

193

from josepy import JWK, JWKRSA, Header, RS256

194

195

# List of JOSE objects

196

jose_objects = [

197

JWKRSA(key=private_key),

198

Header(alg=RS256, kid="key-1"),

199

# ... other JOSE objects

200

]

201

202

# Serialize list of JOSE objects

203

serialized = json.dumps(

204

jose_objects,

205

default=JSONDeSerializable.json_dump_default,

206

indent=2

207

)

208

209

print(f"Serialized JOSE objects:\n{serialized}")

210

211

# The serialized JSON can be loaded back using appropriate from_json methods

212

data = json.loads(serialized)

213

# Then reconstruct objects based on their types

214

```

215

216

## Design Principles

217

218

### Serialization Modes

219

220

1. **Partial Serialization** (`to_partial_json()`):

221

- May contain other `JSONDeSerializable` objects

222

- Suitable for intermediate processing

223

- Used internally by the serialization framework

224

225

2. **Full Serialization** (`to_json()`):

226

- Contains only basic Python types

227

- Suitable for final JSON encoding

228

- Recursively processes all nested objects

229

230

### Error Handling

231

232

- **SerializationError**: Raised when objects cannot be converted to JSON-compatible format

233

- **DeserializationError**: Raised when JSON data cannot be converted back to Python objects

234

- **TypeError**: Raised by `json_dump_default()` for non-JSONDeSerializable objects

235

236

### Integration Pattern

237

238

All JOSE objects (JWK, JWS, Header, etc.) implement this interface, providing:

239

- Consistent serialization behavior across all objects

240

- Automatic handling of nested JOSE objects

241

- Proper error reporting and debugging information

242

- Integration with standard Python `json` module