diff --git a/api/openapi/things.yml b/api/openapi/things.yml index 52aacedbe1..668af17a1c 100644 --- a/api/openapi/things.yml +++ b/api/openapi/things.yml @@ -1,90 +1,100 @@ -openapi: 3.0.1 +openapi: 3.0.3 info: - title: Mainflux things service - description: HTTP API for managing platform things and channels. - version: "1.0.0" + title: Mainflux Things Service + description: | + This is the Things Server based on the OpenAPI 3.0 specification. It is the HTTP API for managing platform things and channels. You can now help us improve the API whether it's by making changes to the definition itself or to the code. + Some useful links: + - [The Mainflux repository](https://github.com/mainflux/mainflux) + - [The Mainflux Postman Collection](https://github.com/mainflux/mainflux/blob/master/api/postman/postman.yaml) + contact: + email: info@mainflux.com + license: + name: Apache 2.0 + url: https://github.com/mainflux/mainflux/blob/master/LICENSE + version: 0.14.0 + +servers: + - url: http://localhost:9000 + - url: https://localhost:9000 + +tags: + - name: Things + description: Everything about your Things + externalDocs: + description: Find out more abour things + url: http://docs.mainflux.io/ + - name: Channels + description: Everything about your Channels + externalDocs: + description: Find out more about things channels + url: http://docs.mainflux.io/ + - name: Policies + description: Access to things policies + externalDocs: + description: Find out more about things policies + url: http://docs.mainflux.io/ paths: /things: post: + tags: + - Things summary: Adds new thing description: | Adds new thing to the list of things owned by user identified using the provided access token. - tags: - - things requestBody: $ref: "#/components/requestBodies/ThingCreateReq" responses: '201': - $ref: "#/components/responses/CreateThingRes" + $ref: "#/components/responses/ThingCreateRes" '400': description: Failed due to malformed JSON. '401': description: Missing or invalid access token provided. '409': - description: Entity already exist. + description: Failed due to using an existing identity. '415': description: Missing or invalid content type. '422': - description: Database can't process request. + description: Database can't process request. '500': $ref: "#/components/responses/ServiceError" + get: + tags: + - Things summary: Retrieves things description: | Retrieves a list of things. Due to performance concerns, data is retrieved in subsets. The API things must ensure that the entire dataset is consumed either by making subsequent requests, or by increasing the subset size of the initial request. - tags: - - things parameters: - $ref: "#/components/parameters/Limit" - $ref: "#/components/parameters/Offset" - - $ref: "#/components/parameters/Name" - - $ref: "#/components/parameters/Order" - - $ref: "#/components/parameters/Direction" - $ref: "#/components/parameters/Metadata" + - $ref: "#/components/parameters/Status" + - $ref: "#/components/parameters/ThingName" + - $ref: "#/components/parameters/Tags" + - $ref: "#/components/parameters/Owner" + security: + - bearerAuth: [] responses: '200': - $ref: "#/components/responses/ThingsPageRes" + $ref: "#/components/responses/ThingPageRes" '400': description: Failed due to malformed query parameters. '401': - description: Missing or invalid access token provided. + description: | + Missing or invalid access token provided. '404': description: A non-existent entity request. '422': description: Database can't process request. '500': $ref: "#/components/responses/ServiceError" - /things/search: - post: - summary: Search and retrieves things - description: | - Retrieves a list of things with name and metadata filtering. - Due to performance concerns, data is retrieved in subsets. - The API things must ensure that the entire - dataset is consumed either by making subsequent requests, or by - increasing the subset size of the initial request. - tags: - - things - requestBody: - $ref: "#/components/requestBodies/ThingsSearchReq" - responses: - '200': - $ref: "#/components/responses/ThingsPageRes" - '400': - description: Failed due to malformed query parameters. - '401': - description: Missing or invalid access token provided. - '404': - description: A non-existent entity request. - '422': - description: Unprocessable Entity - '500': - $ref: "#/components/responses/ServiceError" + /things/bulk: post: summary: Bulk provisions new things @@ -92,12 +102,12 @@ paths: Adds new things to the list of things owned by user identified using the provided access token. tags: - - things + - Things requestBody: $ref: "#/components/requestBodies/ThingsCreateReq" responses: '201': - description: Things registered. + $ref: "#/components/responses/ThingPageRes" '400': description: Failed due to malformed JSON. '401': @@ -106,77 +116,201 @@ paths: description: Missing or invalid content type. '500': $ref: "#/components/responses/ServiceError" - /things/{thingId}: + + + /things/{thingID}: get: summary: Retrieves thing info + description: | + Retrieves a specific thing that is identifier by the thing ID. tags: - - things + - Things parameters: - - $ref: "#/components/parameters/ThingId" + - $ref: "#/components/parameters/ThingID" + security: + - bearerAuth: [] responses: '200': $ref: "#/components/responses/ThingRes" '401': description: Missing or invalid access token provided. '404': - description: Thing does not exist. + description: A non-existent entity request. '422': description: Database can't process request. '500': $ref: "#/components/responses/ServiceError" - put: - summary: Updates thing info + + patch: + summary: Updates name and metadata of the thing. description: | Update is performed by replacing the current resource data with values provided in a request payload. Note that the thing's type and ID cannot be changed. tags: - - things + - Things parameters: - - $ref: "#/components/parameters/ThingId" + - $ref: "#/components/parameters/ThingID" requestBody: $ref: "#/components/requestBodies/ThingUpdateReq" + security: + - bearerAuth: [] + responses: + '200': + $ref: "#/components/responses/ThingRes" + '400': + description: Failed due to malformed JSON. + '401': + description: Missing or invalid access token provided. + '404': + description: Failed due to non existing thing. + '415': + description: Missing or invalid content type. + '500': + $ref: "#/components/responses/ServiceError" + + /things/{thingID}/tags: + patch: + summary: Updates tags the thing. + description: | + Updates tags of the thing with provided ID. Tags is updated using + authorization token and the new tags received in request. + tags: + - Things + parameters: + - $ref: "#/components/parameters/ThingID" + requestBody: + $ref: "#/components/requestBodies/ThingUpdateTagsReq" + security: + - bearerAuth: [] + responses: + '200': + $ref: "#/components/responses/ThingRes" + '400': + description: Failed due to malformed JSON. + '404': + description: Failed due to non existing thing. + '401': + description: Missing or invalid access token provided. + '500': + $ref: "#/components/responses/ServiceError" + + /things/{thingID}/owner: + patch: + summary: Updates the thing owner. + description: | + Updates owner for the thing with provided ID. Owner is updated using + authorization token and a new owner identifier received in request. + tags: + - Things + parameters: + - $ref: "#/components/parameters/ThingID" + requestBody: + $ref: "#/components/requestBodies/ThingUpdateOwnerReq" + security: + - bearerAuth: [] responses: '200': - description: Thing updated. + $ref: "#/components/responses/ThingRes" '400': description: Failed due to malformed JSON. + '404': + description: Failed due to non existing thing. '401': description: Missing or invalid access token provided. + '500': + $ref: "#/components/responses/ServiceError" + + /things/{thingID}/secret: + patch: + summary: Updates Secret of the identified thing. + description: | + Updates secret of the identified in thing. Secret is updated using + authorization token and the new received info. Update is performed by replacing current key with a new one. + tags: + - Things + parameters: + - $ref: "#/components/parameters/ThingID" + requestBody: + $ref: "#/components/requestBodies/ThingUpdateSecretReq" + security: + - bearerAuth: [] + responses: + '200': + $ref: "#/components/responses/ThingRes" + '400': + description: Failed due to malformed JSON. + '401': + description: Missing or invalid access token provided. '404': - description: Thing does not exist. + description: Failed due to non existing thing. + '409': + description: Specified key already exists. '415': - description: Missing or invalid content type. + description: Missing or invalid content type. + '500': + $ref: "#/components/responses/ServiceError" + + /things/{thingID}/disable: + post: + summary: Disables a thing + description: | + Disables a specific thing that is identifier by the thing ID. + tags: + - Things + parameters: + - $ref: "#/components/parameters/ThingID" + security: + - bearerAuth: [] + responses: + '200': + $ref: "#/components/responses/ThingRes" + '400': + description: Failed due to malformed thing's ID. + '401': + description: Missing or invalid access token provided. + '404': + description: A non-existent entity request. + '422': + description: Database can't process request. '500': $ref: "#/components/responses/ServiceError" - delete: - summary: Removes a thing + + /things/{thingID}/enable: + post: + summary: Enables a thing description: | - Removes a thing. The service will ensure that the removed thing is - disconnected from all of the existing channels. + Enables a specific thing that is identifier by the thing ID. tags: - - things + - Things parameters: - - $ref: "#/components/parameters/ThingId" + - $ref: "#/components/parameters/ThingID" + security: + - bearerAuth: [] responses: - '204': - description: Thing removed. + '200': + $ref: "#/components/responses/ThingRes" '400': description: Failed due to malformed thing's ID. '401': description: Missing or invalid access token provided. + '404': + description: A non-existent entity request. + '422': + description: Database can't process request. '500': $ref: "#/components/responses/ServiceError" - /things/{thingId}/share: + + /things/{thingID}/share: post: summary: Shares a thing with user identified by request body. description: | Adds 'read', 'write' or 'delete' policies to the user identified by the request body. Sharing a particular thing is only allowed to users who have 'write' access to that thing. tags: - - things + - Things parameters: - - $ref: "#/components/parameters/ThingId" + - $ref: "#/components/parameters/ThingID" requestBody: $ref: "#/components/requestBodies/ShareThingReq" responses: @@ -192,42 +326,45 @@ paths: description: Missing or invalid content type. '500': $ref: "#/components/responses/ServiceError" - /things/{thingId}/key: - patch: - summary: Updates thing key + + /things/{thingID}/channels: + get: + summary: List of channels connected to specified thing description: | - Update is performed by replacing current key with a new one. + Retrieves list of channels connected to specified thing with pagination + metadata. tags: - - things + - Things parameters: - - $ref: "#/components/parameters/ThingId" - requestBody: - $ref: "#/components/requestBodies/KeyUpdateReq" + - $ref: "#/components/parameters/ThingID" + - $ref: "#/components/parameters/Offset" + - $ref: "#/components/parameters/Limit" responses: '200': - description: Thing key updated. + $ref: "#/components/responses/ChannelPageRes" '400': - description: Failed due to malformed JSON. + description: Failed due to malformed query parameters. '401': description: Missing or invalid access token provided. '404': description: Thing does not exist. - '409': - description: Specified key already exists. - '415': - description: Missing or invalid content type. + '422': + description: Database can't process request. '500': $ref: "#/components/responses/ServiceError" + /channels: post: + tags: + - Channels summary: Creates new channel description: | Creates new channel. User identified by the provided access token will be the channel's owner. - tags: - - channels requestBody: $ref: "#/components/requestBodies/ChannelCreateReq" + security: + - bearerAuth: [] responses: '201': $ref: "#/components/responses/ChannelCreateRes" @@ -236,38 +373,43 @@ paths: '401': description: Missing or invalid access token provided. '409': - description: Entity already exist. + description: Failed due to using an existing identity. '415': description: Missing or invalid content type. '500': $ref: "#/components/responses/ServiceError" + get: - summary: Retrieves channels + summary: Lists channels. description: | Retrieves a list of channels. Due to performance concerns, data is retrieved in subsets. The API things must ensure that the entire dataset is consumed either by making subsequent requests, or by increasing the subset size of the initial request. tags: - - channels + - Channels + security: + - bearerAuth: [] parameters: - $ref: "#/components/parameters/Limit" - $ref: "#/components/parameters/Offset" - - $ref: "#/components/parameters/Name" - - $ref: "#/components/parameters/Order" - - $ref: "#/components/parameters/Direction" - $ref: "#/components/parameters/Metadata" + - $ref: "#/components/parameters/ChannelName" + - $ref: "#/components/parameters/OwnerId" responses: '200': - $ref: "#/components/responses/ChannelsPageRes" + $ref: "#/components/responses/ChannelPageRes" '400': description: Failed due to malformed query parameters. '401': description: Missing or invalid access token provided. + '404': + description: Channel does not exist. '422': - description: Database can't process request. + description: Database can't process request. '500': $ref: "#/components/responses/ServiceError" + /channels/bulk: post: summary: Bulk provisions new channels @@ -275,7 +417,7 @@ paths: Adds new channels to the list of channels owned by user identified using the provided access token. tags: - - channels + - Channels requestBody: $ref: "#/components/requestBodies/ChannelsCreateReq" responses: @@ -291,13 +433,18 @@ paths: description: Missing or invalid content type. '500': $ref: "#/components/responses/ServiceError" - /channels/{chanId}: + + /channels/{channelId}: get: - summary: Retrieves channel info + summary: Retrieves channel info. + description: | + Gets info on a channel specified by id. tags: - - channels + - Channels parameters: - - $ref: "#/components/parameters/ChanId" + - $ref: "#/components/parameters/ChannelId" + security: + - bearerAuth: [] responses: '200': $ref: "#/components/responses/ChannelRes" @@ -308,52 +455,115 @@ paths: '404': description: Channel does not exist. '422': - description: Database can't process request. + description: Database can't process request. '500': $ref: "#/components/responses/ServiceError" + put: - summary: Updates channel info + summary: Updates channel data. description: | Update is performed by replacing the current resource data with values provided in a request payload. Note that the channel's ID will not be affected. tags: - - channels + - Channels parameters: - - $ref: "#/components/parameters/ChanId" + - $ref: "#/components/parameters/ChannelId" + security: + - bearerAuth: [] requestBody: - $ref: "#/components/requestBodies/ChannelCreateReq" + $ref: "#/components/requestBodies/ChannelUpdateReq" responses: '200': - description: Channel updated. + $ref: "#/components/responses/ChannelRes" '400': - description: Failed due to malformed JSON. + description: Failed due to malformed query parameters. '401': description: Missing or invalid access token provided. '404': description: Channel does not exist. '415': - description: Missing or invalid content type. + description: Missing or invalid content type. '500': $ref: "#/components/responses/ServiceError" - delete: - summary: Removes a channel + + /channels/{channelId}/enable: + post: + summary: Enables a channel description: | - Removes a channel. The service will ensure that the subscribed apps and - things are unsubscribed from the removed channel. + Enables a specific channel that is identifier by the channel ID. tags: - - channels + - Channels parameters: - - $ref: "#/components/parameters/ChanId" + - $ref: "#/components/parameters/ChannelId" + security: + - bearerAuth: [] responses: - '204': - description: Channel removed. + '200': + $ref: "#/components/responses/ChannelRes" + '400': + description: Failed due to malformed query parameters. + '401': + description: Missing or invalid access token provided. + '404': + description: A non-existent entity request. + '422': + description: Database can't process request. + '500': + $ref: "#/components/responses/ServiceError" + + /channels/{channelId}/disable: + post: + summary: Disables a channel + description: | + Disables a specific channel that is identifier by the channel ID. + tags: + - Channels + parameters: + - $ref: "#/components/parameters/ChannelId" + security: + - bearerAuth: [] + responses: + '200': + $ref: "#/components/responses/ChannelRes" '400': description: Failed due to malformed channel's ID. '401': description: Missing or invalid access token provided. + '404': + description: A non-existent entity request. + '422': + description: Database can't process request. + '500': + $ref: "#/components/responses/ServiceError" + + /channels/{channelId}/things: + get: + summary: List of things connected to specified channel + description: | + Retrieves list of things connected to specified channel with pagination + metadata. + tags: + - Channels + parameters: + - $ref: "#/components/parameters/ChannelId" + - $ref: "#/components/parameters/Offset" + - $ref: "#/components/parameters/Limit" + - $ref: "#/components/parameters/Connected" + responses: + '200': + $ref: "#/components/responses/ThingsPageRes" + '400': + description: Failed due to malformed query parameters. + '401': + description: Missing or invalid access token provided. + '404': + description: A non-existent entity request. + '422': + description: Database can't process request. '500': $ref: "#/components/responses/ServiceError" + /connect: post: summary: Connects thing and channel. @@ -361,7 +571,7 @@ paths: Connect things specified by IDs to channels specified by IDs. Channel and thing are owned by user identified using the provided access token. tags: - - things + - Policies requestBody: $ref: "#/components/requestBodies/ConnCreateReq" responses: @@ -379,18 +589,19 @@ paths: description: Missing or invalid content type. '500': $ref: "#/components/responses/ServiceError" + /disconnect: - put: + post: summary: Disconnect things and channels using lists of IDs. description: | Disconnect things from channels specified by lists of IDs. Channels and things are owned by user identified using the provided access token. tags: - - things + - Policies requestBody: $ref: "#/components/requestBodies/DisconnReq" responses: - '200': + '204': $ref: "#/components/responses/DisconnRes" '400': description: Failed due to malformed JSON. @@ -401,114 +612,65 @@ paths: '415': description: Missing or invalid content type. '500': - $ref: "#/components/responses/ServiceError" - /things/{thingId}/channels: - get: - summary: List of channels connected to specified thing + $ref: "#/components/responses/ServiceError" + + /channels/{channelId}/things/{thingID}: + post: + summary: Connects the thing to the channel description: | - Retrieves list of channels connected to specified thing with pagination - metadata. + Creates connection between a thing and a channel. Once connected to + the channel, things are allowed to exchange messages through it. tags: - - channels + - Policies parameters: - - $ref: "#/components/parameters/ThingId" - - $ref: "#/components/parameters/Offset" - - $ref: "#/components/parameters/Limit" - - $ref: "#/components/parameters/Connected" + - $ref: "#/components/parameters/ChannelId" + - $ref: "#/components/parameters/ThingID" responses: '200': - $ref: "#/components/responses/ChannelsPageRes" + $ref: "#/components/responses/ConnCreateRes" '400': description: Failed due to malformed query parameters. '401': description: Missing or invalid access token provided. '404': - description: Thing does not exist. - '422': - description: Database can't process request. + description: Channel or thing does not exist. '500': $ref: "#/components/responses/ServiceError" - /channels/{chanId}/things: - get: - summary: List of things connected to specified channel + + delete: + summary: Disconnects the thing from the channel description: | - Retrieves list of things connected to specified channel with pagination - metadata. + Removes connection between a thing and a channel. Once connection is + removed, thing can no longer exchange messages through the channel. tags: - - things + - Policies parameters: - - $ref: "#/components/parameters/ChanId" - - $ref: "#/components/parameters/Offset" - - $ref: "#/components/parameters/Limit" - - $ref: "#/components/parameters/Connected" + - $ref: "#/components/parameters/ChannelId" + - $ref: "#/components/parameters/ThingID" responses: - '200': - $ref: "#/components/responses/ThingsPageRes" + '204': + description: Thing disconnected. '400': description: Failed due to malformed query parameters. '401': description: Missing or invalid access token provided. '404': - description: A non-existent entity request. - '422': - description: Database can't process request. + description: Channel or thing does not exist. '500': - $ref: "#/components/responses/ServiceError" - /channels/{chanId}/things/{thingId}: - put: - summary: Connects the thing to the channel - description: | - Creates connection between a thing and a channel. Once connected to - the channel, things are allowed to exchange messages through it. - tags: - - channels - parameters: - - $ref: "#/components/parameters/ChanId" - - $ref: "#/components/parameters/ThingId" - responses: - '200': - description: Thing connected. - '400': - description: Failed due to malformed query parameters. - '401': - description: Missing or invalid access token provided. - '404': - description: Channel or thing does not exist. - '500': - $ref: "#/components/responses/ServiceError" - delete: - summary: Disconnects the thing from the channel - description: | - Removes connection between a thing and a channel. Once connection is - removed, thing can no longer exchange messages through the channel. - tags: - - channels - parameters: - - $ref: "#/components/parameters/ChanId" - - $ref: "#/components/parameters/ThingId" - responses: - '204': - description: Thing disconnected. - '400': - description: Failed due to malformed query parameters. - '401': - description: Missing or invalid access token provided. - '404': - description: Channel or thing does not exist. - '500': - $ref: "#/components/responses/ServiceError" - /identify/channels/{chanId}/access-by-key: - post: - summary: Checks if thing has access to a channel. + $ref: "#/components/responses/ServiceError" + + /identify/channels/{channelId}/access-by-key: + post: + summary: Checks if thing has access to a channel. description: | Checks if a thing with a specified key has an access to a specified channel and if it has, it returns that things id. tags: - - access + - Policies parameters: - - $ref: "#/components/parameters/ChanId" + - $ref: "#/components/parameters/ChannelId" requestBody: - $ref: "#/components/requestBodies/IdentityReq" + $ref: "#/components/requestBodies/AccessByIDReq" responses: '200': $ref: "#/components/responses/AccessGrantedRes" @@ -520,16 +682,17 @@ paths: description: Missing or invalid content type. '500': $ref: "#/components/responses/ServiceError" - /identify/channels/{chanId}/access-by-id: + + /identify/channels/{channelId}/access-by-id: post: summary: Checks if thing has access to a channel. description: | Checks if a thing with a specified ID has an access to a specified channel. tags: - - access + - Policies parameters: - - $ref: "#/components/parameters/ChanId" + - $ref: "#/components/parameters/ChannelId" requestBody: $ref: "#/components/requestBodies/AccessByIDReq" responses: @@ -543,6 +706,7 @@ paths: description: Missing or invalid content type. '500': $ref: "#/components/responses/ServiceError" + /identify: post: summary: Validates thing's key and returns it's ID if key is valid. @@ -550,7 +714,7 @@ paths: Validates thing's key and returns it's ID if specified key exists and is valid. tags: - - identity + - Policies requestBody: $ref: "#/components/requestBodies/IdentityReq" responses: @@ -561,37 +725,84 @@ paths: '415': description: Missing or invalid content type. '500': - $ref: "#/components/responses/ServiceError" - /groups/{groupId}: + $ref: "#/components/responses/ServiceError" + get: - summary: Retrieves things + summary: Fetches policy data. description: | - Retrieves a list of things that belong to a group. Due to performance concerns, data - is retrieved in subsets. The API things must ensure that the entire - dataset is consumed either by making subsequent requests, or by - increasing the subset size of the initial request. + List available policies. tags: - - things + - Policies parameters: - - $ref: "#/components/parameters/GroupId" - $ref: "#/components/parameters/Limit" - - $ref: "#/components/parameters/Offset" - - $ref: "#/components/parameters/Order" - - $ref: "#/components/parameters/Direction" - - $ref: "#/components/parameters/Metadata" + - $ref: "#/components/parameters/Offset" + - $ref: "#/components/parameters/Subject" + - $ref: "#/components/parameters/Object" + - $ref: "#/components/parameters/Actions" + security: + - bearerAuth: [] responses: '200': - $ref: "#/components/responses/ThingsPageRes" + $ref: "#/components/responses/PolicyPageRes" '400': description: Failed due to malformed query parameters. '401': description: Missing or invalid access token provided. '404': - description: A non-existent entity request. - '422': - description: Database can't process request. + description: Channel does not exist. + '500': + $ref: "#/components/responses/ServiceError" + + put: + summary: Updates policy data. + description: | + Updates Actions of a policy. + tags: + - Policies + parameters: + - $ref: "#/components/parameters/Subject" + - $ref: "#/components/parameters/Object" + - $ref: "#/components/parameters/Actions" + security: + - bearerAuth: [] + requestBody: + $ref: "#/components/requestBodies/PolicyUpdateReq" + responses: + '200': + description: Channel updated. + '400': + description: Failed due to malformed query parameters. + '401': + description: Missing or invalid access token provided. + '404': + description: Channel does not exist. '500': $ref: "#/components/responses/ServiceError" + + /policies/{obj}/{sub}: + delete: + tags: + - Policies + summary: Delete policy + description: | + Delete specified policies + security: + - bearerAuth: [] + parameters: + - $ref: "#/components/parameters/Obj" + - $ref: "#/components/parameters/Sub" + responses: + '200': + $ref: "#/components/responses/PolicyPageRes" + '400': + description: Failed due to malformed query parameters. + '401': + description: Missing or invalid access token provided. + '404': + description: Policy does not exist. + '500': + $ref: "#/components/responses/ServiceError" + /health: get: summary: Retrieves service health check info. @@ -605,92 +816,367 @@ paths: components: schemas: - Key: - type: string - format: uuid - description: | - Thing key that is used for thing auth. If there is - not one provided service will generate one in UUID - format. - Identity: + ThingReqObj: type: object properties: - id: + name: + type: string + example: thingName + description: Thing name. + tags: + type: array + minItems: 0 + items: + type: string + example: ['tag1', 'tag2'] + description: Thing tags. + credentials: + type: object + properties: + identity: + type: string + example: "thingidentity" + description: Thing's identity will be used as its unique identifier + secret: + type: string + format: password + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + minimum: 8 + description: Free-form account secret used for acquiring auth token(s). + owner: type: string format: uuid - description: Thing unique identifier. This can be either - provided by the user or left blank. If the user provides a UUID, - it would be validated. If there is not one provided then - the service will generate one in UUID format. - ThingReqSchema: + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + description: Thing owner must be exsiting in the databse. + metadata: + type: object + example: {"domain": "example.com"} + description: Arbitrary, object-encoded thing's data. + status: + type: string + description: Thing Status + format: string + example: enabled + required: + - credentials + + ChannelReqObj: type: object properties: - key: - $ref: "#/components/schemas/Key" name: type: string - description: Free-form thing name. + example: channelName + description: Free-form channel name. Channel name is unique on the given hierarchy level. + description: + type: string + example: long channel description + description: Channel description, free form text. + parent_id: + type: string + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + description: Id of parent channel, it must be existing channel. metadata: type: object + example: {"domain": "example.com"} + description: Arbitrary, object-encoded channels's data. + status: + type: string + description: Channel Status + format: string + example: enabled + owner_id: + type: string + format: uuid + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + description: Channel owner ID must be exsiting in the databse. + required: + - name + + PolicyReqObj: + type: object + properties: + subject: + type: string + description: Policy subject refers to the thing id + example: 'bb7edb32-2eac-4aad-aebe-ed96fe073879' + object: + type: string + description: Policy object refers to either the thing id, channel id, computation id or dataset id + example: 'bb7edb32-2eac-4aad-aebe-ed96fe073879' + actions: + type: array + minItems: 0 + items: + type: string + example: ['m_write', 'g_add'] + description: Policy actions. + required: + - subject + - object + - actions + + Thing: + type: object + properties: + id: + type: string + format: uuid + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + description: Thing unique identifier. + name: + type: string + example: thingName + description: Thing name. + tags: + type: array + minItems: 0 + items: + type: string + example: ['tag1', 'tag2'] + description: Thing tags. + owner: + type: string + format: uuid + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + description: Thing owner identifier. + credentials: + type: object + properties: + identity: + type: string + example: thingidentity + description: Thing Identity for example email address. + secret: + type: string + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + description: Thing secret password. + metadata: + type: object + example: {"domain": "example.com"} description: Arbitrary, object-encoded thing's data. - ThingsReqSchema: + status: + type: string + description: Thing Status + format: string + example: enabled + created_at: + type: string + format: date-time + example: "2019-11-26 13:31:52" + description: Time when the channel was created. + updated_at: + type: string + format: date-time + example: "2019-11-26 13:31:52" + description: Time when the channel was created. + xml: + name: thing + + Channel: type: object properties: + id: + type: string + format: uuid + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + description: Unique channel identifier generated by the service. name: type: string - description: Name filter. Filtering is performed as a case-insensitive partial match. + example: channelName + description: Free-form channel name. Channel name is unique on the given hierarchy level. + owner_id: + type: string + format: uuid + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + description: Channel owner identifier of thing that created the channel.. + parent_id: + type: string + format: uuid + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + description: Channel parent identifier. + description: + type: string + example: long channel description + description: Channel description, free form text. metadata: type: object - description: Metadata filter. Filtering is performed matching the parameter with metadata on top level. Parameter is json. - total: - type: integer - description: Total number of items. - offset: + example: {"role": "general"} + description: Arbitrary, object-encoded channels's data. + path: + type: string + example: bb7edb32-2eac-4aad-aebe-ed96fe073879.bb7edb32-2eac-4aad-aebe-ed96fe073879 + description: Hierarchy path, concatenated ids of channel ancestors. + level: type: integer - description: Number of items to skip during retrieval. - default: 0 - minimum: 0 - limit: + description: Level in hierarchy, distance from the root channel. + format: int32 + example: 2 + maximum: 5 + created_at: + type: string + format: date-time + example: "2019-11-26 13:31:52" + description: Datetime when the channel was created. + updated_at: + type: string + format: date-time + example: "2019-11-26 13:31:52" + description: Datetime when the channel was created. + status: + type: string + description: Channel Status + format: string + example: enabled + xml: + name: channel + + Memberships: + type: object + properties: + id: + type: string + format: uuid + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + description: Unique channel identifier generated by the service. + name: + type: string + example: channelName + description: Free-form channel name. Channel name is unique on the given hierarchy level. + owner_id: + type: string + format: uuid + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + description: Channel owner identifier of thing that created the channel.. + parent_id: + type: string + format: uuid + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + description: Channel parent identifier. + description: + type: string + example: long channel description + description: Channel description, free form text. + metadata: + type: object + example: {"role": "general"} + description: Arbitrary, object-encoded channels's data. + path: + type: string + example: bb7edb32-2eac-4aad-aebe-ed96fe073879.bb7edb32-2eac-4aad-aebe-ed96fe073879 + description: Hierarchy path, concatenated ids of channel ancestors. + level: type: integer - description: Size of the subset to retrieve. - default: 10 - maximum: 100 - minimum: 1 - order: + description: Level in hierarchy, distance from the root channel. + format: int32 + example: 2 + created_at: type: string - description: Order type. - default: id - enum: - - name - - id - dir: + format: date-time + example: "2019-11-26 13:31:52" + description: Datetime when the channel was created. + updated_at: type: string - description: Order direction. - default: desc - enum: - - asc - - desc - ThingResSchema: + format: date-time + example: "2019-11-26 13:31:52" + description: Datetime when the channel was created. + xml: + name: memberships + + Members: type: object properties: id: type: string format: uuid - description: Unique thing identifier generated by the service. + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + description: Thing unique identifier. name: type: string - description: Free-form thing name. - key: + example: thingName + description: Thing name. + tags: + type: array + minItems: 0 + items: + type: string + example: ['computations', 'datasets'] + description: Thing tags. + owner: type: string format: uuid - description: Auto-generated access key. + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + description: Thing owner identifier. + credentials: + type: object + properties: + identity: + type: string + example: thing@mainflux.com + description: Thing Identity for example email address. + secret: + type: string + example: password + description: Thing secret password. metadata: type: object + example: {"role": "general"} description: Arbitrary, object-encoded thing's data. - required: - - id - - type - - key + status: + type: string + description: Thing Status + format: string + example: enabled + created_at: + type: string + format: date-time + example: "2019-11-26 13:31:52" + description: Time when the channel was created. + updated_at: + type: string + format: date-time + example: "2019-11-26 13:31:52" + description: Time when the channel was created. + xml: + name: members + + Policy: + type: object + properties: + owner_id: + type: string + format: uuid + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + description: Policy owner identifier. + subject: + type: string + format: uuid + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + description: Policy subject identifier. + object: + type: string + format: uuid + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + description: Policy object identifier. + actions: + type: array + minItems: 0 + items: + type: string + example: ['m_write', 'g_add'] + description: Policy actions. + created_at: + type: string + format: date-time + example: "2019-11-26 13:31:52" + description: Time when the policy was created. + updated_at: + type: string + format: date-time + example: "2019-11-26 13:31:52" + description: Time when the policy was updated. + xml: + name: policy + ThingsPage: type: object properties: @@ -699,253 +1185,600 @@ components: minItems: 0 uniqueItems: true items: - $ref: "#/components/schemas/ThingResSchema" + $ref: "#/components/schemas/Thing" total: type: integer + example: 1 description: Total number of items. offset: type: integer description: Number of items to skip during retrieval. limit: type: integer + example: 10 description: Maximum number of items to return in one page. required: - things - ChannelReqSchema: + - total + - offset + + ChannelsPage: type: object properties: - name: - type: string - description: Free-form channel name. - metadata: - type: object - description: Arbitrary, object-encoded channel's data. - ChannelResSchema: + channels: + type: array + minItems: 0 + uniqueItems: true + items: + $ref: "#/components/schemas/Channel" + total: + type: integer + example: 1 + description: Total number of items. + offset: + type: integer + description: Number of items to skip during retrieval. + limit: + type: integer + example: 10 + description: Maximum number of items to return in one page. + required: + - channels + - total + - level + + MembershipsPage: type: object properties: - id: - type: string - description: Unique channel identifier generated by the service. - name: - type: string - description: Free-form channel name. - metadata: - type: object - description: Arbitrary, object-encoded channel's data. + memberships: + type: array + minItems: 0 + uniqueItems: true + items: + $ref: "#/components/schemas/Memberships" + total: + type: integer + example: 1 + description: Total number of items. + offset: + type: integer + description: Number of items to skip during retrieval. + limit: + type: integer + example: 10 + description: Maximum number of items to return in one page. required: - - id - ChannelsPage: + - memberships + - total + - level + + MembersPage: type: object properties: - channels: + members: type: array minItems: 0 uniqueItems: true items: - $ref: "#/components/schemas/ChannelResSchema" + $ref: "#/components/schemas/Members" total: type: integer + example: 1 description: Total number of items. offset: type: integer description: Number of items to skip during retrieval. limit: type: integer + example: 10 description: Maximum number of items to return in one page. required: - - channels + - members + - total + - level + + PoliciesPage: + type: object + properties: + policies: + type: array + minItems: 0 + uniqueItems: true + items: + $ref: "#/components/schemas/Policy" + total: + type: integer + example: 1 + description: Total number of items. + offset: + type: integer + description: Number of items to skip during retrieval. + limit: + type: integer + example: 10 + description: Maximum number of items to return in one page. + required: + - policies + - total + - offset + + ThingUpdate: + type: object + properties: + name: + type: string + example: thingName + description: Thing name. + metadata: + type: object + example: {"role": "general"} + description: Arbitrary, object-encoded thing's data. + required: + - name + - metadata + + ThingTags: + type: object + properties: + tags: + type: array + example: ['tag1', 'tag2'] + description: Thing tags. + minItems: 0 + uniqueItems: true + items: + type: string + + ThingSecret: + type: object + properties: + secret: + type: string + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + description: New thing secret. + required: + - secret + + ThingOwner: + type: object + properties: + owner: + type: string + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + description: Thing owner for example email address. + required: + - owner + + ChannelUpdate: + type: object + properties: + name: + type: string + example: channelName + description: Free-form channel name. Channel name is unique on the given hierarchy level. + description: + type: string + example: long description but not too long + description: Channel description, free form text. + metadata: + type: object + example: {"role": "general"} + description: Arbitrary, object-encoded channels's data. + required: + - name + - metadata + - description + + PolicyUpdate: + type: object + properties: + actions: + type: array + example: ['m_write', 'g_add'] + description: Policy actions. + minItems: 0 + uniqueItems: true + items: + type: string + + Identity: + type: object + properties: + id: + type: string + format: uuid + description: Thing unique identifier. This can be either + provided by the user or left blank. If the user provides a UUID, + it would be validated. If there is not one provided then + the service will generate one in UUID format. + ConnectionReqSchema: type: object properties: - channel_ids: + group_ids: type: array description: Channel IDs. items: - type: string - thing_ids: + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + client_ids: type: array description: Thing IDs items: - type: string + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + ShareThingReqSchema: type: object properties: - user_id: - type: string - description: User ID. + user_ids: + type: array + description: User IDs. items: - type: string + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 policies: type: array description: Policies items: - type: string + example: c_update + + Error: + type: object + properties: + error: + type: string + description: Error message + example: {"error": "malformed entity specification"} + HealthRes: + type: object + properties: + status: + type: string + description: Service status. + enum: + - pass + version: + type: string + description: Service version. + example: 0.14.0 + commit: + type: string + description: Service commit hash. + example: 7d6f4dc4f7f0c1fa3dc24eddfb18bb5073ff4f62 + description: + type: string + description: Service description. + example: things service + build_time: + type: string + description: Service build time. + example: 1970-01-01_00:00:00 + parameters: - ChanId: - name: chanId - description: Unique channel identifier. - in: path - schema: - type: string - format: uuid - required: true - ThingId: - name: thingId - description: Unique thing identifier. - in: path - schema: - type: string - format: uuid - required: true - GroupId: - name: groupId - description: Unique group identifier. - in: path - schema: - type: string - format: ulid - required: true - Limit: - name: limit - description: Size of the subset to retrieve. - in: query - schema: - type: integer - default: 10 - maximum: 100 - minimum: 1 - required: false - Offset: - name: offset - description: Number of items to skip during retrieval. - in: query - schema: - type: integer - default: 0 - minimum: 0 - required: false - Connected: - name: connected - description: Connection state of the subset to retrieve. - in: query - schema: - type: boolean - default: true - required: false - Name: - name: name - description: Name filter. Filtering is performed as a case-insensitive partial match. - in: query - schema: - type: string - required: false - Order: - name: order - description: Order type. - in: query - schema: - type: string - default: id - enum: - - name - - id - required: false - Direction: - name: dir - description: Order direction. - in: query - schema: - type: string - default: desc - enum: - - asc - - desc - required: false - Metadata: - name: metadata - description: Metadata filter. Filtering is performed matching the parameter with metadata on top level. Parameter is json. - in: query - required: false - schema: - type: object - additionalProperties: {} + ThingID: + name: thingID + description: Unique thing identifier. + in: path + schema: + type: string + format: uuid + required: true + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + + ThingName: + name: name + description: Thing's name. + in: query + schema: + type: string + required: false + example: 'thingName' + + ThingIdentity: + name: identity + description: Thing's identity. + in: query + schema: + type: string + required: false + example: 'admin@example.com' + + Owner: + name: owner + description: Thing's owner. + in: query + schema: + type: string + format: uuid + required: false + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + + ThingOwner: + name: owner + description: Unique owner identifier for a thing. + in: query + schema: + type: string + format: uuid + required: false + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + + Status: + name: status + description: Thing account status. + in: query + schema: + type: string + default: enabled + required: false + example: enabled + Tags: + name: tags + description: Thing tags. + in: query + schema: + type: array + minItems: 0 + uniqueItems: true + items: + type: string + required: false + example: ['yello', 'orange'] + + ChannelName: + name: name + description: Channel's name. + in: query + schema: + type: string + required: false + example: 'channelName' + + ChannelDescription: + name: name + description: Channel's description. + in: query + schema: + type: string + required: false + example: 'channel description' + + ChannelId: + name: channelId + description: Unique channel identifier. + in: path + schema: + type: string + format: uuid + required: true + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + + ParentId: + name: parentId + description: Unique parent identifier for a channel. + in: query + schema: + type: string + format: uuid + required: false + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + + Level: + name: level + description: Level of hierarchy up to which to retrieve channels from given channel id. + in: query + schema: + type: integer + minimum: 1 + maximum: 5 + required: false + + Tree: + name: tree + description: Specify type of response, JSON array or tree. + in: query + required: false + schema: + type: boolean + default: false + + OwnerId: + name: ownerId + description: Unique owner identifier for a channel. + in: query + schema: + type: string + format: uuid + required: false + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + + Subject: + name: subject + description: Unique subject identifier for a policy. + in: query + schema: + type: string + format: uuid + required: false + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + + Object: + name: object + description: Unique object identifier for a policy. + in: query + schema: + type: string + format: uuid + required: false + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + + Actions: + name: actions + description: Policy action types. + in: query + schema: + type: array + minItems: 0 + uniqueItems: true + items: + type: string + required: false + example: ['m_write', 'g_add'] + + Sub: + name: sub + description: Unique subject identifier for a policy. + in: path + schema: + type: string + format: uuid + required: true + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + + Obj: + name: obj + description: Unique object identifier for a policy. + in: path + schema: + type: string + format: uuid + required: true + example: bb7edb32-2eac-4aad-aebe-ed96fe073879 + + Metadata: + name: metadata + description: Metadata filter. Filtering is performed matching the parameter with metadata on top level. Parameter is json. + in: query + schema: + type: string + minimum: 0 + required: false + + Limit: + name: limit + description: Size of the subset to retrieve. + in: query + schema: + type: integer + default: 10 + maximum: 100 + minimum: 1 + required: false + example: '100' + + Offset: + name: offset + description: Number of items to skip during retrieval. + in: query + schema: + type: integer + default: 0 + minimum: 0 + required: false + example: '0' + + Connected: + name: connected + description: Connection state of the subset to retrieve. + in: query + schema: + type: boolean + default: true + required: false + requestBodies: ThingCreateReq: - description: JSON-formatted document describing the new thing. + description: JSON-formatted document describing the new thing to be registered required: true content: application/json: schema: - $ref: "#/components/schemas/ThingReqSchema" - ThingsCreateReq: - description: JSON-formatted document describing the new things. + $ref: '#/components/schemas/ThingReqObj' + + ThingUpdateReq: + description: JSON-formated document describing the metadata and name of thing to be update required: true content: application/json: schema: - type: object - properties: - key: - $ref: "#/components/schemas/Key" - things: - type: array - items: - $ref: "#/components/schemas/ThingReqSchema" - ThingUpdateReq: - description: Arbitrary, object-encoded thing's data. + $ref: "#/components/schemas/ThingUpdate" + + ThingUpdateTagsReq: + description: JSON-formated document describing the tags of thing to be update required: true content: application/json: schema: - type: object - properties: - name: - type: string - description: Free-form thing name. - metadata: - type: object - ThingsSearchReq: - description: JSON-formatted document describing search parameters. + $ref: "#/components/schemas/ThingTags" + + ThingUpdateSecretReq: + description: Secret change data. Thing can change its secret. required: true content: application/json: schema: - $ref: "#/components/schemas/ThingsReqSchema" - KeyUpdateReq: + $ref: '#/components/schemas/ThingSecret' + + ThingUpdateOwnerReq: + description: JSON-formated document describing the owner of thing to be update required: true - description: JSON containing thing. content: application/json: schema: - type: object - properties: - key: - type: string - format: uuid - description: Thing key that is used for thing auth. + $ref: "#/components/schemas/ThingOwner" + ChannelCreateReq: - description: JSON-formatted document describing the updated channel. + description: JSON-formatted document describing the new channel to be registered + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ChannelReqObj' + + ChannelUpdateReq: + description: JSON-formated document describing the metadata and name of channel to be update required: true content: application/json: schema: - $ref: "#/components/schemas/ChannelReqSchema" + $ref: "#/components/schemas/ChannelUpdate" + + PolicyCreateReq: + description: JSON-formatted document describing the new channel to be registered + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PolicyReqObj' + + PolicyUpdateReq: + description: JSON-formated document describing the actions of a policy to be update + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/PolicyUpdate" + + ThingsCreateReq: + description: JSON-formatted document describing the new things. + required: true + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/ThingReqObj" + ChannelsCreateReq: description: JSON-formatted document describing the new channels. required: true content: application/json: schema: - type: object - properties: - key: - $ref: "#/components/schemas/Key" - things: - type: array - items: - $ref: "#/components/schemas/ChannelReqSchema" + type: array + items: + $ref: "#/components/schemas/ChannelReqObj" + ConnCreateReq: description: JSON-formatted document describing the new connection. required: true @@ -953,6 +1786,7 @@ components: application/json: schema: $ref: "#/components/schemas/ConnectionReqSchema" + DisconnReq: description: JSON-formatted document describing the entities for disconnection. required: true @@ -960,6 +1794,7 @@ components: application/json: schema: $ref: "#/components/schemas/ConnectionReqSchema" + IdentityReq: description: JSON-formatted document that contains thing key. required: true @@ -974,6 +1809,7 @@ components: description: Thing key that is used for thing auth. required: - token + AccessByIDReq: description: JSON-formatted document that contains thing key. required: true @@ -982,10 +1818,21 @@ components: schema: type: object properties: - thing_id: + client_id: type: string format: uuid description: Thing ID by which thing is uniquely identified. + action: + type: string + format: string + example: "m_read" + description: Action you want to check access against. + entity_type: + type: string + format: string + example: group + description: Entity Type. + ShareThingReq: description: JSON-formatted document describing sharing things policies. required: true @@ -995,61 +1842,117 @@ components: $ref: "#/components/schemas/ShareThingReqSchema" responses: - CreateThingRes: - description: Thing registered. + ThingCreateRes: + description: Registered new thing. headers: Location: - content: - text/plain: - schema: - type: string - description: Created thing's relative URL. - example: /things/{thingId} + schema: + type: string + format: url + description: Registered thing relative URL in the format `/things/` + content: + application/json: + schema: + $ref: "#/components/schemas/Thing" + ThingRes: description: Data retrieved. content: application/json: schema: - $ref: "#/components/schemas/ThingResSchema" + $ref: "#/components/schemas/Thing" + + ThingPageRes: + description: Data retrieved. + content: + application/json: + schema: + $ref: "#/components/schemas/ThingsPage" + ThingsPageRes: description: Data retrieved. content: application/json: schema: $ref: "#/components/schemas/ThingsPage" + + MembershipsPageRes: + description: Memberships associated with the thing. + content: + application/json: + schema: + $ref: "#/components/schemas/MembershipsPage" + ChannelCreateRes: - description: Channel created. + description: Registered new channel. headers: Location: - content: - text/plain: - schema: - type: string - description: Created channel's relative URL (i.e. /channels/{chanId}). + schema: + type: string + format: url + description: Registered channel relative URL in the format `/channels/` + content: + application/json: + schema: + $ref: "#/components/schemas/Channel" + ChannelRes: description: Data retrieved. content: application/json: schema: - $ref: "#/components/schemas/ChannelResSchema" - ChannelsPageRes: + $ref: "#/components/schemas/Channel" + + ChannelPageRes: description: Data retrieved. content: application/json: schema: $ref: "#/components/schemas/ChannelsPage" - ConnCreateRes: - description: Thing registered. + + MembersPageRes: + description: Channel members retrieved. + content: + application/json: + schema: + $ref: "#/components/schemas/MembersPage" + + PolicyCreateRes: + description: Registered new policy. headers: Location: content: text/plain: schema: type: string - description: Created thing's relative URL. - example: /things/{thingId} + format: url + description: Registered policy relative URL. + example: /policy/{subject}/{object} + + PolicyRes: + description: Data retrieved. + content: + application/json: + schema: + $ref: "#/components/schemas/Policy" + + PolicyPageRes: + description: Data retrieved. + content: + application/json: + schema: + $ref: "#/components/schemas/PoliciesPage" + + ConnCreateRes: + description: Thing registered. + content: + application/json: + schema: + $ref: "#/components/schemas/PoliciesPage" + DisconnRes: description: Things disconnected. + AccessGrantedRes: description: | Thing has access to the specified channel and the thing ID is returned. @@ -1057,33 +1960,35 @@ components: application/json: schema: $ref: "#/components/schemas/Identity" + IdentityRes: description: Thing ID returned. content: application/json: schema: $ref: "#/components/schemas/Identity" - ServiceError: - description: Unexpected server-side error occurred. - content: - application/json: - schema: - type: string - format: byte + HealthRes: description: Service Health Check. + content: + application/health+json: + schema: + $ref: "#/components/schemas/HealthRes" + + ServiceError: + description: Unexpected server-side error occurred. content: application/json: schema: - $ref: "./schemas/HealthInfo.yml" - + $ref: "#/components/schemas/Error" + securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: JWT description: | - * Users access: "Authorization: Bearer " - + * Thing access: "Authorization: Bearer " + security: - bearerAuth: [] diff --git a/cli/users.go b/cli/users.go index 966b76f586..62ffaee1c2 100644 --- a/cli/users.go +++ b/cli/users.go @@ -250,16 +250,16 @@ var cmdUsers = []cobra.Command{ }, }, { - Use: "password ", + Use: "password ", Short: "Update password", Long: `Update user password`, Run: func(cmd *cobra.Command, args []string) { - if len(args) != 4 { + if len(args) != 3 { logUsage(cmd.Use) return } - user, err := sdk.UpdatePassword(args[0], args[1], args[2], args[3]) + user, err := sdk.UpdatePassword(args[0], args[1], args[2]) if err != nil { logError(err) return diff --git a/pkg/sdk/go/requests.go b/pkg/sdk/go/requests.go index 8a26fe6ead..d1503b7191 100644 --- a/pkg/sdk/go/requests.go +++ b/pkg/sdk/go/requests.go @@ -10,7 +10,7 @@ type updateClientSecretReq struct { } type updateThingSecretReq struct { - Secret string `json:"key,omitempty"` + Secret string `json:"secret,omitempty"` } // updateClientIdentityReq is used to update the client identity diff --git a/pkg/sdk/go/sdk.go b/pkg/sdk/go/sdk.go index 3fac7ddb02..c19c268d44 100644 --- a/pkg/sdk/go/sdk.go +++ b/pkg/sdk/go/sdk.go @@ -124,7 +124,7 @@ type SDK interface { UpdateUserOwner(user User, token string) (User, errors.SDKError) // UpdatePassword updates user password. - UpdatePassword(id, oldPass, newPass, token string) (User, errors.SDKError) + UpdatePassword(oldPass, newPass, token string) (User, errors.SDKError) // EnableUser changes the status of the user to enabled. EnableUser(id, token string) (User, errors.SDKError) diff --git a/pkg/sdk/go/things.go b/pkg/sdk/go/things.go index 3c891c911f..4ab7e1f39c 100644 --- a/pkg/sdk/go/things.go +++ b/pkg/sdk/go/things.go @@ -182,7 +182,7 @@ func (sdk mfSDK) UpdateThingSecret(id, secret, token string) (Thing, errors.SDKE return Thing{}, errors.NewSDKError(err) } - url := fmt.Sprintf("%s/%s/%s/key", sdk.thingsURL, thingsEndpoint, id) + url := fmt.Sprintf("%s/%s/%s/secret", sdk.thingsURL, thingsEndpoint, id) _, body, sdkerr := sdk.processRequest(http.MethodPatch, url, token, string(CTJSON), data, http.StatusOK) if sdkerr != nil { diff --git a/pkg/sdk/go/users.go b/pkg/sdk/go/users.go index dc82e0aec6..8c4d86da90 100644 --- a/pkg/sdk/go/users.go +++ b/pkg/sdk/go/users.go @@ -194,7 +194,7 @@ func (sdk mfSDK) UpdateUserIdentity(user User, token string) (User, errors.SDKEr } // UpdatePassword updates user password. -func (sdk mfSDK) UpdatePassword(id, oldPass, newPass, token string) (User, errors.SDKError) { +func (sdk mfSDK) UpdatePassword(oldPass, newPass, token string) (User, errors.SDKError) { var ucsr = updateClientSecretReq{OldSecret: oldPass, NewSecret: newPass} data, err := json.Marshal(ucsr) @@ -202,7 +202,7 @@ func (sdk mfSDK) UpdatePassword(id, oldPass, newPass, token string) (User, error return User{}, errors.NewSDKError(err) } - url := fmt.Sprintf("%s/%s/%s/secret", sdk.usersURL, usersEndpoint, id) + url := fmt.Sprintf("%s/%s/secret", sdk.usersURL, usersEndpoint) _, body, sdkerr := sdk.processRequest(http.MethodPatch, url, token, string(CTJSON), data, http.StatusOK) if sdkerr != nil { diff --git a/pkg/sdk/go/users_test.go b/pkg/sdk/go/users_test.go index 5de063e30c..c6815fdbe4 100644 --- a/pkg/sdk/go/users_test.go +++ b/pkg/sdk/go/users_test.go @@ -872,7 +872,7 @@ func TestUpdateClientSecret(t *testing.T) { repoCall := cRepo.On("RetrieveByID", mock.Anything, user.ID).Return(convertClient(tc.response), tc.err) repoCall1 := cRepo.On("RetrieveByIdentity", mock.Anything, user.Credentials.Identity).Return(convertClient(tc.response), tc.err) repoCall2 := cRepo.On("UpdateSecret", mock.Anything, mock.Anything).Return(convertClient(tc.response), tc.err) - uClient, err := clientSDK.UpdatePassword(user.ID, tc.oldSecret, tc.newSecret, tc.token) + uClient, err := clientSDK.UpdatePassword(tc.oldSecret, tc.newSecret, tc.token) assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected error %s, got %s", tc.desc, tc.err, err)) assert.Equal(t, tc.response, uClient, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, uClient)) if tc.err == nil { diff --git a/things/clients/api/requests.go b/things/clients/api/requests.go index 3849b3ae5a..1c18ed431f 100644 --- a/things/clients/api/requests.go +++ b/things/clients/api/requests.go @@ -176,7 +176,7 @@ func (req updateClientOwnerReq) validate() error { type updateClientCredentialsReq struct { token string id string - Secret string `json:"key,omitempty"` + Secret string `json:"secret,omitempty"` } func (req updateClientCredentialsReq) validate() error { diff --git a/things/clients/api/transport.go b/things/clients/api/transport.go index 3cdb2be856..5acf53ed3e 100644 --- a/things/clients/api/transport.go +++ b/things/clients/api/transport.go @@ -80,7 +80,7 @@ func MakeHandler(svc clients.Service, mux *bone.Mux, logger mflog.Logger) http.H opts..., )) - mux.Patch("/things/:id/key", kithttp.NewServer( + mux.Patch("/things/:id/secret", kithttp.NewServer( otelkit.EndpointMiddleware(otelkit.WithOperation("update_thing_secret"))(updateClientSecretEndpoint(svc)), decodeUpdateClientCredentials, api.EncodeResponse, diff --git a/things/groups/api/transport.go b/things/groups/api/transport.go index 8b961055dc..07aa281f82 100644 --- a/things/groups/api/transport.go +++ b/things/groups/api/transport.go @@ -62,6 +62,7 @@ func MakeHandler(svc groups.Service, mux *bone.Mux, logger logger.Logger) http.H api.EncodeResponse, opts..., )) + mux.Post("/channels/:id/enable", kithttp.NewServer( otelkit.EndpointMiddleware(otelkit.WithOperation("enable_channel"))(enableGroupEndpoint(svc)), decodeChangeGroupStatus, diff --git a/things/policies/api/http/endpoints.go b/things/policies/api/http/endpoints.go index 7401def859..e50c5a9dc3 100644 --- a/things/policies/api/http/endpoints.go +++ b/things/policies/api/http/endpoints.go @@ -83,7 +83,7 @@ func connectEndpoint(svc policies.Service) endpoint.Endpoint { return nil, err } - return policyRes{policy, true}, nil + return policyRes{[]policies.Policy{policy}, true}, nil } } @@ -94,6 +94,7 @@ func connectThingsEndpoint(svc policies.Service) endpoint.Endpoint { if err := cr.validate(); err != nil { return nil, err } + ps := []policies.Policy{} for _, tid := range cr.ClientIDs { for _, cid := range cr.GroupIDs { if len(cr.Actions) == 0 { @@ -107,10 +108,11 @@ func connectThingsEndpoint(svc policies.Service) endpoint.Endpoint { if _, err := svc.AddPolicy(ctx, cr.token, policy); err != nil { return nil, err } + ps = append(ps, policy) } } - return policyRes{created: true}, nil + return policyRes{created: true, Policies: ps}, nil } } @@ -131,7 +133,7 @@ func updatePolicyEndpoint(svc policies.Service) endpoint.Endpoint { return nil, err } - return policyRes{policy, true}, nil + return policyRes{[]policies.Policy{policy}, true}, nil } } diff --git a/things/policies/api/http/responses.go b/things/policies/api/http/responses.go index d9bf0405a9..2143ac44c6 100644 --- a/things/policies/api/http/responses.go +++ b/things/policies/api/http/responses.go @@ -16,8 +16,8 @@ var ( ) type policyRes struct { - policies.Policy - created bool + Policies []policies.Policy `json:"policies"` + created bool } func (res policyRes) Code() int { diff --git a/things/policies/api/http/transport.go b/things/policies/api/http/transport.go index 233977cd55..8bae87b23c 100644 --- a/things/policies/api/http/transport.go +++ b/things/policies/api/http/transport.go @@ -109,6 +109,11 @@ func decodeDisconnectThing(_ context.Context, r *http.Request) (interface{}, err GroupID: bone.GetValue(r, "chanId"), ClientID: bone.GetValue(r, "thingId"), } + if r.Body != http.NoBody { + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + return nil, errors.Wrap(errors.ErrMalformedEntity, err) + } + } return req, nil } diff --git a/things/policies/page.go b/things/policies/page.go index 8007ac74af..fac221e8c5 100644 --- a/things/policies/page.go +++ b/things/policies/page.go @@ -10,11 +10,11 @@ type Page struct { Total uint64 Offset uint64 Limit uint64 - OwnerID string - Subject string - Object string - Action string - Metadata Metadata + OwnerID string `json:"owner,omitempty"` + Subject string `json:"subject,omitempty"` + Object string `json:"object,omitempty"` + Action string `json:"action,omitempty"` + Metadata Metadata `json:"metadata,omitempty"` } // Validate check page actions. diff --git a/users/clients/api/endpoints.go b/users/clients/api/endpoints.go index 2d8f81b237..a9a7e6874e 100644 --- a/users/clients/api/endpoints.go +++ b/users/clients/api/endpoints.go @@ -151,7 +151,7 @@ func updateClientTagsEndpoint(svc clients.Service) endpoint.Endpoint { func updateClientIdentityEndpoint(svc clients.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { - req := request.(updateClientCredentialsReq) + req := request.(updateClientIdentityReq) if err := req.validate(); err != nil { return nil, err } @@ -209,7 +209,7 @@ func passwordResetEndpoint(svc clients.Service) endpoint.Endpoint { func updateClientSecretEndpoint(svc clients.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { - req := request.(updateClientCredentialsReq) + req := request.(updateClientSecretReq) if err := req.validate(); err != nil { return nil, err } diff --git a/users/clients/api/requests.go b/users/clients/api/requests.go index 6f45f6c12e..c8319ece74 100644 --- a/users/clients/api/requests.go +++ b/users/clients/api/requests.go @@ -134,15 +134,13 @@ func (req updateClientOwnerReq) validate() error { return nil } -type updateClientCredentialsReq struct { - token string - id string - Identity string `json:"identity,omitempty"` - OldSecret string `json:"old_secret,omitempty"` - NewSecret string `json:"new_secret,omitempty"` +type updateClientIdentityReq struct { + token string + id string + Identity string `json:"identity,omitempty"` } -func (req updateClientCredentialsReq) validate() error { +func (req updateClientIdentityReq) validate() error { if req.token == "" { return apiutil.ErrBearerToken } @@ -152,6 +150,19 @@ func (req updateClientCredentialsReq) validate() error { return nil } +type updateClientSecretReq struct { + token string + OldSecret string `json:"old_secret,omitempty"` + NewSecret string `json:"new_secret,omitempty"` +} + +func (req updateClientSecretReq) validate() error { + if req.token == "" { + return apiutil.ErrBearerToken + } + return nil +} + type changeClientStatusReq struct { token string id string diff --git a/users/clients/api/transport.go b/users/clients/api/transport.go index 0e1542f06d..7b8e9068ee 100644 --- a/users/clients/api/transport.go +++ b/users/clients/api/transport.go @@ -59,6 +59,13 @@ func MakeClientsHandler(svc clients.Service, mux *bone.Mux, logger mflog.Logger) opts..., )) + mux.Patch("/users/secret", kithttp.NewServer( + otelkit.EndpointMiddleware(otelkit.WithOperation("update_client_secret"))(updateClientSecretEndpoint(svc)), + decodeUpdateClientSecret, + api.EncodeResponse, + opts..., + )) + mux.Patch("/users/:id", kithttp.NewServer( otelkit.EndpointMiddleware(otelkit.WithOperation("update_client_name_and_metadata"))(updateClientEndpoint(svc)), decodeUpdateClient, @@ -75,7 +82,7 @@ func MakeClientsHandler(svc clients.Service, mux *bone.Mux, logger mflog.Logger) mux.Patch("/users/:id/identity", kithttp.NewServer( otelkit.EndpointMiddleware(otelkit.WithOperation("update_client_identity"))(updateClientIdentityEndpoint(svc)), - decodeUpdateClientCredentials, + decodeUpdateClientIdentity, api.EncodeResponse, opts..., )) @@ -94,13 +101,6 @@ func MakeClientsHandler(svc clients.Service, mux *bone.Mux, logger mflog.Logger) opts..., )) - mux.Patch("/users/:id/secret", kithttp.NewServer( - otelkit.EndpointMiddleware(otelkit.WithOperation("update_client_secret"))(updateClientSecretEndpoint(svc)), - decodeUpdateClientCredentials, - api.EncodeResponse, - opts..., - )) - mux.Patch("/users/:id/owner", kithttp.NewServer( otelkit.EndpointMiddleware(otelkit.WithOperation("update_client_owner"))(updateClientOwnerEndpoint(svc)), decodeUpdateClientOwner, @@ -254,11 +254,11 @@ func decodeUpdateClientTags(_ context.Context, r *http.Request) (interface{}, er return req, nil } -func decodeUpdateClientCredentials(_ context.Context, r *http.Request) (interface{}, error) { +func decodeUpdateClientIdentity(_ context.Context, r *http.Request) (interface{}, error) { if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) { return nil, errors.ErrUnsupportedContentType } - req := updateClientCredentialsReq{ + req := updateClientIdentityReq{ token: apiutil.ExtractBearerToken(r), id: bone.GetValue(r, "id"), } @@ -269,6 +269,20 @@ func decodeUpdateClientCredentials(_ context.Context, r *http.Request) (interfac return req, nil } +func decodeUpdateClientSecret(_ context.Context, r *http.Request) (interface{}, error) { + if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) { + return nil, errors.ErrUnsupportedContentType + } + req := updateClientSecretReq{ + token: apiutil.ExtractBearerToken(r), + } + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + return nil, errors.Wrap(errors.ErrMalformedEntity, err) + } + + return req, nil +} + func decodePasswordResetRequest(_ context.Context, r *http.Request) (interface{}, error) { if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) { return nil, errors.ErrUnsupportedContentType