adyd-detector-api 0.1.0__tar.gz
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.
- adyd_detector_api-0.1.0/PKG-INFO +35 -0
- adyd_detector_api-0.1.0/README.md +17 -0
- adyd_detector_api-0.1.0/adyd_detector_api/controllers/file_controller_controller.py +20 -0
- adyd_detector_api-0.1.0/adyd_detector_api/models/bucket_file_list_dto.py +97 -0
- adyd_detector_api-0.1.0/adyd_detector_api/models/file_info_storage_dto.py +155 -0
- adyd_detector_api-0.1.0/adyd_detector_api/openapi.yaml +100 -0
- adyd_detector_api-0.1.0/adyd_detector_api/test/test_file_controller_controller.py +29 -0
- adyd_detector_api-0.1.0/pyproject.toml +26 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: adyd-detector-api
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: API para ADYD Detector
|
|
5
|
+
Author: JacoboGeadaAnsino
|
|
6
|
+
Author-email: jacobo.geada.ansino@gmail.com
|
|
7
|
+
Requires-Python: >=3.12,<4.0
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
12
|
+
Requires-Dist: connexion[flask] (>=3.0.0)
|
|
13
|
+
Requires-Dist: flask (>=3.0.0)
|
|
14
|
+
Requires-Dist: pydantic (>=2.0,<3.0)
|
|
15
|
+
Requires-Dist: python-dateutil (>=2.8.2)
|
|
16
|
+
Project-URL: Repository, https://github.com/gilmith/adyd_detector_api
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
Lo que hace con poe es tener casi un maven o u npm para ejecutar pasos y generar codigo.
|
|
20
|
+
|
|
21
|
+
Define las dependencias de los proyectos haciendo un add library
|
|
22
|
+
|
|
23
|
+
Y con poe puede ejecutar task, en este caos la de openapi es de java o de node pero la puede ejecutar
|
|
24
|
+
|
|
25
|
+
el pyproject.toml es el equivalente al package.json de node para generar las dependencias del proyecto.
|
|
26
|
+
|
|
27
|
+
Para compilar poetry build
|
|
28
|
+
|
|
29
|
+
publicar en github packages
|
|
30
|
+
|
|
31
|
+
poetry config repositories.github https://pypi.pkg.github.com/<ORGANIZACION>/adyd-contracts
|
|
32
|
+
|
|
33
|
+
poetry config http-basic.github <TU_USUARIO_GITHUB> <TU_TOKEN_PAT>
|
|
34
|
+
|
|
35
|
+
poetry publish --build -r github
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Lo que hace con poe es tener casi un maven o u npm para ejecutar pasos y generar codigo.
|
|
2
|
+
|
|
3
|
+
Define las dependencias de los proyectos haciendo un add library
|
|
4
|
+
|
|
5
|
+
Y con poe puede ejecutar task, en este caos la de openapi es de java o de node pero la puede ejecutar
|
|
6
|
+
|
|
7
|
+
el pyproject.toml es el equivalente al package.json de node para generar las dependencias del proyecto.
|
|
8
|
+
|
|
9
|
+
Para compilar poetry build
|
|
10
|
+
|
|
11
|
+
publicar en github packages
|
|
12
|
+
|
|
13
|
+
poetry config repositories.github https://pypi.pkg.github.com/<ORGANIZACION>/adyd-contracts
|
|
14
|
+
|
|
15
|
+
poetry config http-basic.github <TU_USUARIO_GITHUB> <TU_TOKEN_PAT>
|
|
16
|
+
|
|
17
|
+
poetry publish --build -r github
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import connexion
|
|
2
|
+
from typing import Dict
|
|
3
|
+
from typing import Tuple
|
|
4
|
+
from typing import Union
|
|
5
|
+
|
|
6
|
+
from adyd_detector_api.models.bucket_file_list_dto import BucketFileListDto # noqa: E501
|
|
7
|
+
from adyd_detector_api import util
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def list_monster_files(bucket_name): # noqa: E501
|
|
11
|
+
"""list_monster_files
|
|
12
|
+
|
|
13
|
+
# noqa: E501
|
|
14
|
+
|
|
15
|
+
:param bucket_name:
|
|
16
|
+
:type bucket_name: str
|
|
17
|
+
|
|
18
|
+
:rtype: Union[BucketFileListDto, Tuple[BucketFileListDto, int], Tuple[BucketFileListDto, int, Dict[str, str]]
|
|
19
|
+
"""
|
|
20
|
+
return 'do some magic!'
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
from datetime import date, datetime # noqa: F401
|
|
2
|
+
|
|
3
|
+
from typing import List, Dict # noqa: F401
|
|
4
|
+
|
|
5
|
+
from adyd_detector_api.models.base_model import Model
|
|
6
|
+
from adyd_detector_api.models.file_info_storage_dto import FileInfoStorageDto
|
|
7
|
+
from adyd_detector_api import util
|
|
8
|
+
|
|
9
|
+
from adyd_detector_api.models.file_info_storage_dto import FileInfoStorageDto # noqa: E501
|
|
10
|
+
|
|
11
|
+
class BucketFileListDto(Model):
|
|
12
|
+
"""NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
|
13
|
+
|
|
14
|
+
Do not edit the class manually.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, bucket=None, files_info=None): # noqa: E501
|
|
18
|
+
"""BucketFileListDto - a model defined in OpenAPI
|
|
19
|
+
|
|
20
|
+
:param bucket: The bucket of this BucketFileListDto. # noqa: E501
|
|
21
|
+
:type bucket: str
|
|
22
|
+
:param files_info: The files_info of this BucketFileListDto. # noqa: E501
|
|
23
|
+
:type files_info: List[FileInfoStorageDto]
|
|
24
|
+
"""
|
|
25
|
+
self.openapi_types = {
|
|
26
|
+
'bucket': str,
|
|
27
|
+
'files_info': List[FileInfoStorageDto]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
self.attribute_map = {
|
|
31
|
+
'bucket': 'bucket',
|
|
32
|
+
'files_info': 'files_info'
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
self._bucket = bucket
|
|
36
|
+
self._files_info = files_info
|
|
37
|
+
|
|
38
|
+
@classmethod
|
|
39
|
+
def from_dict(cls, dikt) -> 'BucketFileListDto':
|
|
40
|
+
"""Returns the dict as a model
|
|
41
|
+
|
|
42
|
+
:param dikt: A dict.
|
|
43
|
+
:type: dict
|
|
44
|
+
:return: The BucketFileListDto of this BucketFileListDto. # noqa: E501
|
|
45
|
+
:rtype: BucketFileListDto
|
|
46
|
+
"""
|
|
47
|
+
return util.deserialize_model(dikt, cls)
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def bucket(self) -> str:
|
|
51
|
+
"""Gets the bucket of this BucketFileListDto.
|
|
52
|
+
|
|
53
|
+
# noqa: E501
|
|
54
|
+
|
|
55
|
+
:return: The bucket of this BucketFileListDto.
|
|
56
|
+
:rtype: str
|
|
57
|
+
"""
|
|
58
|
+
return self._bucket
|
|
59
|
+
|
|
60
|
+
@bucket.setter
|
|
61
|
+
def bucket(self, bucket: str):
|
|
62
|
+
"""Sets the bucket of this BucketFileListDto.
|
|
63
|
+
|
|
64
|
+
# noqa: E501
|
|
65
|
+
|
|
66
|
+
:param bucket: The bucket of this BucketFileListDto.
|
|
67
|
+
:type bucket: str
|
|
68
|
+
"""
|
|
69
|
+
if bucket is None:
|
|
70
|
+
raise ValueError("Invalid value for `bucket`, must not be `None`") # noqa: E501
|
|
71
|
+
|
|
72
|
+
self._bucket = bucket
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def files_info(self) -> List[FileInfoStorageDto]:
|
|
76
|
+
"""Gets the files_info of this BucketFileListDto.
|
|
77
|
+
|
|
78
|
+
# noqa: E501
|
|
79
|
+
|
|
80
|
+
:return: The files_info of this BucketFileListDto.
|
|
81
|
+
:rtype: List[FileInfoStorageDto]
|
|
82
|
+
"""
|
|
83
|
+
return self._files_info
|
|
84
|
+
|
|
85
|
+
@files_info.setter
|
|
86
|
+
def files_info(self, files_info: List[FileInfoStorageDto]):
|
|
87
|
+
"""Sets the files_info of this BucketFileListDto.
|
|
88
|
+
|
|
89
|
+
# noqa: E501
|
|
90
|
+
|
|
91
|
+
:param files_info: The files_info of this BucketFileListDto.
|
|
92
|
+
:type files_info: List[FileInfoStorageDto]
|
|
93
|
+
"""
|
|
94
|
+
if files_info is None:
|
|
95
|
+
raise ValueError("Invalid value for `files_info`, must not be `None`") # noqa: E501
|
|
96
|
+
|
|
97
|
+
self._files_info = files_info
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
from datetime import date, datetime # noqa: F401
|
|
2
|
+
|
|
3
|
+
from typing import List, Dict # noqa: F401
|
|
4
|
+
|
|
5
|
+
from adyd_detector_api.models.base_model import Model
|
|
6
|
+
from adyd_detector_api import util
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class FileInfoStorageDto(Model):
|
|
10
|
+
"""NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
|
11
|
+
|
|
12
|
+
Do not edit the class manually.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(self, file_name=None, file_size=None, unit=None, content_type=None): # noqa: E501
|
|
16
|
+
"""FileInfoStorageDto - a model defined in OpenAPI
|
|
17
|
+
|
|
18
|
+
:param file_name: The file_name of this FileInfoStorageDto. # noqa: E501
|
|
19
|
+
:type file_name: str
|
|
20
|
+
:param file_size: The file_size of this FileInfoStorageDto. # noqa: E501
|
|
21
|
+
:type file_size: int
|
|
22
|
+
:param unit: The unit of this FileInfoStorageDto. # noqa: E501
|
|
23
|
+
:type unit: str
|
|
24
|
+
:param content_type: The content_type of this FileInfoStorageDto. # noqa: E501
|
|
25
|
+
:type content_type: str
|
|
26
|
+
"""
|
|
27
|
+
self.openapi_types = {
|
|
28
|
+
'file_name': str,
|
|
29
|
+
'file_size': int,
|
|
30
|
+
'unit': str,
|
|
31
|
+
'content_type': str
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
self.attribute_map = {
|
|
35
|
+
'file_name': 'file_name',
|
|
36
|
+
'file_size': 'file_size',
|
|
37
|
+
'unit': 'unit',
|
|
38
|
+
'content_type': 'content_type'
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
self._file_name = file_name
|
|
42
|
+
self._file_size = file_size
|
|
43
|
+
self._unit = unit
|
|
44
|
+
self._content_type = content_type
|
|
45
|
+
|
|
46
|
+
@classmethod
|
|
47
|
+
def from_dict(cls, dikt) -> 'FileInfoStorageDto':
|
|
48
|
+
"""Returns the dict as a model
|
|
49
|
+
|
|
50
|
+
:param dikt: A dict.
|
|
51
|
+
:type: dict
|
|
52
|
+
:return: The FileInfoStorageDto of this FileInfoStorageDto. # noqa: E501
|
|
53
|
+
:rtype: FileInfoStorageDto
|
|
54
|
+
"""
|
|
55
|
+
return util.deserialize_model(dikt, cls)
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def file_name(self) -> str:
|
|
59
|
+
"""Gets the file_name of this FileInfoStorageDto.
|
|
60
|
+
|
|
61
|
+
# noqa: E501
|
|
62
|
+
|
|
63
|
+
:return: The file_name of this FileInfoStorageDto.
|
|
64
|
+
:rtype: str
|
|
65
|
+
"""
|
|
66
|
+
return self._file_name
|
|
67
|
+
|
|
68
|
+
@file_name.setter
|
|
69
|
+
def file_name(self, file_name: str):
|
|
70
|
+
"""Sets the file_name of this FileInfoStorageDto.
|
|
71
|
+
|
|
72
|
+
# noqa: E501
|
|
73
|
+
|
|
74
|
+
:param file_name: The file_name of this FileInfoStorageDto.
|
|
75
|
+
:type file_name: str
|
|
76
|
+
"""
|
|
77
|
+
if file_name is None:
|
|
78
|
+
raise ValueError("Invalid value for `file_name`, must not be `None`") # noqa: E501
|
|
79
|
+
|
|
80
|
+
self._file_name = file_name
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def file_size(self) -> int:
|
|
84
|
+
"""Gets the file_size of this FileInfoStorageDto.
|
|
85
|
+
|
|
86
|
+
# noqa: E501
|
|
87
|
+
|
|
88
|
+
:return: The file_size of this FileInfoStorageDto.
|
|
89
|
+
:rtype: int
|
|
90
|
+
"""
|
|
91
|
+
return self._file_size
|
|
92
|
+
|
|
93
|
+
@file_size.setter
|
|
94
|
+
def file_size(self, file_size: int):
|
|
95
|
+
"""Sets the file_size of this FileInfoStorageDto.
|
|
96
|
+
|
|
97
|
+
# noqa: E501
|
|
98
|
+
|
|
99
|
+
:param file_size: The file_size of this FileInfoStorageDto.
|
|
100
|
+
:type file_size: int
|
|
101
|
+
"""
|
|
102
|
+
if file_size is None:
|
|
103
|
+
raise ValueError("Invalid value for `file_size`, must not be `None`") # noqa: E501
|
|
104
|
+
|
|
105
|
+
self._file_size = file_size
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def unit(self) -> str:
|
|
109
|
+
"""Gets the unit of this FileInfoStorageDto.
|
|
110
|
+
|
|
111
|
+
# noqa: E501
|
|
112
|
+
|
|
113
|
+
:return: The unit of this FileInfoStorageDto.
|
|
114
|
+
:rtype: str
|
|
115
|
+
"""
|
|
116
|
+
return self._unit
|
|
117
|
+
|
|
118
|
+
@unit.setter
|
|
119
|
+
def unit(self, unit: str):
|
|
120
|
+
"""Sets the unit of this FileInfoStorageDto.
|
|
121
|
+
|
|
122
|
+
# noqa: E501
|
|
123
|
+
|
|
124
|
+
:param unit: The unit of this FileInfoStorageDto.
|
|
125
|
+
:type unit: str
|
|
126
|
+
"""
|
|
127
|
+
if unit is None:
|
|
128
|
+
raise ValueError("Invalid value for `unit`, must not be `None`") # noqa: E501
|
|
129
|
+
|
|
130
|
+
self._unit = unit
|
|
131
|
+
|
|
132
|
+
@property
|
|
133
|
+
def content_type(self) -> str:
|
|
134
|
+
"""Gets the content_type of this FileInfoStorageDto.
|
|
135
|
+
|
|
136
|
+
# noqa: E501
|
|
137
|
+
|
|
138
|
+
:return: The content_type of this FileInfoStorageDto.
|
|
139
|
+
:rtype: str
|
|
140
|
+
"""
|
|
141
|
+
return self._content_type
|
|
142
|
+
|
|
143
|
+
@content_type.setter
|
|
144
|
+
def content_type(self, content_type: str):
|
|
145
|
+
"""Sets the content_type of this FileInfoStorageDto.
|
|
146
|
+
|
|
147
|
+
# noqa: E501
|
|
148
|
+
|
|
149
|
+
:param content_type: The content_type of this FileInfoStorageDto.
|
|
150
|
+
:type content_type: str
|
|
151
|
+
"""
|
|
152
|
+
if content_type is None:
|
|
153
|
+
raise ValueError("Invalid value for `content_type`, must not be `None`") # noqa: E501
|
|
154
|
+
|
|
155
|
+
self._content_type = content_type
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
{
|
|
2
|
+
"openapi": "3.0.3",
|
|
3
|
+
"info": {
|
|
4
|
+
"title": "Blank API",
|
|
5
|
+
"version": "0.0.2",
|
|
6
|
+
"description": "This is a simple API descriptor."
|
|
7
|
+
},
|
|
8
|
+
"paths": {
|
|
9
|
+
"/files/{bucket_name}": {
|
|
10
|
+
"get": {
|
|
11
|
+
"tags": [
|
|
12
|
+
"File-Controller"
|
|
13
|
+
],
|
|
14
|
+
"responses": {
|
|
15
|
+
"200": {
|
|
16
|
+
"$ref": "#/components/responses/BucketFileListResponse"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"operationId": "list_monster_files",
|
|
20
|
+
"summary": "list_monster_files"
|
|
21
|
+
},
|
|
22
|
+
"parameters": [
|
|
23
|
+
{
|
|
24
|
+
"name": "bucket_name",
|
|
25
|
+
"schema": {
|
|
26
|
+
"type": "string"
|
|
27
|
+
},
|
|
28
|
+
"in": "path",
|
|
29
|
+
"required": true
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"components": {
|
|
35
|
+
"schemas": {
|
|
36
|
+
"BucketFileListDto": {
|
|
37
|
+
"description": "",
|
|
38
|
+
"required": [
|
|
39
|
+
"bucket",
|
|
40
|
+
"files_info"
|
|
41
|
+
],
|
|
42
|
+
"type": "object",
|
|
43
|
+
"properties": {
|
|
44
|
+
"bucket": {
|
|
45
|
+
"description": "",
|
|
46
|
+
"type": "string"
|
|
47
|
+
},
|
|
48
|
+
"files_info": {
|
|
49
|
+
"description": "",
|
|
50
|
+
"type": "array",
|
|
51
|
+
"items": {
|
|
52
|
+
"$ref": "#/components/schemas/FileInfoStorageDto"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"FileInfoStorageDto": {
|
|
58
|
+
"description": "",
|
|
59
|
+
"required": [
|
|
60
|
+
"file_name",
|
|
61
|
+
"file_size",
|
|
62
|
+
"unit",
|
|
63
|
+
"content_type"
|
|
64
|
+
],
|
|
65
|
+
"type": "object",
|
|
66
|
+
"properties": {
|
|
67
|
+
"file_name": {
|
|
68
|
+
"description": "",
|
|
69
|
+
"type": "string"
|
|
70
|
+
},
|
|
71
|
+
"file_size": {
|
|
72
|
+
"format": "int64",
|
|
73
|
+
"description": "",
|
|
74
|
+
"type": "integer"
|
|
75
|
+
},
|
|
76
|
+
"unit": {
|
|
77
|
+
"description": "",
|
|
78
|
+
"type": "string"
|
|
79
|
+
},
|
|
80
|
+
"content_type": {
|
|
81
|
+
"description": "",
|
|
82
|
+
"type": "string"
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"responses": {
|
|
88
|
+
"BucketFileListResponse": {
|
|
89
|
+
"content": {
|
|
90
|
+
"application/json": {
|
|
91
|
+
"schema": {
|
|
92
|
+
"$ref": "#/components/schemas/BucketFileListDto"
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
"description": ""
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
|
|
3
|
+
from flask import json
|
|
4
|
+
|
|
5
|
+
from adyd_detector_api.models.bucket_file_list_dto import BucketFileListDto # noqa: E501
|
|
6
|
+
from adyd_detector_api.test import BaseTestCase
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class TestFileControllerController(BaseTestCase):
|
|
10
|
+
"""FileControllerController integration test stubs"""
|
|
11
|
+
|
|
12
|
+
def test_list_monster_files(self):
|
|
13
|
+
"""Test case for list_monster_files
|
|
14
|
+
|
|
15
|
+
list_monster_files
|
|
16
|
+
"""
|
|
17
|
+
headers = {
|
|
18
|
+
'Accept': 'application/json',
|
|
19
|
+
}
|
|
20
|
+
response = self.client.open(
|
|
21
|
+
'/files/{bucket_name}'.format(bucket_name='bucket_name_example'),
|
|
22
|
+
method='GET',
|
|
23
|
+
headers=headers)
|
|
24
|
+
self.assert200(response,
|
|
25
|
+
'Response body is : ' + response.data.decode('utf-8'))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
if __name__ == '__main__':
|
|
29
|
+
unittest.main()
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
[tool.poetry]
|
|
2
|
+
name = "adyd-detector-api"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "API para ADYD Detector"
|
|
5
|
+
authors = ["JacoboGeadaAnsino <jacobo.geada.ansino@gmail.com>"]
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
packages = [{include = "adyd_detector_api"}]
|
|
8
|
+
repository = "https://github.com/gilmith/adyd_detector_api"
|
|
9
|
+
|
|
10
|
+
[tool.poetry.dependencies]
|
|
11
|
+
python = "^3.12"
|
|
12
|
+
python-dateutil = ">=2.8.2"
|
|
13
|
+
flask = ">=3.0.0"
|
|
14
|
+
connexion = {extras = ["flask"], version = ">=3.0.0"}
|
|
15
|
+
pydantic = "^2.0"
|
|
16
|
+
|
|
17
|
+
[tool.poetry.group.dev.dependencies]
|
|
18
|
+
poethepoet = ">=0.42.1"
|
|
19
|
+
|
|
20
|
+
[tool.poe.tasks]
|
|
21
|
+
generate = "openapi-generator-cli generate -i adyd_detector_api/openapi.yaml -g python-flask -o ./ --package-name adyd_detector_api --global-property models,apis --additional-properties=interfaceOnly=true,generateSourceCodeOnly=true"
|
|
22
|
+
publish = "poetry publish --build"
|
|
23
|
+
|
|
24
|
+
[build-system]
|
|
25
|
+
requires = ["poetry-core>=1.0.0"]
|
|
26
|
+
build-backend = "poetry.core.masonry.api"
|