maleo-metadata-client 0.1.50__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,311 @@
1
+ import json
2
+ from copy import deepcopy
3
+ from datetime import datetime, timezone
4
+ from typing import Literal, overload
5
+ from uuid import UUID
6
+ from maleo.client.maleo.config import MaleoMetadataClientConfig
7
+ from maleo.client.maleo.service import MaleoClientService
8
+ from maleo.database.enums import Connection
9
+ from maleo.database.utils import build_cache_key
10
+ from maleo.enums.cardinality import Cardinality
11
+ from maleo.enums.connection import Header
12
+ from maleo.logging.enums import Level
13
+ from maleo.metadata.constants.gender import GENDER_RESOURCE
14
+ from maleo.metadata.enums.gender import Granularity
15
+ from maleo.metadata.mixins.gender import is_id_identifier
16
+ from maleo.metadata.schemas.gender import (
17
+ ReadMultipleParameter,
18
+ ReadSingleParameter,
19
+ StandardGenderSchema,
20
+ FullGenderSchema,
21
+ )
22
+ from maleo.metadata.utils.gender import get_schema_model
23
+ from maleo.schemas.connection import ConnectionContext
24
+ from maleo.schemas.exception.factory import MaleoExceptionFactory
25
+ from maleo.schemas.operation.action.resource import ReadResourceOperationAction
26
+ from maleo.schemas.operation.enums import OperationType, Target
27
+ from maleo.schemas.operation.mixins import Timestamp
28
+ from maleo.schemas.operation.resource import (
29
+ ReadMultipleResourceOperation,
30
+ ReadSingleResourceOperation,
31
+ )
32
+ from maleo.schemas.pagination import StrictPagination
33
+ from maleo.schemas.resource import AggregateField
34
+ from maleo.schemas.response import (
35
+ MultipleDataResponse,
36
+ ReadMultipleDataResponse,
37
+ SingleDataResponse,
38
+ ReadSingleDataResponse,
39
+ )
40
+ from maleo.schemas.security.authorization import (
41
+ OptAnyAuthorization,
42
+ AnyAuthorization,
43
+ AuthorizationFactory,
44
+ )
45
+ from maleo.schemas.security.impersonation import OptImpersonation
46
+ from maleo.types.dict import OptStrToStrDict
47
+ from maleo.utils.merger import merge_dicts
48
+
49
+
50
+ class GenderClientService(MaleoClientService[MaleoMetadataClientConfig]):
51
+ resource = GENDER_RESOURCE
52
+
53
+ @overload
54
+ async def read(
55
+ self,
56
+ cardinality: Literal[Cardinality.MULTIPLE],
57
+ granularity: Literal[Granularity.STANDARD],
58
+ *,
59
+ operation_id: UUID,
60
+ connection_context: ConnectionContext,
61
+ authorization: AnyAuthorization,
62
+ impersonation: OptImpersonation = None,
63
+ parameters: ReadMultipleParameter,
64
+ headers: OptStrToStrDict = None,
65
+ ) -> ReadMultipleDataResponse[StandardGenderSchema, StrictPagination, None]: ...
66
+ @overload
67
+ async def read(
68
+ self,
69
+ cardinality: Literal[Cardinality.MULTIPLE],
70
+ granularity: Literal[Granularity.FULL],
71
+ *,
72
+ operation_id: UUID,
73
+ connection_context: ConnectionContext,
74
+ authorization: AnyAuthorization,
75
+ impersonation: OptImpersonation = None,
76
+ parameters: ReadMultipleParameter,
77
+ headers: OptStrToStrDict = None,
78
+ ) -> ReadMultipleDataResponse[FullGenderSchema, StrictPagination, None]: ...
79
+ @overload
80
+ async def read(
81
+ self,
82
+ cardinality: Literal[Cardinality.SINGLE],
83
+ granularity: Literal[Granularity.STANDARD],
84
+ *,
85
+ operation_id: UUID,
86
+ connection_context: ConnectionContext,
87
+ authorization: AnyAuthorization,
88
+ impersonation: OptImpersonation = None,
89
+ parameters: ReadSingleParameter,
90
+ headers: OptStrToStrDict = None,
91
+ ) -> ReadSingleDataResponse[StandardGenderSchema, None]: ...
92
+ @overload
93
+ async def read(
94
+ self,
95
+ cardinality: Literal[Cardinality.SINGLE],
96
+ granularity: Literal[Granularity.FULL],
97
+ *,
98
+ operation_id: UUID,
99
+ connection_context: ConnectionContext,
100
+ authorization: AnyAuthorization,
101
+ impersonation: OptImpersonation = None,
102
+ parameters: ReadSingleParameter,
103
+ headers: OptStrToStrDict = None,
104
+ ) -> ReadSingleDataResponse[FullGenderSchema, None]: ...
105
+ async def read(
106
+ self,
107
+ cardinality: Cardinality,
108
+ granularity: Granularity,
109
+ *,
110
+ operation_id: UUID,
111
+ connection_context: ConnectionContext,
112
+ authorization: OptAnyAuthorization = None,
113
+ impersonation: OptImpersonation = None,
114
+ parameters: ReadMultipleParameter | ReadSingleParameter,
115
+ headers: OptStrToStrDict = None,
116
+ ) -> (
117
+ ReadMultipleDataResponse[StandardGenderSchema, StrictPagination, None]
118
+ | ReadMultipleDataResponse[FullGenderSchema, StrictPagination, None]
119
+ | ReadSingleDataResponse[StandardGenderSchema, None]
120
+ | ReadSingleDataResponse[FullGenderSchema, None]
121
+ ):
122
+ redis_client = self._redis.manager.client.get(Connection.ASYNC)
123
+ data_model_cls = get_schema_model(granularity)
124
+
125
+ executed_at = datetime.now(tz=timezone.utc)
126
+
127
+ # Define arguments being used in this function
128
+ positional_arguments = [cardinality, granularity]
129
+ keyword_arguments = {
130
+ "authorization": (
131
+ authorization.model_dump(mode="json")
132
+ if authorization is not None
133
+ else None
134
+ ),
135
+ "parameters": parameters.model_dump(mode="json"),
136
+ }
137
+
138
+ # Define full function string
139
+ ext = f"({json.dumps(positional_arguments)}|{json.dumps(keyword_arguments)})"
140
+
141
+ # Define full cache_key
142
+ cache_key = build_cache_key(ext, namespace=self._namespace)
143
+
144
+ if parameters.use_cache:
145
+ # Initialize cache operation context
146
+ operation_context = deepcopy(self._operation_context)
147
+ operation_context.target.type = Target.CACHE
148
+
149
+ redis_response_str = await redis_client.get(cache_key)
150
+
151
+ if redis_response_str is not None:
152
+ operation_timestamp = Timestamp.completed_now(executed_at)
153
+ if cardinality is Cardinality.MULTIPLE:
154
+ response = ReadMultipleDataResponse[
155
+ data_model_cls, StrictPagination, None
156
+ ].model_validate_json(redis_response_str)
157
+ operation = ReadMultipleResourceOperation[
158
+ data_model_cls, StrictPagination, None
159
+ ](
160
+ application_context=self._application_context,
161
+ id=operation_id,
162
+ context=operation_context,
163
+ resource=self.resource,
164
+ timestamp=operation_timestamp,
165
+ summary=f"Successfully read multiple {granularity} {self.resource.aggregate(AggregateField.NAME, sep=" ").lower()} from cache",
166
+ connection_context=connection_context,
167
+ authentication=None,
168
+ authorization=authorization,
169
+ impersonation=impersonation,
170
+ response=response,
171
+ )
172
+ operation.log(self._logger, Level.INFO)
173
+ operation.publish(self._logger, self._publishers)
174
+ elif cardinality is Cardinality.SINGLE:
175
+ response = ReadSingleDataResponse[
176
+ data_model_cls, None
177
+ ].model_validate_json(redis_response_str)
178
+ operation = ReadSingleResourceOperation[data_model_cls, None](
179
+ application_context=self._application_context,
180
+ id=operation_id,
181
+ context=operation_context,
182
+ resource=self.resource,
183
+ timestamp=operation_timestamp,
184
+ summary=f"Successfully read single {granularity} {self.resource.aggregate(AggregateField.NAME, sep=" ").lower()} from cache",
185
+ connection_context=connection_context,
186
+ authentication=None,
187
+ authorization=authorization,
188
+ impersonation=impersonation,
189
+ response=response,
190
+ )
191
+ operation.log(self._logger, Level.INFO)
192
+ operation.publish(self._logger, self._publishers)
193
+
194
+ return response # type: ignore
195
+
196
+ operation_context = deepcopy(self._operation_context)
197
+ operation_context.target.type = Target.MICROSERVICE
198
+
199
+ async with self._http_client_manager.get() as http_client:
200
+ base_headers = {
201
+ Header.CONTENT_TYPE.value: "application/json",
202
+ Header.X_OPERATION_ID.value: str(operation_id),
203
+ }
204
+ if impersonation is not None:
205
+ base_headers[Header.X_USER_ID.value] = str(impersonation.user_id)
206
+ if impersonation.organization_id is not None:
207
+ base_headers[Header.X_ORGANIZATION_ID.value] = str(
208
+ impersonation.organization_id
209
+ )
210
+
211
+ if headers is not None:
212
+ headers = merge_dicts(base_headers, headers)
213
+ else:
214
+ headers = base_headers
215
+
216
+ if authorization is not None:
217
+ auth = AuthorizationFactory.httpx_auth(
218
+ scheme=authorization.scheme, authorization=authorization.credentials
219
+ )
220
+ else:
221
+ auth = None
222
+
223
+ base_url = f"{self._config.url}/v1/{self.resource.identifiers[-1].slug}/"
224
+ if isinstance(parameters, ReadMultipleParameter):
225
+ url = base_url
226
+ elif isinstance(parameters, ReadSingleParameter):
227
+ if is_id_identifier(parameters.identifier):
228
+ url = base_url + str(parameters.identifier.value)
229
+ else:
230
+ url = (
231
+ base_url
232
+ + f"{parameters.identifier.type}/{parameters.identifier.value}"
233
+ )
234
+
235
+ params = parameters.to_query_params()
236
+
237
+ response = await http_client.get(
238
+ url, params=params, headers=headers, auth=auth
239
+ )
240
+
241
+ operation_timestamp = Timestamp.completed_now(executed_at)
242
+
243
+ if response.is_error:
244
+ exc = MaleoExceptionFactory.from_httpx(
245
+ response,
246
+ operation_type=OperationType.REQUEST,
247
+ application_context=self._application_context,
248
+ operation_id=operation_id,
249
+ operation_context=operation_context,
250
+ operation_action=ReadResourceOperationAction(),
251
+ operation_timestamp=operation_timestamp,
252
+ connection_context=connection_context,
253
+ authentication=None,
254
+ authorization=authorization,
255
+ impersonation=impersonation,
256
+ logger=self._logger,
257
+ )
258
+ exc.log_and_publish_operation(self._logger, self._publishers)
259
+ raise exc
260
+
261
+ if isinstance(parameters, ReadMultipleParameter):
262
+ validated_response = MultipleDataResponse[
263
+ data_model_cls, StrictPagination, None
264
+ ].model_validate(response.json())
265
+ service_response = ReadMultipleDataResponse[
266
+ data_model_cls, StrictPagination, None
267
+ ].new(
268
+ data=validated_response.data,
269
+ pagination=validated_response.pagination,
270
+ )
271
+ operation = ReadMultipleResourceOperation[
272
+ data_model_cls, StrictPagination, None
273
+ ](
274
+ application_context=self._application_context,
275
+ id=operation_id,
276
+ context=operation_context,
277
+ resource=self.resource,
278
+ timestamp=operation_timestamp,
279
+ summary=f"Successfully read multiple {granularity} {self.resource.aggregate(AggregateField.NAME, sep=" ").lower()} from microservice",
280
+ connection_context=connection_context,
281
+ authentication=None,
282
+ authorization=authorization,
283
+ impersonation=impersonation,
284
+ response=service_response,
285
+ )
286
+ operation.log(self._logger, Level.INFO)
287
+ operation.publish(self._logger, self._publishers)
288
+ elif isinstance(parameters, ReadSingleParameter):
289
+ validated_response = SingleDataResponse[
290
+ data_model_cls, None
291
+ ].model_validate(response.json())
292
+ service_response = ReadSingleDataResponse[data_model_cls, None].new(
293
+ data=validated_response.data,
294
+ )
295
+ operation = ReadSingleResourceOperation[data_model_cls, None](
296
+ application_context=self._application_context,
297
+ id=operation_id,
298
+ context=operation_context,
299
+ resource=self.resource,
300
+ timestamp=operation_timestamp,
301
+ summary=f"Successfully read single {granularity} {self.resource.aggregate(AggregateField.NAME, sep=" ").lower()} from microservice",
302
+ connection_context=connection_context,
303
+ authentication=None,
304
+ authorization=authorization,
305
+ impersonation=impersonation,
306
+ response=service_response,
307
+ )
308
+ operation.log(self._logger, Level.INFO)
309
+ operation.publish(self._logger, self._publishers)
310
+
311
+ return service_response # type: ignore
@@ -0,0 +1,358 @@
1
+ import json
2
+ from copy import deepcopy
3
+ from datetime import datetime, timezone
4
+ from typing import Literal, overload
5
+ from uuid import UUID
6
+ from maleo.client.maleo.config import MaleoMetadataClientConfig
7
+ from maleo.client.maleo.service import MaleoClientService
8
+ from maleo.database.enums import Connection
9
+ from maleo.database.utils import build_cache_key
10
+ from maleo.enums.cardinality import Cardinality
11
+ from maleo.enums.connection import Header
12
+ from maleo.logging.enums import Level
13
+ from maleo.metadata.constants.medical_role import MEDICAL_ROLE_RESOURCE
14
+ from maleo.metadata.enums.medical_role import Granularity, IdentifierType
15
+ from maleo.metadata.schemas.medical_role import (
16
+ ReadMultipleSpecializationsParameter,
17
+ ReadMultipleParameter,
18
+ ReadSingleParameter,
19
+ StandardMedicalRoleSchema,
20
+ FullMedicalRoleSchema,
21
+ )
22
+ from maleo.metadata.utils.medical_role import get_schema_model
23
+ from maleo.schemas.connection import ConnectionContext
24
+ from maleo.schemas.exception.factory import MaleoExceptionFactory
25
+ from maleo.schemas.operation.action.resource import ReadResourceOperationAction
26
+ from maleo.schemas.operation.enums import OperationType, Target
27
+ from maleo.schemas.operation.mixins import Timestamp
28
+ from maleo.schemas.operation.resource import (
29
+ ReadMultipleResourceOperation,
30
+ ReadSingleResourceOperation,
31
+ )
32
+ from maleo.schemas.pagination import StrictPagination
33
+ from maleo.schemas.resource import AggregateField
34
+ from maleo.schemas.response import (
35
+ MultipleDataResponse,
36
+ ReadMultipleDataResponse,
37
+ SingleDataResponse,
38
+ ReadSingleDataResponse,
39
+ )
40
+ from maleo.schemas.security.authorization import (
41
+ OptAnyAuthorization,
42
+ AnyAuthorization,
43
+ AuthorizationFactory,
44
+ )
45
+ from maleo.schemas.security.impersonation import OptImpersonation
46
+ from maleo.types.dict import OptStrToStrDict
47
+ from maleo.types.integer import OptInt
48
+ from maleo.utils.merger import merge_dicts
49
+
50
+
51
+ class MedicalRoleClientService(MaleoClientService[MaleoMetadataClientConfig]):
52
+ resource = MEDICAL_ROLE_RESOURCE
53
+
54
+ @overload
55
+ async def read(
56
+ self,
57
+ cardinality: Literal[Cardinality.MULTIPLE],
58
+ granularity: Literal[Granularity.STANDARD],
59
+ *,
60
+ parent_id: int,
61
+ operation_id: UUID,
62
+ connection_context: ConnectionContext,
63
+ authorization: AnyAuthorization,
64
+ impersonation: OptImpersonation = None,
65
+ parameters: ReadMultipleSpecializationsParameter,
66
+ headers: OptStrToStrDict = None,
67
+ ) -> ReadMultipleDataResponse[
68
+ StandardMedicalRoleSchema, StrictPagination, None
69
+ ]: ...
70
+ @overload
71
+ async def read(
72
+ self,
73
+ cardinality: Literal[Cardinality.MULTIPLE],
74
+ granularity: Literal[Granularity.FULL],
75
+ *,
76
+ parent_id: int,
77
+ operation_id: UUID,
78
+ connection_context: ConnectionContext,
79
+ authorization: AnyAuthorization,
80
+ impersonation: OptImpersonation = None,
81
+ parameters: ReadMultipleSpecializationsParameter,
82
+ headers: OptStrToStrDict = None,
83
+ ) -> ReadMultipleDataResponse[FullMedicalRoleSchema, StrictPagination, None]: ...
84
+ @overload
85
+ async def read(
86
+ self,
87
+ cardinality: Literal[Cardinality.MULTIPLE],
88
+ granularity: Literal[Granularity.STANDARD],
89
+ *,
90
+ operation_id: UUID,
91
+ connection_context: ConnectionContext,
92
+ authorization: AnyAuthorization,
93
+ impersonation: OptImpersonation = None,
94
+ parameters: ReadMultipleParameter,
95
+ headers: OptStrToStrDict = None,
96
+ ) -> ReadMultipleDataResponse[
97
+ StandardMedicalRoleSchema, StrictPagination, None
98
+ ]: ...
99
+ @overload
100
+ async def read(
101
+ self,
102
+ cardinality: Literal[Cardinality.MULTIPLE],
103
+ granularity: Literal[Granularity.FULL],
104
+ *,
105
+ operation_id: UUID,
106
+ connection_context: ConnectionContext,
107
+ authorization: AnyAuthorization,
108
+ impersonation: OptImpersonation = None,
109
+ parameters: ReadMultipleParameter,
110
+ headers: OptStrToStrDict = None,
111
+ ) -> ReadMultipleDataResponse[FullMedicalRoleSchema, StrictPagination, None]: ...
112
+ @overload
113
+ async def read(
114
+ self,
115
+ cardinality: Literal[Cardinality.SINGLE],
116
+ granularity: Literal[Granularity.STANDARD],
117
+ *,
118
+ operation_id: UUID,
119
+ connection_context: ConnectionContext,
120
+ authorization: AnyAuthorization,
121
+ impersonation: OptImpersonation = None,
122
+ parameters: ReadSingleParameter,
123
+ headers: OptStrToStrDict = None,
124
+ ) -> ReadSingleDataResponse[StandardMedicalRoleSchema, None]: ...
125
+ @overload
126
+ async def read(
127
+ self,
128
+ cardinality: Literal[Cardinality.SINGLE],
129
+ granularity: Literal[Granularity.FULL],
130
+ *,
131
+ operation_id: UUID,
132
+ connection_context: ConnectionContext,
133
+ authorization: AnyAuthorization,
134
+ impersonation: OptImpersonation = None,
135
+ parameters: ReadSingleParameter,
136
+ headers: OptStrToStrDict = None,
137
+ ) -> ReadSingleDataResponse[FullMedicalRoleSchema, None]: ...
138
+ async def read(
139
+ self,
140
+ cardinality: Cardinality,
141
+ granularity: Granularity,
142
+ *,
143
+ parent_id: OptInt = None,
144
+ operation_id: UUID,
145
+ connection_context: ConnectionContext,
146
+ authorization: OptAnyAuthorization = None,
147
+ impersonation: OptImpersonation = None,
148
+ parameters: (
149
+ ReadMultipleSpecializationsParameter
150
+ | ReadMultipleParameter
151
+ | ReadSingleParameter
152
+ ),
153
+ headers: OptStrToStrDict = None,
154
+ ) -> (
155
+ ReadMultipleDataResponse[StandardMedicalRoleSchema, StrictPagination, None]
156
+ | ReadMultipleDataResponse[FullMedicalRoleSchema, StrictPagination, None]
157
+ | ReadSingleDataResponse[StandardMedicalRoleSchema, None]
158
+ | ReadSingleDataResponse[FullMedicalRoleSchema, None]
159
+ ):
160
+ redis_client = self._redis.manager.client.get(Connection.ASYNC)
161
+ data_model_cls = get_schema_model(granularity)
162
+
163
+ executed_at = datetime.now(tz=timezone.utc)
164
+
165
+ # Define arguments being used in this function
166
+ positional_arguments = [cardinality, granularity]
167
+ keyword_arguments = {
168
+ "authorization": (
169
+ authorization.model_dump(mode="json")
170
+ if authorization is not None
171
+ else None
172
+ ),
173
+ "parameters": parameters.model_dump(mode="json"),
174
+ }
175
+
176
+ # Define full function string
177
+ ext = f"({json.dumps(positional_arguments)}|{json.dumps(keyword_arguments)})"
178
+
179
+ # Define full cache_key
180
+ cache_key = build_cache_key(ext, namespace=self._namespace)
181
+
182
+ if parameters.use_cache:
183
+ # Initialize cache operation context
184
+ operation_context = deepcopy(self._operation_context)
185
+ operation_context.target.type = Target.CACHE
186
+
187
+ redis_response_str = await redis_client.get(cache_key)
188
+
189
+ if redis_response_str is not None:
190
+ operation_timestamp = Timestamp.completed_now(executed_at)
191
+ if cardinality is Cardinality.MULTIPLE:
192
+ response = ReadMultipleDataResponse[
193
+ data_model_cls, StrictPagination, None
194
+ ].model_validate_json(redis_response_str)
195
+ operation = ReadMultipleResourceOperation[
196
+ data_model_cls, StrictPagination, None
197
+ ](
198
+ application_context=self._application_context,
199
+ id=operation_id,
200
+ context=operation_context,
201
+ resource=self.resource,
202
+ timestamp=operation_timestamp,
203
+ summary=f"Successfully read multiple {granularity} {self.resource.aggregate(AggregateField.NAME, sep=" ").lower()} from cache",
204
+ connection_context=connection_context,
205
+ authentication=None,
206
+ authorization=authorization,
207
+ impersonation=impersonation,
208
+ response=response,
209
+ )
210
+ operation.log(self._logger, Level.INFO)
211
+ operation.publish(self._logger, self._publishers)
212
+ elif cardinality is Cardinality.SINGLE:
213
+ response = ReadSingleDataResponse[
214
+ data_model_cls, None
215
+ ].model_validate_json(redis_response_str)
216
+ operation = ReadSingleResourceOperation[data_model_cls, None](
217
+ application_context=self._application_context,
218
+ id=operation_id,
219
+ context=operation_context,
220
+ resource=self.resource,
221
+ timestamp=operation_timestamp,
222
+ summary=f"Successfully read single {granularity} {self.resource.aggregate(AggregateField.NAME, sep=" ").lower()} from cache",
223
+ connection_context=connection_context,
224
+ authentication=None,
225
+ authorization=authorization,
226
+ impersonation=impersonation,
227
+ response=response,
228
+ )
229
+ operation.log(self._logger, Level.INFO)
230
+ operation.publish(self._logger, self._publishers)
231
+
232
+ return response # type: ignore
233
+
234
+ operation_context = deepcopy(self._operation_context)
235
+ operation_context.target.type = Target.MICROSERVICE
236
+
237
+ async with self._http_client_manager.get() as http_client:
238
+ base_headers = {
239
+ Header.CONTENT_TYPE.value: "application/json",
240
+ Header.X_OPERATION_ID.value: str(operation_id),
241
+ }
242
+ if impersonation is not None:
243
+ base_headers[Header.X_USER_ID.value] = str(impersonation.user_id)
244
+ if impersonation.organization_id is not None:
245
+ base_headers[Header.X_ORGANIZATION_ID.value] = str(
246
+ impersonation.organization_id
247
+ )
248
+
249
+ if headers is not None:
250
+ headers = merge_dicts(base_headers, headers)
251
+ else:
252
+ headers = base_headers
253
+
254
+ if authorization is not None:
255
+ auth = AuthorizationFactory.httpx_auth(
256
+ scheme=authorization.scheme, authorization=authorization.credentials
257
+ )
258
+ else:
259
+ auth = None
260
+
261
+ base_url = f"{self._config.url}/v1/{self.resource.identifiers[-1].slug}/"
262
+ if isinstance(parameters, ReadMultipleSpecializationsParameter):
263
+ if parent_id is None:
264
+ raise ValueError(
265
+ f"Parent ID can not be None to read {self.resource.aggregate(AggregateField.NAME, sep=" ").lower()} specializations"
266
+ )
267
+ url = base_url + f"{parent_id}/specializations"
268
+ elif isinstance(parameters, ReadMultipleParameter):
269
+ url = base_url
270
+ elif isinstance(parameters, ReadSingleParameter):
271
+ if parameters.identifier.type is IdentifierType.ID:
272
+ url = base_url + str(parameters.identifier.value)
273
+ else:
274
+ url = (
275
+ base_url
276
+ + f"{parameters.identifier.type}/{parameters.identifier.value}"
277
+ )
278
+
279
+ params = parameters.to_query_params()
280
+
281
+ response = await http_client.get(
282
+ url, params=params, headers=headers, auth=auth
283
+ )
284
+
285
+ operation_timestamp = Timestamp.completed_now(executed_at)
286
+
287
+ if response.is_error:
288
+ exc = MaleoExceptionFactory.from_httpx(
289
+ response,
290
+ operation_type=OperationType.REQUEST,
291
+ application_context=self._application_context,
292
+ operation_id=operation_id,
293
+ operation_context=operation_context,
294
+ operation_action=ReadResourceOperationAction(),
295
+ operation_timestamp=operation_timestamp,
296
+ connection_context=connection_context,
297
+ authentication=None,
298
+ authorization=authorization,
299
+ impersonation=impersonation,
300
+ logger=self._logger,
301
+ )
302
+ exc.log_and_publish_operation(self._logger, self._publishers)
303
+ raise exc
304
+
305
+ if isinstance(
306
+ parameters,
307
+ (ReadMultipleSpecializationsParameter, ReadMultipleParameter),
308
+ ):
309
+ validated_response = MultipleDataResponse[
310
+ data_model_cls, StrictPagination, None
311
+ ].model_validate(response.json())
312
+ service_response = ReadMultipleDataResponse[
313
+ data_model_cls, StrictPagination, None
314
+ ].new(
315
+ data=validated_response.data,
316
+ pagination=validated_response.pagination,
317
+ )
318
+ operation = ReadMultipleResourceOperation[
319
+ data_model_cls, StrictPagination, None
320
+ ](
321
+ application_context=self._application_context,
322
+ id=operation_id,
323
+ context=operation_context,
324
+ resource=self.resource,
325
+ timestamp=operation_timestamp,
326
+ summary=f"Successfully read multiple {granularity} {self.resource.aggregate(AggregateField.NAME, sep=" ").lower()} from microservice",
327
+ connection_context=connection_context,
328
+ authentication=None,
329
+ authorization=authorization,
330
+ impersonation=impersonation,
331
+ response=service_response,
332
+ )
333
+ operation.log(self._logger, Level.INFO)
334
+ operation.publish(self._logger, self._publishers)
335
+ elif isinstance(parameters, ReadSingleParameter):
336
+ validated_response = SingleDataResponse[
337
+ data_model_cls, None
338
+ ].model_validate(response.json())
339
+ service_response = ReadSingleDataResponse[data_model_cls, None].new(
340
+ data=validated_response.data,
341
+ )
342
+ operation = ReadSingleResourceOperation[data_model_cls, None](
343
+ application_context=self._application_context,
344
+ id=operation_id,
345
+ context=operation_context,
346
+ resource=self.resource,
347
+ timestamp=operation_timestamp,
348
+ summary=f"Successfully read single {granularity} {self.resource.aggregate(AggregateField.NAME, sep=" ").lower()} from microservice",
349
+ connection_context=connection_context,
350
+ authentication=None,
351
+ authorization=authorization,
352
+ impersonation=impersonation,
353
+ response=service_response,
354
+ )
355
+ operation.log(self._logger, Level.INFO)
356
+ operation.publish(self._logger, self._publishers)
357
+
358
+ return service_response # type: ignore