Я разработал свой бэкэнд, используя Spring boot.
Я интегрирую облачные конечные точки, но у меня много ошибок, потому что я могу загрузить файл (apk, images) с некоторыми из моих API.
Вот мой файл swagger:
swagger: '2.0'
info:
description: 'Api Documentation'
version: '1.0.0'
title: 'Api Documentation for apk micro service'
termsOfService: 'urn:tos'
contact: {}
license:
name: 'Apache 2.0'
url: 'http://www.apache.org/licenses/LICENSE-2.0'
host: "mapk.api.gara.store"
basePath: /
tags:
-
name: apk-service-controller
description: 'Apk Service Controller'
-
name: category-controller
description: 'Category Controller'
schemes:
# Uncomment the next line if you configure SSL for this API.
# - "https"
- "http"
paths:
/api/apk/:
post:
tags: [apk-service-controller]
summary: create
operationId: createUsingPOST
consumes: [application/json]
produces: [application/json]
parameters: [{in: body, name: apkDto, description: apkDto, required: true, schema: {$ref: '#/definitions/ApkDto'}}]
security:
- api_key: []
responses: {'200': {description: OK, schema: {$ref: '#/definitions/Apk'}}, '201': {description: Created}, '401': {description: Unauthorized}, '403': {description: Forbidden}, '404': {description: 'Not Found'}}
put:
tags: [apk-service-controller]
summary: update
operationId: updateUsingPUT
consumes: [application/json]
produces: [application/json]
parameters: [{in: body, name: apkDto, description: apkDto, required: true, schema: {$ref: '#/definitions/ApkDto'}}]
security:
- api_key: []
responses: {'200': {description: OK, schema: {$ref: '#/definitions/Apk'}}, '201': {description: Created}, '401': {description: Unauthorized}, '403': {description: Forbidden}, '404': {description: 'Not Found'}}
/api/apk/activateapkversion:
post:
tags: [apk-service-controller]
summary: activateApkVersion
operationId: activateApkVersionUsingPOST
consumes: [application/json]
produces: ['*/*']
parameters: [{name: apkId, in: query, description: apkId, required: true, type: integer, format: int64}, {name: codeVersion, in: query, description: codeVersion, required: true, type: integer, format: int64}]
security:
- api_key: []
responses: {'200': {description: OK, schema: {$ref: '#/definitions/Apk'}}, '201': {description: Created}, '401': {description: Unauthorized}, '403': {description: Forbidden}, '404': {description: 'Not Found'}}
/api/apk/addapk:
post:
tags: [apk-service-controller]
summary: addApkFile
operationId: addApkFileUsingPOST
consumes: [multipart/form-data]
produces: ['*/*']
parameters: [{name: file, in: formData, description: file, required: true, type: file}, {name: apkId, in: query, description: apkId, required: true, type: integer, format: int64}]
security:
- api_key: []
responses: {'200': {description: OK, schema: {$ref: '#/definitions/ApkVersion'}}, '201': {description: Created}, '401': {description: Unauthorized}, '403': {description: Forbidden}, '404': {description: 'Not Found'}}
/api/apk/addorupdatecover:
post:
tags: [apk-service-controller]
summary: uploadOrUpdateCoverImage
operationId: uploadOrUpdateCoverImageUsingPOST
consumes: [multipart/form-data]
produces: ['*/*']
parameters: [{name: file, in: formData, description: file, required: true, type: file}, {name: apkId, in: query, description: apkId, required: true, type: integer, format: int64}]
security:
- api_key: []
responses: {'200': {description: OK, schema: {$ref: '#/definitions/Apk'}}, '201': {description: Created}, '401': {description: Unauthorized}, '403': {description: Forbidden}, '404': {description: 'Not Found'}}
/api/apk/addorupdateicon:
post:
tags: [apk-service-controller]
summary: uploadOrUpdateIconImage
operationId: uploadOrUpdateIconImageUsingPOST
consumes: [multipart/form-data]
produces: ['*/*']
parameters: [{name: file, in: formData, description: file, required: true, type: file}, {name: apkId, in: query, description: apkId, required: true, type: integer, format: int64}]
security:
- api_key: []
responses: {'200': {description: OK, schema: {$ref: '#/definitions/Apk'}}, '201': {description: Created}, '401': {description: Unauthorized}, '403': {description: Forbidden}, '404': {description: 'Not Found'}}
/api/apk/addscreenshots:
post:
tags: [apk-service-controller]
summary: addOrUpdateScreenShot
operationId: addOrUpdateScreenShotUsingPOST
consumes: [multipart/form-data]
produces: ['*/*']
parameters: [{name: file, in: formData, description: file, required: true, type: file}, {name: apkId, in: query, description: apkId, required: true, type: integer, format: int64}, {name: index, in: query, description: index, required: true, type: integer, format: int32}]
security:
- api_key: []
responses: {'200': {description: OK, schema: {$ref: '#/definitions/Apk'}}, '201': {description: Created}, '401': {description: Unauthorized}, '403': {description: Forbidden}, '404': {description: 'Not Found'}}
/api/apk/category/:
get:
tags: [category-controller]
summary: getAllCategories
operationId: getAllCategoriesUsingGET
produces: [application/json]
responses: {'200': {description: OK, schema: {type: array, items: {$ref: '#/definitions/Category'}}}, '401': {description: Unauthorized}, '403': {description: Forbidden}, '404': {description: 'Not Found'}}
security:
- api_key: []
post:
tags: [category-controller]
summary: createCategory
operationId: createCategoryUsingPOST
consumes: [application/json]
produces: [application/json]
parameters: [{name: categoryname, in: query, description: categoryname, required: true, type: string}]
security:
- api_key: []
responses: {'200': {description: OK, schema: {$ref: '#/definitions/Category'}}, '201': {description: Created}, '401': {description: Unauthorized}, '403': {description: Forbidden}, '404': {description: 'Not Found'}}
/api/apk/category/addsubcategory:
post:
tags: [category-controller]
summary: addSubCategory
operationId: addSubCategoryUsingPOST
consumes: [application/json]
produces: ['*/*']
parameters: [{name: categoryId, in: query, description: categoryId, required: true, type: integer, format: int64}, {name: subcategory, in: query, description: subcategory, required: true, type: string}]
security:
- api_key: []
responses: {'200': {description: OK, schema: {$ref: '#/definitions/Category'}}, '201': {description: Created}, '401': {description: Unauthorized}, '403': {description: Forbidden}, '404': {description: 'Not Found'}}
/api/apk/category/removesubcategory:
post:
tags: [category-controller]
summary: removeSubCategory
operationId: removeSubCategoryUsingPOST
consumes: [application/json]
produces: ['*/*']
parameters: [{name: categoryId, in: query, description: categoryId, required: true, type: integer, format: int64}, {name: subCategoryId, in: query, description: subCategoryId, required: true, type: integer, format: int64}]
security:
- api_key: []
responses: {'200': {description: OK, schema: {$ref: '#/definitions/Category'}}, '201': {description: Created}, '401': {description: Unauthorized}, '403': {description: Forbidden}, '404': {description: 'Not Found'}}
'/api/apk/category/{categoryId}':
delete:
tags: [category-controller]
summary: delete
operationId: deleteUsingDELETE_1
produces: ['*/*']
parameters: [{name: categoryId, in: path, description: categoryId, required: true, type: integer, format: int64}]
responses: {'200': {description: OK}, '204': {description: 'No Content'}, '401': {description: Unauthorized}, '403': {description: Forbidden}}
security:
- api_key: []
'/api/apk/category/{id}':
get:
tags: [category-controller]
summary: getCategoyById
operationId: getCategoyByIdUsingGET
produces: ['*/*']
parameters: [{name: id, in: path, description: id, required: true, type: integer, format: int64}]
responses: {'200': {description: OK, schema: {$ref: '#/definitions/Category'}}, '401': {description: Unauthorized}, '403': {description: Forbidden}, '404': {description: 'Not Found'}}
security:
- api_key: []
'/api/apk/company/{companyId}':
get:
tags: [apk-service-controller]
summary: getAllWebtoonByCompany
operationId: getAllWebtoonByCompanyUsingGET
produces: ['*/*']
parameters: [{name: companyId, in: query, description: companyId, required: false, type: integer, format: int64}]
responses: {'200': {description: OK, schema: {type: array, items: {$ref: '#/definitions/Apk'}}}, '401': {description: Unauthorized}, '403': {description: Forbidden}, '404': {description: 'Not Found'}}
security:
- api_key: []
/api/apk/reviewandrated:
post:
tags: [apk-service-controller]
summary: addAndUpdateReviewAndNote
operationId: addAndUpdateReviewAndNoteUsingPOST
consumes: [application/json]
produces: [application/json]
parameters: [{in: body, name: apkReviewDto, description: apkReviewDto, required: true, schema: {$ref: '#/definitions/ApkReviewDto'}}]
security:
- api_key: []
responses: {'200': {description: OK, schema: {$ref: '#/definitions/Apk'}}, '201': {description: Created}, '401': {description: Unauthorized}, '403': {description: Forbidden}, '404': {description: 'Not Found'}}
'/api/apk/{id}':
get:
tags: [apk-service-controller]
summary: getApkById
operationId: getApkByIdUsingGET
produces: ['*/*']
parameters: [{name: id, in: path, description: id, required: true, type: integer, format: int64}]
security:
- api_key: []
responses: {'200': {description: OK, schema: {$ref: '#/definitions/Apk'}}, '401': {description: Unauthorized}, '403': {description: Forbidden}, '404': {description: 'Not Found'}}
delete:
tags: [apk-service-controller]
summary: delete
operationId: deleteUsingDELETE
produces: ['*/*']
parameters: [{name: id, in: path, description: id, required: true, type: integer, format: int64}]
security:
- api_key: []
responses: {'200': {description: OK}, '204': {description: 'No Content'}, '401': {description: Unauthorized}, '403': {description: Forbidden}}
"/auth/info/googlejwt":
get:
description: "Returns the requests' authentication information."
operationId: "auth_info_google_jwt"
produces:
- "application/json"
responses:
200:
description: "Authenication info."
schema:
$ref: "#/definitions/authInfoResponse"
security:
- api_key: []
google_jwt: []
"/auth/info/googleidtoken":
get:
description: "Returns the requests' authentication information."
operationId: "authInfoGoogleIdToken"
produces:
- "application/json"
responses:
200:
description: "Authenication info."
schema:
$ref: "#/definitions/authInfoResponse"
security:
- api_key: []
google_id_token: []
definitions:
Apk:
type: object
properties:
apkDownloadUrl: {type: string}
apkName: {type: string}
apkPath: {type: string}
category: {$ref: '#/definitions/Category'}
changes: {type: string}
companyId: {type: integer, format: int64}
containsAds: {type: boolean}
coverDownloadUrl: {type: string}
coverPath: {type: string}
dependencies: {type: array, items: {type: string}}
description: {type: string}
displayName: {type: string}
iconDownloadUrl: {type: string}
iconPath: {type: string}
id: {type: integer, format: int64}
installs: {type: integer, format: int64}
isFree: {type: boolean}
listOfapkVersion: {type: array, items: {$ref: '#/definitions/ApkVersion'}}
maxSdkVersion: {type: string}
minSdkVersion: {type: string}
packageName: {type: string}
permissions: {type: array, items: {type: string}}
price: {type: number}
rating: {$ref: '#/definitions/Rating'}
repositoryGeneratedId: {type: string}
screenshotList: {type: array, items: {type: string}}
shortDescription: {type: string}
size: {type: integer, format: int64}
status: {type: string, enum: [INITIATED, PUBLISHED, VALIDATION_IN_PROGRESS, REJECTED]}
subCategory: {$ref: '#/definitions/SubCategory'}
targetSdkVersion: {type: string}
userReview: {type: array, items: {$ref: '#/definitions/Review'}}
versionCode: {type: integer, format: int64}
versionName: {type: string}
videoUrl: {type: string}
title: Apk
ApkDto:
type: object
properties:
allMandatoryFieldsFilledForCreation: {type: boolean}
apkId: {type: integer, format: int64}
categoryId: {type: integer, format: int64}
companyId: {type: integer, format: int64}
description: {type: string}
displayName: {type: string}
isFree: {type: boolean}
price: {type: number}
shortDescription: {type: string}
subCategoryId: {type: integer, format: int64}
title: ApkDto
ApkReviewDto:
type: object
properties:
apkId: {type: integer, format: int64}
appUserId: {type: integer, format: int64}
minimumFielsRequiredSet: {type: boolean}
reviewComment: {type: string}
reviewId: {type: integer, format: int64}
stars: {type: integer, format: int32}
title: ApkReviewDto
ApkVersion:
type: object
properties:
artifactId: {type: string}
compileSdkVersion: {type: string}
compileSdkVersionCodename: {type: string}
configForSplit: {type: string}
dependencies: {type: array, items: {type: string}}
downloadPath: {type: string}
featureSplit: {type: boolean}
groupId: {type: string}
id: {type: integer, format: int64}
installLocation: {type: string}
isolatedSplits: {type: boolean}
label: {type: string}
maxSdkVersion: {type: string}
minSdkVersion: {type: string}
name: {type: string}
packageName: {type: string}
path: {type: string}
permissions: {type: array, items: {type: string}}
platformBuildVersionCode: {type: string}
revisionCode: {type: integer, format: int64}
sharedUserId: {type: string}
sharedUserLabel: {type: string}
size: {type: integer, format: int64}
split: {type: string}
splitRequired: {type: boolean}
targetSdkVersion: {type: string}
usesFeatures: {type: array, items: {type: string}}
versionCode: {type: integer, format: int64}
versionName: {type: string}
title: ApkVersion
Category:
type: object
properties:
id: {type: integer, format: int64}
name: {type: string}
subCategoryList: {type: array, items: {$ref: '#/definitions/SubCategory'}}
title: Category
Rating:
type: object
properties:
average: {type: number, format: float}
ratingId: {type: integer, format: int64}
stars: {type: object, additionalProperties: {type: integer, format: int32}}
starsByUserId: {type: object, additionalProperties: {type: integer, format: int32}}
title: Rating
Review:
type: object
properties:
appUserId: {type: integer, format: int64}
comment: {type: string}
commentDate: {type: string, format: date-time}
id: {type: integer, format: int64}
stars: {type: integer, format: int32}
title: Review
SubCategory:
type: object
properties:
id: {type: integer, format: int64}
name: {type: string}
title: SubCategory
securityDefinitions:
# This section configures basic authentication with an API key.
api_key:
type: "apiKey"
name: "key"
in: "query"
# This section configures authentication using Google API Service Accounts
# to sign a json web token. This is mostly used for server-to-server
# communication.
google_jwt:
authorizationUrl: ""
flow: "implicit"
type: "oauth2"
# This must match the 'iss' field in the JWT.
x-google-issuer: "jwt-client.endpoints.sample.google.com"
# Update this with your service account's email address.
x-google-jwks_uri: "https://www.googleapis.com/service_accounts/v1/jwk/YOUR-SERVICE-ACCOUNT-EMAIL"
# This must match the "aud" field in the JWT. You can add multiple
# audiences to accept JWTs from multiple clients.
x-google-audiences: "echo.endpoints.sample.google.com"
# This section configures authentication using Google OAuth2 ID Tokens.
# ID Tokens can be obtained using OAuth2 clients, and can be used to access
# your API on behalf of a particular user.
google_id_token:
authorizationUrl: ""
flow: "implicit"
type: "oauth2"
x-google-issuer: "https://accounts.google.com"
x-google-jwks_uri: "https://www.googleapis.com/oauth2/v3/certs"
# Your OAuth2 client's Client ID must be added here. You can add
# multiple client IDs to accept tokens from multiple clients.
x-google-audiences: "YOUR-CLIENT-ID"
Я получил следующие ошибки с моей командой развертывания gcloud --verbosity=debug endpoints services deploy openapi.yaml
:
INFO: Refreshing access_token
DEBUG: Running [gcloud.endpoints.services.deploy] with arguments: [--verbosity: "debug", SERVICE_CONFIG_FILE:1: "[u'openapi.yaml']"]
INFO: No JSON detected in service config. Trying YAML...
DEBUG: (gcloud.endpoints.services.deploy) INVALID_ARGUMENT: Cannot convert to service config.
'location: "unknown location"
kind: ERROR
message: "http: repeated message field \'google.protobuf.Struct.fields\' referred to by message \'AddApkFileUsingPOSTRequest\' cannot be mapped as an HTTP parameter."
location: "unknown location"
kind: ERROR
message: "http: cyclic message field \'google.protobuf.Struct.FieldsEntry.value\' referred to by message \'AddApkFileUsingPOSTRequest\' in method \'method 1.mapk_api_gara_store.AddApkFileUsingPOST\' cannot be mapped as an HTTP parameter."
location: "unknown location"
kind: ERROR
message: "http: cyclic message field \'google.protobuf.ListValue.values\' referred to by message \'AddApkFileUsingPOSTRequest\' in method \'method 1.mapk_api_gara_store.AddApkFileUsingPOST\' cannot be mapped as an HTTP parameter."
location: "unknown location"
kind: ERROR
message: "http: repeated message field \'google.protobuf.Struct.fields\' referred to by message \'AddOrUpdateScreenShotUsingPOSTRequest\' cannot be mapped as an HTTP parameter."
location: "unknown location"
kind: ERROR
message: "http: cyclic message field \'google.protobuf.Struct.FieldsEntry.value\' referred to by message \'AddOrUpdateScreenShotUsingPOSTRequest\' in method \'method 1.mapk_api_gara_store.AddOrUpdateScreenShotUsingPOST\' cannot be mapped as an HTTP parameter."
Traceback (most recent call last):
File "/usr/lib64/google-cloud-sdk/lib/googlecloudsdk/calliope/cli.py", line 984, in Execute
resources = calliope_command.Run(cli=self, args=args)
File "/usr/lib64/google-cloud-sdk/lib/googlecloudsdk/calliope/backend.py", line 807, in Run
resources = command_instance.Run(args)
File "/usr/lib64/google-cloud-sdk/lib/surface/endpoints/services/deploy.py", line 356, in Run
validate_only=self.validate_only)
File "/usr/lib64/google-cloud-sdk/lib/googlecloudsdk/api_lib/endpoints/services_util.py", line 333, in PushMultipleServiceConfigFiles
api_response = client.services_configs.Submit(submit_request)
File "/usr/lib64/google-cloud-sdk/lib/googlecloudsdk/third_party/apis/servicemanagement/v1/servicemanagement_v1_client.py", line 273, in Submit
config, request, global_params=global_params)
File "/usr/lib64/google-cloud-sdk/lib/third_party/apitools/base/py/base_api.py", line 731, in _RunMethod
return self.ProcessHttpResponse(method_config, http_response, request)
File "/usr/lib64/google-cloud-sdk/lib/third_party/apitools/base/py/base_api.py", line 737, in ProcessHttpResponse
self.__ProcessHttpResponse(method_config, http_response, request))
File "/usr/lib64/google-cloud-sdk/lib/third_party/apitools/base/py/base_api.py", line 604, in __ProcessHttpResponse
http_response, method_config=method_config, request=request)
HttpBadRequestError: HttpError accessing <https://servicemanagement.googleapis.com/v1/services/mapk.api.gara.store/configs:submit?alt=json>: response: <{'status': '400', 'content-length': '3538', 'x-xss-protection': '0', 'x-content-type-options': 'nosniff', 'transfer-encoding': 'chunked', 'vary': 'Origin, X-Origin, Referer', 'server': 'ESF', '-content-encoding': 'gzip', 'cache-control': 'private', 'date': 'Tue, 17 Mar 2020 20:58:29 GMT', 'x-frame-options': 'SAMEORIGIN', 'alt-svc': 'quic=":443"; ma=2592000; v="46,43",h3-Q050=":443"; ma=2592000,h3-Q049=":443"; ma=2592000,h3-Q048=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000', 'content-type': 'application/json; charset=UTF-8'}>, content <{
"error": {
"code": 400,
"message": "Cannot convert to service config.\n'location: \"unknown location\"\nkind: ERROR\nmessage: \"http: repeated message field \\'google.protobuf.Struct.fields\\' referred to by message \\'AddApkFileUsingPOSTRequest\\' cannot be mapped as an HTTP parameter.\"\n\n location: \"unknown location\"\nkind: ERROR\nmessage: \"http: cyclic message field \\'google.protobuf.Struct.FieldsEntry.value\\' referred to by message \\'AddApkFileUsingPOSTRequest\\' in method \\'method 1.mapk_api_gara_store.AddApkFileUsingPOST\\' cannot be mapped as an HTTP parameter.\"\n\n location: \"unknown location\"\nkind: ERROR\nmessage: \"http: cyclic message field \\'google.protobuf.ListValue.values\\' referred to by message \\'AddApkFileUsingPOSTRequest\\' in method \\'method 1.mapk_api_gara_store.AddApkFileUsingPOST\\' cannot be mapped as an HTTP parameter.\"\n\n location: \"unknown location\"\nkind: ERROR\nmessage: \"http: repeated message field \\'google.protobuf.Struct.fields\\' referred to by message \\'UploadOrUpdateCoverImageUsingPOSTRequest\\' cannot be mapped as an HTTP parameter.\"\n\n location: \"unknown location\"\nkind: ERROR\nmessage: \"http: cyclic message field \\'google.protobuf.Struct.FieldsEntry.value\\' referred to by message \\'UploadOrUpdateCoverImageUsingPOSTRequest\\' in method \\'method 1.mapk_api_gara_store.UploadOrUpdateCoverImageUsingPOST\\' cannot be mapped as an HTTP parameter.\"\n\n location: \"unknown location\"\nkind: ERROR\nmessage: \"http: cyclic message field \\'google.protobuf.ListValue.values\\' referred to by message \\'UploadOrUpdateCoverImageUsingPOSTRequest\\' in method \\'method 1.mapk_api_gara_store.UploadOrUpdateCoverImageUsingPOST\\' cannot be mapped as an HTTP parameter.\"\n\n location: \"unknown location\"\nkind: ERROR\nmessage: \"http: repeated message field \\'google.protobuf.Struct.fields\\' referred to by message \\'UploadOrUpdateIconImageUsingPOSTRequest\\' cannot be mapped as an HTTP parameter.\"\n\n location: \"unknown location\"\nkind: ERROR\nmessage: \"http: cyclic message field \\'google.protobuf.Struct.FieldsEntry.value\\' referred to by message \\'UploadOrUpdateIconImageUsingPOSTRequest\\' in method \\'method 1.mapk_api_gara_store.UploadOrUpdateIconImageUsingPOST\\' cannot be mapped as an HTTP parameter.\"\n\n location: \"unknown location\"\nkind: ERROR\nmessage: \"http: cyclic message field \\'google.protobuf.ListValue.values\\' referred to by message \\'UploadOrUpdateIconImageUsingPOSTRequest\\' in method \\'method 1.mapk_api_gara_store.UploadOrUpdateIconImageUsingPOST\\' cannot be mapped as an HTTP parameter.\"\n\n location: \"unknown location\"\nkind: ERROR\nmessage: \"http: repeated message field \\'google.protobuf.Struct.fields\\' referred to by message \\'AddOrUpdateScreenShotUsingPOSTRequest\\' cannot be mapped as an HTTP parameter.\"\n\n location: \"unknown location\"\nkind: ERROR\nmessage: \"http: cyclic message field \\'google.protobuf.Struct.FieldsEntry.value\\' referred to by message \\'AddOrUpdateScreenShotUsingPOSTRequest\\' in method \\'method 1.mapk_api_gara_store.AddOrUpdateScreenShotUsingPOST\\' cannot be mapped as an HTTP parameter.\"\n\n location: \"unknown location\"\nkind: ERROR\nmessage: \"http: cyclic message field \\'google.protobuf.ListValue.values\\' referred to by message \\'AddOrUpdateScreenShotUsingPOSTRequest\\' in method \\'method 1.mapk_api_gara_store.AddOrUpdateScreenShotUsingPOST\\' cannot be mapped as an HTTP parameter.\"\n'",
"status": "INVALID_ARGUMENT"
}
}
>
ERROR: (gcloud.endpoints.services.deploy) INVALID_ARGUMENT: Cannot convert to service config.
'location: "unknown location"
kind: ERROR
message: "http: repeated message field \'google.protobuf.Struct.fields\' referred to by message \'AddApkFileUsingPOSTRequest\' cannot be mapped as an HTTP parameter."
location: "unknown location"
kind: ERROR
message: "http: cyclic message field \'google.protobuf.Struct.FieldsEntry.value\' referred to by message \'AddApkFileUsingPOSTRequest\' in method \'method 1.mapk_api_gara_store.AddApkFileUsingPOST\' cannot be mapped as an HTTP parameter."
Как я могу это сделать? Похоже, что облачные конечные точки не поддерживают файл. Мое приложение на рынке, мне нужно загрузить файл через мои API.
Спасибо