Overview
The Category service is the core API for managing categories. It supports back-office and administrative tasks using REST calls to list, view, create, edit, and delete category records.
Categories are tree structures that enable the assignment of resource references to categories. A resource reference is a data structure that points to another resource in the system, such as a product, and contains the ID and type of the referenced resource and the URL.
The Category API is a universal solution for categorization of various entities. It provides a scalable, fast, and easy-to-use back-end for:
- Storefronts (web and native apps) serving category trees.
- Back-office PCM and data-editing tools for categories.
- Systems integration using a flexible and rich information set that is centrally available through a well-defined API.
You can use a mashup service that consolidates data from multiple services and sources to serve up the presentation in the customer-facing systems. You can also use the Product Details service to merge category and price information with the core product record.
API Reference
/{tenant}/categories
/{tenant}/categories
Get categories.
Accepted scopes:
hybris.category_read_unpublished
- required to retrieve non-public categories. If not provided only published categories are returned
Create new category.
Accepted scopes:
hybris.category_create
- mandatoryhybris.category_publish
- required if category is created as published (by providingpublished
flagtrue
)
Deletes all categories.
Accepted scopes:
hybris.category_delete_all
- mandatory
/{tenant}/categories/{categoryId}
Retrieves a single category entity.
Accepted scopes:
hybris.category_read_unpublished
- required to retrieve non-public category
Updates a single category entity.
Accepted scopes:
hybris.category_update
- required to update category datahybris.category_publish
- required to publish the category (by settingpublished
flag totrue
)hybris.category_unpublish
- required to unpublish the category (by settingpublished
flag tofalse
)
Deletes a single category.
Accepted scopes:
hybris.category_delete
- mandatory
/{tenant}/categories/{categoryId}/assignments
Assignments of resource references to categories.
Assigns a resource reference to category.
Accepted scopes:
hybris.category_update
- mandatory
Get resource references assigned to the specified category.
Accepted scopes:
hybris.category_read_unpublished
- required to retrieve assignments of non-public category
Delete assignments.
Accepted scopes:
hybris.category_update
- mandatory
/{tenant}/categories/{categoryId}/assignments/{assignmentId}
Removes assignment of resource reference to the specified category.
Accepted scopes:
hybris.category_update
- mandatory
/{tenant}/categories/{categoryId}/media
Media files of the category.
Initialize process of creating new media file for category
Accepted scopes:
hybris.category_update
- mandatory
Return metadata of media files. The list is ordered according to the "position" attribute which was passed during media creation.
Accepted scopes:
hybris.category_read_unpublished
- required to retrieve media metadata of non-public categories
/{tenant}/categories/{categoryId}/media/{mediaId}
Return media file metadata by ID.
Accepted scope:
hybris.category_read_unpublished
- to retrieve media metadata of non-public category
Update media file metadata. Note that only part of the metadata field can be updated.
Accepted scopes:
hybris.category_update
- mandatory
Delete media identified by media ID.
Accepted scopes:
hybris.category_update
- mandatory
/{tenant}/categories/{categoryId}/media/{mediaId}/commit
Confirms that the media file specified by the media id is updated and ready to be used with category.
Accepted scope:
hybris.category_update
- required to attach media to category
Events
The topic owner client is: hybris.category
EVENT TYPE | DESCRIPTION | PAYLOAD SCHEMA | PAYLOAD EXAMPLE |
---|---|---|---|
category-created | Triggered when a category is successfully created. | schema |
|
category-updated | Triggered when a category is successfully updated. | schema |
|
category-deleted | Triggered when a category is successfully deleted. | schema |
|
assignment-created | Triggered when a resource reference is assigned to a category. | schema |
|
assignments-deleted | Triggered when a resource reference is unassigned from a category. | schema |
|
Scopes in the Category Service
Scopes let you specify exactly what type of access you need to resources and operations in the Category service.
The following table includes all the scopes that are supported by the Category service.
Scope | Description |
---|---|
hybris.category_read_unpublished | Use this scope to see the unpublished categories. |
hybris.category_create | Use this scope to create a new category. |
hybris.category_update | Use this scope to change the details of a category. |
hybris.category_delete | Use this scope to delete a category. |
hybris.category_delete_all | Use this scope to delete all categories. |
hybris.category_publish | Use this scope to publish a category so that it is visible to anonymous users. To do so, set the published property value to true . |
hybris.category_unpublish | Use this scope to unpublish a category. To do so, set the published property value to false . |
If a certain operation requires two scopes to be allowed, then your role will need to have these two scopes assigned. For example, to create a category and publish it simultaneously with one POST request, you need two scopes: hybris.category_create and hybris.category_publish.
This is an example of how to change some properties of the unpublished category and publish it at the same time:
- You want to change some of the category properties and publish it. To publish a category, your role needs to have the hybris.category_publish scope assigned to it. This allows you to change the published property from
false
totrue
. - However, the act of changing the category's properties (other than published property) is an update operation. The update operation requires the hybris.category_update scope.
- So, if you change certain category properties and publish an unpublished category by changing the published property to
true
at the same time, you need a role that has both the hybris.category_update and hybris.category_publish scopes.
- While creating a category, you can make it published or unpublished:
- To create an unpublished category, you only need the hybris.category_create scope.
- To create a published category, you need both the create hybris.category_create and hybris.category_publish scopes.
- Scopes are assigned to user roles. Users are assigned to user roles. A user role could be called a connection point between a scope and a user. As a result, you could be assigned to two user roles, where each role connects you to a separate scope, or you could be assigned to a single role that connects you to two scopes at once. The result would be the same: you could perform operations permitted by those two scopes.
For more information about the authorization and authentication used in SAP Hybris services, and also about the scopes in general, see:
Expanding Category in Response
You can use the expand query parameter to retrieve subcategories and assigned resource references.
Execute the GET method on the /{tenant}/categories
resources and add the expand parameter with the required value. You can also use other parameters to modify the results.
Querying parameter to expand returned data
Expand information on categories with assignments and subcategories
The expand parameter in the query, such as /categories?expand=assignments
or /categories?expand=subcategories
, enables you to specify whether assignments and subcategories should be included in the returned categories.
- Example
GET/categories?expand=assignments
This returns a plain list of all root categories and subcategories. The retrieved categories include a list of the assignments that belong to them.[ … { "id": "102400256", "name": "main1", "assignments": [ { "id": "1s0jhc-1oysjk-iz9-1oyt4w", "ref": { "id": "12", "type": "product", "url": "http://product-service/12" } }, … ] }, … ]
- Example
GET/categories?expand=subcategories
The requested categories contain all descendant categories up to the level specified by the depth query parameter. If the depth parameter is not set, then all descendants are returned.
[
...
{
"id": "102400256",
"name": "mainCatgory1",
"subcategories": [
{
"id": "102400512",
"parentId": "102400256",
"name": "subcategory1",
"subcategories": [
{
"id": "102400768",
"parentId": "102400512",
"name": "subsubcategory1"
}
]
}
]
}
...
]
- Query parameters can be combined. To retrieve top-level categories with descendants up to one level containing assignments, use the GET method on
/categories?expand=subcategories,assignments&toplevel=true&depth=1
. - The depth query parameter is ignored if the
?expand=subcategories
parameter is not provided.
Expand information on a single category
Similar to the GET request on /categories?expand=...
, the expand parameter can also be used to expand information for a single category specified in the URI by its id: /categories/{id}?expand=...
Additionally, when getting a single category, you can specify to get the resource mixins of all ancestor categories by setting the expand=inheritedResourceMixins
parameter.
Examples
Retrieve a single category with category and category ancestors resource properties
You can retrieve a specific category with the inheritedResourceMixins property, which contains a map of mixins inherited from ancestor categories:
- Keys of inheritedResourceMixins entries are the mixins namespaces.
- Values of inheritedResourceMixins entries are URL links that contain the JSON schema of each ancestor category resource properties.
To retrieve a category with the inheritedResourceMixins property, append the unique categoryId to the URL and use the expand=inheritedResourceMixins
query parameter.
For example, perform a GET request on https://api.beta.yaas.io/hybris/category/v1/{tenant}/categories/5555?expand=inheritedResourceMixins
.
The JSON sample below shows what is returned if the category named Smartphones has:
- The resourceMixins property, containing URL reference to the smartphoneSchema mixin
- At least two ancestor categories, both having the resourceMixins property with URL references to the telephoneSchema and electronicSchema mixins.
{
"id": "5555",
"parentId":"2345",
"name": "Smartphones",
"description": "Category containing all smartphones.",
"resourceMixins" : {
"smartphoneProperties":"https://api.beta.yaas.io/hybris/schema/v1/myShopProjectId/smartphoneSchema_v3"
},
"inheritedResourceMixins":{
"telephoneProperties":"https://api.beta.yaas.io/hybris/schema/v1/myShopProjectId/telephoneSchema_v2",
"electronicsProperties":"https://api.beta.yaas.io/hybris/schema/v1/myShopProjectId/electronicsSchema_v8"
}
}
Retrieve a single category with a parent category
You can retrieve a specific category with the parent property containing basic information about the parent category.
To retrieve a category with parent, append the unique categoryId to the URI and use the expand=parent
query parameter.
For example, perform a GET request on https://api.beta.yaas.io/hybris/category/v1/{tenant}/categories/5555?expand=parent
.
The JSON sample below shows what is returned if the category with an id of 5555
and a name of Smartphones
has a parent category named Telephones
:
{
"id": "5555",
"parentId": "2345",
"name": "Smartphones",
"description": "Category containing all smartphones.",
"resourceMixins" : {
"smartphoneProperties":"https://api.beta.yaas.io/hybris/schema/v1/myShopProjectId/smartphoneSchema_v3"
},
"parent":{
"id": "2345",
"parentId": "1233",
"name": "Telephones",
"description": "Category containing all telephones.",
"resourceMixins" : {
"smartphoneProperties":"https://api.beta.yaas.io/hybris/schema/v1/myShopProjectId/telephoneSchema_v2"
}
}
}
/categories?expand=subcategories,parent
resource, then only the queried category will be returned with the additional parent property. Subcategories and their descendants will not have the parent property filled, as the information about the parent is already included in the response. This is to avoid duplication and improve performance.The next sample shows what is to be returned if the category named Smartphones has a parent category named Telephones and child categories IPhone and Samsung:
{
"id": "5555",
"parentId": "2345",
"name": "Smartphones",
"description": "Category containing all smartphones.",
"resourceMixins" : {
"smartphoneProperties":"https://api.beta.yaas.io/hybris/schema/v1/myShopProjectId/smartphoneSchema_v3"
},
"parent":{
"id": "2345",
"parentId": "1233",
"name": "Telephones",
"description": "Category containing all telephones.",
"resourceMixins" : {
"smartphoneProperties":"https://api.beta.yaas.io/hybris/schema/v1/myShopProjectId/telephoneSchema_v2"
}
},
"subcategories": [
{
"id": "777854",
"parentId": "5555",
"name": "IPhone",
"resourceMixins" : {
"iphoneProperties":"https://api.beta.yaas.io/hybris/schema/v1/myShopProjectId/iphoneSchema_v1"
}
},
{
"id": "739454",
"parentId": "5555",
"name": "Samsung",
"resourceMixins" : {
"samsungProperties":"https://api.beta.yaas.io/hybris/schema/v1/myShopProjectId/samsungSchema_v2"
}
}
]
}
Note that the IPhone and Samsung subcategories do not have an additional parent property provided, however, users can easily read the parent data as they are provided in the response.
Retrieve a Single Category with Parent Category and its Ancestors
You can retrieve a specific category with the parent property containing:
- Basic information about parent category
- Basic information of all its ancestors
To retrieve details of a category, including its parent category and parent's ancestor categories, append the unique categoryId to the URL and use the expand=parent
and parent.recursive=true
query parameters.
For example, perform GET request on https://api.beta.yaas.io/hybris/category/v1/{tenant}/categories/5555?expand=parent&parent.recursive=true
.
The example below shows what should be returned if the category named Smartphones has a parent category named Telephones, which has its own parent category named Electronics:
{
"id": "5555",
"parentId": "2345",
"name": "Smartphones",
"description": "Category containing all smartphones.",
"resourceMixins" : {
"smartphoneProperties":"https://api.beta.yaas.io/hybris/schema/v1/myShopProjectId/smartphoneSchema_v3"
},
"parent":{
"id": "2345",
"parentId": "1233",
"name": "Telephones",
"description": "Category containing all telephones.",
"resourceMixins" : {
"smartphoneProperties":"https://api.beta.yaas.io/hybris/schema/v1/myShopProjectId/telephoneSchema_v2"
},
"parent":{
"id": "1233",
"name": "Electronics",
"description": "Category containing all electronics.",
"resourceMixins" : {
"smartphoneProperties":"https://api.beta.yaas.io/hybris/schema/v1/myShopProjectId/electronicsSchema_v8"
}
}
}
}
Sorting
You can sort all retrieved categories using the position property. To sort these categories, append the sort query parameter to the request URL. The results will be sorted. You can set the results in ascending or descending order by using asc or desc as the suffix.
?sort=position:asc
?sort=position:desc
You can also sort all subcategories using the additional expand=subcategories
URL query parameter.
Currently, only sorting by the position property is supported.
Categories and Mixins
This section supplements the information about extending categories provided in the Category Extensibility tutorial, available through the navigation menu to the left.
General notes
- You can extend a category with additional properties by specifying mixins that define these properties.
- A single category can use many mixins.
- You can assign one mixin to many categories.
- Provide each URL for a mixin definition in the metadata.mixins section, as defined in the category schema.
Inheritance
- Categories can have subcategories, but subcategories do not inherit mixins.
- You can have an extended category that has a subcategory, but the mixin-based properties are not available in the subcategory.
- To include the category's attributes in the subcategory, separately extend the subcategory with the mixin.
Localization
- You can define the localization language in the optional content-language header. The header provides the language code for the localized simple string attributes. If you do not provide the content-language header, the service uses the default language.
- The value in the content-language header only applies to the category's basic attributes. The mixin-based attributes are not localized.
Delete Assignments from Category
As a merchant with the proper scope, you can remove a resource reference that is assigned to a category. You can remove all references assigned to a category at once, or you can use query parameters to narrow the references being removed.
You can narrow references affected by this request with query parameters, as shown in this example:
https://api.beta.yaas.io/hybris/category/v1/{tenant}/categories/{categoryId}/assignments?ref.id={refId}&ref.type={refType}
You can use ref.id and ref.type query parameters to provide more restrictions on the resource references to be removed from the category. You can also execute the DELETE method without any query parameters. These examples show the results that are returned using different query parameters:
- To remove all references from the category, send this request:
DELETE/{tenant}/category/{categoryId}/assignments
- To remove all references of type {refType}, send this request:
DELETE/{tenant}/category/{categoryId}/assignments?ref.type={refType}
- To remove one specific reference, both {refType} and {refId} must be provided:
DELETEcategory/{categoryId}/assignments?ref.type={refType}&ref.id={refId}
If you know the id of a particular assignment you want to delete, you should use the approach described in Delete Assignment from Category.
/{tenant}/category?ref.id=111&ref.id=222&ref.id=333
, only the first parameter that is passed is taken into account. The other parameters are not used.Category Retrieval
This topic supplements the interactive tutorial and provides details about retrieving categories, including the headers and query parameters you can use in the tutorial request example, as well as the information provided in the response.
Available headers to use in the tutorial
You can use these headers in the tutorial examples:
- accept-language: Use this header to restrict the set of natural languages that are preferred in the response. You can provide fallback language codes separated by commas. You can give each language-range an associated quality value that represents an estimate of the user's preference for the languages specified by that range. The quality value default is
q=1
. - hybris-languages: Use the asterisk
*
character to get all available translations of localizable attributes.
Query parameters to limit returned cateogries
You can limit the set of returned categories with these query parameters:
- ref.type: Use this parameter to find categories that contain references to the specified resource type. For example:
https://api.beta.yaas.io/hybris/category/v1/{tenant}/categories?ref.type=product
- ref.type and ref.id: Use these parameters to find categories that contain references with the specific resource type and ID. For example:
https://api.beta.yaas.io/hybris/category/v1/{tenant}/categories?ref.type=product&ref.id=xpz2
- expand: Use this parameter to request additional data to return with the categories. Valid values are
subcategories
,assignments
, andinheritedResourceMixins
. - toplevel: When this parameter is set to
true
, then only the top-level categories are returned.
Response header and body
The response header and body include these details:
- Header: The hybris-count response header holds the total number of categories that the GET method returns.
- Body: The response body contains all requested categories from the current tenant. The service returns only those category fields that have a value and does not return empty fields.
Category Movements
This section supplements the Moving Categories tutorial and includes details about categories, category levels, and parent and child categories. Keep these details in mind when altering the location and level of categories.
Category movement methods and functionality
You can move any category. To do so, specify:
- the category you want to move in the URL path parameter
- the new parent category, using the parentId property of the category you move
To set any category of any level as a top-level category, use one of these methods:
- Perform a full update of the category without providing the parentId in the body. Optionally, you can set the parentId to
null
. During the update, the service removes the category from its current location to a top-level category location. - Run a partial update and set the parentId attribute to
null
. Because a partial update modifies only the selected, or provided properties, the remaining properties remain unchanged.
To change the position of categories within a category tree, update the category in question. You can update categories in two ways:
- Full update: No query parameter required.
- Partial update: Query parameter required.
The Category service always validates whether the category identified by the parentId exists. If it does not, then the service returns an error. Additionally, the application prevents you from creating loops in the structure of the categories. For example, you cannot move or change a category descendant into its own parent category.
Subcategory movement
When you move a category, any subcategories move along with the parent category. The category keeps all assigned resource references. A category can have only one parent category. If you specify a new parentId, the service automatically overrides the previous parentId.
Moving Categories tutorial details
The Moving Categories tutorial, available from the navigation menu, provides examples of how to move categories, and what happens if you try to give a category a non-existing parent, or inadvertently create a loop. The diagrams shown illustrate the organization of the categories used in the examples, at the start of the tutorial and at the end.
The original organization of the category tree used in the Moving Categories tutorial:
The final organization of the category tree used in the Moving Categories tutorial:
Basics
Introduction
Imagine you run a shop with huge diversity of goods. You can just put them all together and sell them without categories. But if you do so, will your customers be able to find anything of interest, at least in a realistic period of time? With so many products, a realistic search would be impossible. The Category service allows you to put items into a group of similar items, with the ability to create categories.
Setup
Assertion
Define variable assert:
assert = chai.assert;
Get access token
To perform any operations with a specific service, you always need an access token. For this purpose, create an API Client for the OAuth2 service:
API.createClient('oAuth2Service',
'/services/oauth2/v1/api.raml');
Now, get the token:
tenant = projectIdPlaceholder;
AccessToken = oAuth2Service.token.post({
'client_id' : clientIdPlaceholder,
'client_secret':clientSecretPlaceholder,
'grant_type' : 'client_credentials',
'token_type': 'Bearer',
'scope': 'hybris.tenant='+tenant+ ' hybris.category_create hybris.category_publish hybris.category_delete hybris.category_delete_all hybris.category_update hybris.category_read_unpublished'
});
To make the calls simple and the code clean, assign the access token to a variable:
access_token = AccessToken.body.access_token;
Create an API client for the Category service
API.createClient('categoryService',
'/services/category/v1/api.raml');
Cleanup
Before you create new category for the tutorial examples, delete all categories in the project:
response = categoryService.tenant(tenant).categories.delete({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json'
}
}
);
assert.equal(response.status, 204);
response;
Examples
The next sections outline the basic operations that the Category service provides, and allow you to learn the operations by running small, practical code samples.
Create a new category
When you begin, there are no categories. All items you have in your store might belong to a simple, uniform set. To differentiate one item from another, you must identify the differences between items and specify sets of items.
Creating a new category is a simple operation. Add the Category details to the payload, and make a call. You can read everything you need to know about the payload in the Details section. The Content-Language header used in our call is explained in another Category service tutorial. For now, use this example to create a category:
response = categoryService.tenant(tenant).categories.post({
'name': 'Shoes',
'code': 'shoes',
'description': 'All kinds of shoes.',
'position': 0
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json',
'Content-Language': 'en'
}
}
);
assert.equal(response.status, 201);
response;
As you can observe, the returned status code tells you whether you successfully created the category.
To retrieve or update a category, you need to know the category id value. Keep the id of the category you just created in a variable for further use.
shoesCategoryId = response.body.id;
Retrieve a single category
Use the category id, now stored in a variable, to retrieve details for a single category. You only need to know the id of the category you want to retrieve.
The Accept-Language header, which you can use to retrieve the language version of localized attributes, is described in further detail in other tutorials.
response = categoryService.tenant(tenant).categories.categoryId(shoesCategoryId).get({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json',
'Accept-Language': 'en'
}
}
)
assert.equal(response.status, 200);
assert.equal(response.body.id, shoesCategoryId);
assert.equal(response.body.code, 'shoes');
assert.equal(response.body.name, 'Shoes');
assert.equal(response.body.description, 'All kinds of shoes.');
response;
This simple request returns all the category attributes that you set when you created the category. It also returns an additional attribute that serves as a unique identifier for a category. This service automatically creates this identifier for each category upon creation and remains constant throughout the category's lifecycle.
The localized attributes, if any, are returned in the language specified in the header. Other, non-localized attributes return as defined.
Update a category
You can modify categories as needed, adding and removing attributes. For example, you can update a category to extend your category description, and change the position of the category.
To update any category, use its id. In the example, the id is stored in the shoesCategoryId variable, which you created in the first example in this tutorial.
Change the description and position attributes in the category definition and set the new, updated content in the payload. The payload includes all attributes included in the original category. During the update, you must replace the whole definition with a new definition that has some updated attributes and some unchanged attributes. The final result, however, is that the category is modified the way you want it to be.
response = categoryService.tenant(tenant).categories.categoryId(shoesCategoryId).put({
'code': 'shoes',
'name': 'Shoes',
'description': 'All kinds of shoes for sale.',
'position': 1
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json',
'Content-Language': 'en'
}
}
)
assert.equal(response.status, 200);
response;
The status code 200
tells you the update was successful. To verify, you can always retrieve the category and check its details.
To verify the accuracy of the latest update, retrieve the updated category:
response = categoryService.tenant(tenant).categories.categoryId(shoesCategoryId).get({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json',
'Accept-Language': 'en'
}
}
)
assert.equal(response.status, 200);
assert.equal(response.body.id, shoesCategoryId);
assert.equal(response.body.code, 'shoes');
assert.equal(response.body.name, 'Shoes');
assert.equal(response.body.description, 'All kinds of shoes for sale.');
assert.equal(response.body.position, '1');
response;
The category is still Shoes. The only attributes with new values are those you just updated: description and position.
Delete a single category
You have created, retrieved, and updated a category. What if you no longer need the category? You can delete a category using its id, as shown:
response = categoryService.tenant(tenant).categories.categoryId(shoesCategoryId).delete({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json'
}
}
);
assert.equal(response.status, 204);
response;
When the operation is successful, the service returns the status code 204
and the category is no longer available. To verify, you can try to retrieve the deleted category. If the category still exists, the service returns the category details.
response = categoryService.tenant(tenant).categories.categoryId(shoesCategoryId).get({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json',
'Accept-Language': 'en'
}
}
)
assert.equal(response.status, 404);
response;
The status code 404
indicates the category is deleted.
Moving Categories
In the Category service, parent categories are not fixed, and you can move a category at any time, to best suit your needs. That means you can define the most logical, clear, and convenient organization for your customers to browse and locate items in an intuitive and effective way.
The examples in this tutorial use a shop that sells computers, accessories, components, peripherals, and other electronic items. For this exercise, you will create several categories in a hierarchical tree structure with parent and child categories, and then recategorize your products as necessary.
Setup
Assert variables as shown.
Assertion
Define variable assert:
assert = chai.assert;
Get an access token
To perform any operation with a specific service, you need an access token. For this purpose, create an API Client for the OAuth2 service:
API.createClient('oAuth2Service',
'/services/oauth2/v1/api.raml');
Get the token:
tenant = projectIdPlaceholder;
AccessToken = oAuth2Service.token.post({
'client_id' : clientIdPlaceholder,
'client_secret':clientSecretPlaceholder,
'grant_type' : 'client_credentials',
'token_type': 'Bearer',
'scope': 'hybris.tenant='+tenant+ ' hybris.category_create hybris.category_publish hybris.category_delete hybris.category_delete_all hybris.category_update hybris.category_read_unpublished'
});
To make the calls simple and the code clean, assign the access token to a variable:
access_token = AccessToken.body.access_token;
Create an API client for the Category service
API.createClient('categoryService',
'/services/category/v1/api.raml');
Cleanup
Before you create new categories for the tutorial examples, clean up the project:
response = categoryService.tenant(tenant).categories.delete({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json'
}
}
);
assert.equal(response.status, 204);
response;
Create a category tree
You can create a category tree with many levels. A category can have only one parent, but many child categories. In this exercise, you will create a category tree with three parent levels and some child categories:
- Computers - Components - Mice - Computer Bags
- Computers - Peripherals - CPU Processors
- Computers - Accessories
You might notice that the category tree is inaccurate. For example, mice are peripherals, not components; CPU processors are components, not peripherals; computer bags are not a subcategory of mice. Because the Category service is flexible, you can move a subcategory to a more suitable parent category at any time. Later in this tutorial, you will move the categories to correct these errors.
Create the Computer category
response = categoryService.tenant(tenant).categories.post({
'name': 'Computers',
'code': 'computers',
'description': 'Computers and all the stuff for you.'
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json',
'Content-Language': 'en'
}
}
);
assert.equal(response.status, 201);
computersCatId = response.body.id;
Create the Components category
response = categoryService.tenant(tenant).categories.post({
'name': 'Components',
'code': 'components',
'description': 'All kinds of components for classy computers.',
'parentId': computersCatId
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json',
'Content-Language': 'en'
}
}
);
assert.equal(response.status, 201);
componentsCatId = response.body.id;
Create the Peripherals category
response = categoryService.tenant(tenant).categories.post({
'name': 'Peripherals',
'code': 'peripherals',
'description': 'All kinds of peripheral items, extending the functionality of your computers.',
'parentId': computersCatId
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json',
'Content-Language': 'en'
}
}
);
assert.equal(response.status, 201);
peripheralsCatId = response.body.id;
Create the Accessories category
response = categoryService.tenant(tenant).categories.post({
'name': 'Accessories',
'code': 'accessories',
'description': 'All accessories for your computer.',
'parentId': computersCatId
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json',
'Content-Language': 'en'
}
}
);
assert.equal(response.status, 201);
accessoriesCatId = response.body.id;
Create the CPU Processors category
response = categoryService.tenant(tenant).categories.post({
'name': 'CPU Processors',
'code': 'cpu_processors',
'description': 'Powerful processors for classy and efficient computers.',
'parentId': peripheralsCatId
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json',
'Content-Language': 'en'
}
}
);
assert.equal(response.status, 201);
cpuProcessorsCatId = response.body.id;
Create the Mice category
response = categoryService.tenant(tenant).categories.post({
'name': 'Mice',
'code': 'mice',
'description': 'Sophisticated mice for players and professionals.',
'parentId': componentsCatId
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json',
'Content-Language': 'en'
}
}
);
assert.equal(response.status, 201);
miceCatId = response.body.id;
Create the Computer Bags category
response = categoryService.tenant(tenant).categories.post({
'name': 'Computer Bags',
'code': 'computer_bags',
'description': 'Sophisticated bags for players and professionals.',
'parentId': miceCatId
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json',
'Content-Language': 'en'
}
}
);
assert.equal(response.status, 201);
computerBagsCatId = response.body.id;
Move a category using a full update
In this exercise, correct the inaccuracies in the category structure by moving the Mice and CPU Processors categories to new locations in the category tree. To move a category, change its parentId property. For a full update, provide all category properties, but modify the parentId only, as shown in the examples that follow.
Currently, the categories are:
- Computers - Components - Mice - Computer Bags
- Computers - Peripherals - CPU Processors
- Computers - Accessories
After you complete this exercise, the categories will have this structure:
- Computers - Components - CPU Processors
- Computers - Peripherals - Mice - Computer Bags
- Computers - Accessories
Move CPU Processors to Components
response = categoryService.tenant(tenant).categories.categoryId(cpuProcessorsCatId).put({
'name': 'CPU Processors',
'code': 'cpu_processors',
'description': 'Powerful processors for classy and efficient computers.',
'parentId': componentsCatId
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json',
'Content-Language': 'en'
}
}
);
assert.equal(response.status, 200);
Move Mice to Peripherals
response = categoryService.tenant(tenant).categories.categoryId(miceCatId).put({
'name': 'Mice',
'code': 'mice',
'description': 'Sophisticated mice for players and professionals.',
'parentId': peripheralsCatId
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json',
'Content-Language': 'en'
}
}
);
assert.equal(response.status, 200);
Verify that the updates are successful:
response = categoryService.tenant(tenant).categories.categoryId(cpuProcessorsCatId).get({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json',
'Accept-Language': 'en'
}
}
)
assert.equal(response.status, 200);
assert.equal(response.body.id, cpuProcessorsCatId);
assert.equal(response.body.parentId, componentsCatId);
response = categoryService.tenant(tenant).categories.categoryId(miceCatId).get({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json',
'Accept-Language': 'en'
}
}
)
assert.equal(response.status, 200);
assert.equal(response.body.id, miceCatId);
assert.equal(response.body.parentId, peripheralsCatId);
Move a category using a partial update
Now the CPU Processors and Mice categories are in the correct locations, but the Computer Bags category is still a subcategory of Mice. In this exercise, you perform a partial update to move the Computer Bags category. You will use a query parameter and send only the parentId property, with a new parent category value.
Currently, the categories are:
- Computers - Components - CPU Processors
- Computers - Peripherals - Mice - Computer Bags
- Computers - Accessories
After you complete this exercise, the categories will have this structure:
- Computers - Components - CPU Processors
- Computers - Peripherals - Mice
- Computers - Accessories - Computer Bags
Follow the example shown to update the parent category:
response = categoryService.tenant(tenant).categories.categoryId(computerBagsCatId).put({
'parentId': accessoriesCatId
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json',
'Content-Language': 'en'
},
query: {
'partial': 'true'
}
}
);
assert.equal(response.status, 200);
Verify whether the update is successful:
response = categoryService.tenant(tenant).categories.categoryId(computerBagsCatId).get({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json',
'Accept-Language': 'en'
}
}
)
assert.equal(response.status, 200);
assert.equal(response.body.id, computerBagsCatId);
assert.equal(response.body.parentId, accessoriesCatId);
Validation
When you update categories, the Category service first verifies that the parent category exists, then updates the child category accordingly. However, if you try to update the parentId property with a category id that does not exist, the service returns an error, as shown.
response = categoryService.tenant(tenant).categories.categoryId(computerBagsCatId).put({
'parentId': 'superTrooperAccesories'
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json',
'Content-Language': 'en'
},
query: {
'partial': 'true'
}
}
);
assert.equal(response.status, 400);
Category loop prevention
The service prevents you from creating loops in the category structure. You cannot update any category descendant to be its own parent. For example, in the final version of the category tree in this tutorial, the Components category is the parent of CPU Processors: Computers - Components - CPU Processors. If you try to set the parentId of Components to the CPU Processors category, the service does not perform the update and returns a 400
error.
response = categoryService.tenant(tenant).categories.categoryId(componentsCatId).put({
'parentId': cpuProcessorsCatId
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json',
'Content-Language': 'en'
},
query: {
'partial': 'true'
}
}
);
assert.equal(response.status, 400);
Retrieving Categories
Introduction
Imagine you run a shop with huge number of categorized goods. You have many categories, with subcategories, thus creating complex structures. This tutorial describes how to retrieve all or some categories to help you keep track of, and maintain, your categories.
Setup
Assertion
Define variable assert:
assert = chai.assert;
Get an access token
To perform any operations with a specific service, you always need an access token. For this purpose, create an API Client for the OAuth2 service:
API.createClient('oAuth2Service',
'/services/oauth2/v1/api.raml');
Now, get the token:
tenant = projectIdPlaceholder;
AccessToken = oAuth2Service.token.post({
'client_id' : clientIdPlaceholder,
'client_secret':clientSecretPlaceholder,
'grant_type' : 'client_credentials',
'token_type': 'Bearer',
'scope': 'hybris.tenant='+tenant+ ' hybris.category_create hybris.category_publish hybris.category_delete hybris.category_delete_all hybris.category_update hybris.category_read_unpublished'
});
ProductAccessToken = oAuth2Service.token.post({
'client_id' : clientIdPlaceholder,
'client_secret':clientSecretPlaceholder,
'grant_type' : 'client_credentials',
'token_type': 'Bearer',
'scope': 'hybris.tenant='+tenant+' hybris.product_read_unpublished hybris.product_create hybris.product_update hybris.product_delete hybris.product_delete_all'
});
To make the calls simple and the code clean, assign the access token to a variable:
access_token = AccessToken.body.access_token;
Additionally, you can store the product access token in another variable:
product_access_token = ProductAccessToken.body.access_token;
Create an API client for the Category service
API.createClient('categoryService',
'/services/category/v1/api.raml');
Create an API client for the Product service
API.createClient('productService',
'/services/product/v2/api.raml');
Cleanup
Before you create new categories for the tutorial examples, clean up the project for a fresh start:
response = categoryService.tenant(tenant).categories.delete({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json'
}
}
);
assert.equal(response.status, 204);
response;
response = productService.tenant(tenant).products.delete({}, {
headers: {
'Authorization': 'Bearer ' + product_access_token,
'Content-type' : 'application/json'
}
}
);
assert.equal(response.status, 204);
response;
Examples
In this section, retrieve some categories and category structures. To do so, you need to have some useful data. Start by creating a few categories that will serve you later.
Category: Shoes
response = categoryService.tenant(tenant).categories.post({
'name': 'Shoes',
'code': 'shoes',
'description': 'All kinds of shoes.',
'position': 0
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json',
'Content-Language': 'en'
}
}
);
assert.equal(response.status, 201);
response;
The returned status code informs you whether you successfully created a category. Store the id of the category you created in a variable for further use:
shoesCategoryId = response.body.id;
Category: Gloves
response = categoryService.tenant(tenant).categories.post({
'name': 'Gloves',
'code': 'gloves',
'description': 'All kinds of gloves.',
'position': 0
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json',
'Content-Language': 'en'
}
}
);
assert.equal(response.status, 201);
response;
Store the new id for further use:
glovesCategoryId = response.body.id;
Retrieve a flat category list
Retrieve all of your categories to get a glimpse into the list.
response = categoryService.tenant(tenant).categories.get({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json',
'Accept-Language': 'en'
}
}
)
assert.equal(response.status, 200);
assert.equal(response.body.length, 2);
assert.sameMembers([response.body[0].code, response.body[1].code], ['shoes', 'gloves']);
response;
Use a query parameter to retrieve categories
In this exercise, use a query parameter to retrieve categories. You can find the available query parameters in the API console for this service. This example uses the expand:assignments
parameter and value. With the expand query parameter set to assignments
, you can get the categories and assignments in one call. This parameter, however, does not let you get assignments from subcategories.
First, create a product to assign to a category:
response = productService.tenant(tenant).products.post({
'code': 'gnocci',
'name': 'Gnocci',
'description': 'Gnocci - classy handmade shoes for everybody.'
}, {
headers: {
'Authorization': 'Bearer ' + product_access_token,
'Content-Type' : 'application/json',
'Content-Language': 'en'
}
}
)
response;
Assign the id of the returned object to a variable:
gnocciId = response.body.id;
Assign the link of the returned object to a variable:
gnocciUrl = response.body.link;
Now, assign the product to a category:
response = categoryService.tenant(tenant).categories.categoryId(shoesCategoryId).assignments.post({
"ref" :
{
"id": gnocciId,
"type": "product",
"url": gnocciUrl
}
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json',
'Content-Language': 'en'
}
}
);
assert.equal(response.status, 201);
response;
At this point, you have two categories in the tenant. One category contains an assignment. Retrieve all of the categories in the tenant using the query parameter and value expand=assignments
.
response = categoryService.tenant(tenant).categories.get({
'q' : 'expand:assignments'
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json',
'Accept-Language': 'en'
}
}
)
assert.equal(response.status, 200);
response;
Retrieve top-level categories
To retrieve only top-level categories, use the query parameter toplevel. If you set the toplevel parameter to true
, the service returns only parent categories.
response = categoryService.tenant(tenant).categories.get({
'q' : 'toplevel:true'
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json',
'Accept-Language': 'en'
}
}
)
assert.equal(response.status, 200);
response;
Retrieve all categories with a specified descendant level
In this exercise, create a gloves subcategory called, which you will use later in this tutorial.
response = categoryService.tenant(tenant).categories.post({
'name': 'children Gloves',
'code': 'children_gloves',
'description': 'All kinds of gloves for children.',
'parentId': glovesCategoryId
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json',
'Content-Language': 'en'
}
}
);
assert.equal(response.status, 201);
response;
Store the new id for later use:
childrenGlovesCategoryId = response.body.id;
Now that you have a category and a subcategory, retrieve the top-level categories and their descendant(s), by using the expand=subcategories
query parameter and value. The service returns a subcategory tree in the subcategories field of each category. If the category hierarchy is large, the amount of data returned can negatively affect performance. To mitigate performance issues, use the depth query parameter, which accepts a numerical value that limits the depth of the subcategory levels returned. In this example, however, you do not have such a complex structure, so you do not need the depth parameter.
response = categoryService.tenant(tenant).categories.get({
'q' : 'toplevel:true,expand:subcategories,depth=1'
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json',
'Accept-Language': 'en'
}
}
)
assert.equal(response.status, 200);
response;
To get a complete tree structure, provide only these query parameters: toplevel=true
and expand=subcategories
. Without the depth parameter, the service returns all categories and subcategories.
Retrieve a single category with a specified descendant level
You can retrieve a specific category and its descendant subcategories. However, before you retrieve the category with all its subcategories, create one more subcategory to add one more level to the category tree so that you can see the difference between the results of this example and the previous one. Because children's gloves are often very colorful, make a colorful subcategory.
response = categoryService.tenant(tenant).categories.post({
'name': 'Rainbow Hued Children Gloves',
'code': 'rainbow_hued_children_gloves',
'description': 'Rainbow-hued gloves for children with imagination.',
'parentId': childrenGlovesCategoryId
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json',
'Content-Language': 'en'
}
}
);
assert.equal(response.status, 201);
response;
Store the new id for further use:
childrenRainbowGlovesCategoryId = response.body.id;
Now you are ready to get all categories you created in this tutorial. Use the unique categoryId in the URL. Next, use the expand=subcategories
and depth query parameters to specify the level of descendants to retrieve. While you could get assignments together with the category definition by using the query parameter expand=assignments, the service returns only the assignments for the queried category.
response = categoryService.tenant(tenant).categories.categoryId(glovesCategoryId).get({
'q' : 'expand:subcategories,depth=2'
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json',
'Accept-Language': 'en'
}
}
)
assert.equal(response.status, 200);
response;
Media
Introduction
Having a shop with a wide selection of wares, you might assign your products to categories that you can organize into very complex structures. You can describe these categories with many properties and information that helps you to see the differences between categories. You can also use some visual elements to accentuate the differences between categories, or to visually express a category to the customer. You can, for example, assign an image that contains the category's brand logo, appealing to a specific target group among your customers.
Setup
Assertion
Define variable assert:
assert = chai.assert;
Get an access token
To perform any operations with a specific service, you always need an access token. For this purpose, create an API Client for the OAuth2 service:
API.createClient('oAuth2Service',
'/services/oauth2/v1/api.raml');
Now, get the token:
tenant = projectIdPlaceholder;
AccessToken = oAuth2Service.token.post({
'client_id' : clientIdPlaceholder,
'client_secret':clientSecretPlaceholder,
'grant_type' : 'client_credentials',
'token_type': 'Bearer',
'scope': 'hybris.tenant='+tenant+' hybris.category_read_unpublished hybris.category_create hybris.category_update hybris.category_delete hybris.category_delete_all hybris.category_publish hybris.category_unpublish'
});
To make the calls simple and the code clean, assign the id of the returned object to a variable:
access_token = AccessToken.body.access_token;
Create an API client for the Category service
API.createClient('categoryService',
'/services/category/v1/api.raml');
Create an API client for the Media service
API.createClient('mediaService',
'/services/media/v2/api.raml');
Cleanup
Before you create new categories for the tutorial examples, delete all categories in the project:
response = categoryService.tenant(tenant).categories.delete({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json'
}
}
);
assert.equal(response.status, 204);
response;
Examples
Create simple categories
To start, create a category that you can use in the examples throughout this tutorial. The examples demonstrate what the Category service provides and show how the service handles media.
Create and define two basic categories without any media.
Define one category for summer shoes:
response = categoryService.tenant(tenant).categories.post({
'name': 'Summer Shoes',
'code': 'summer_shoes',
'description': 'All kinds of shoes for a sunny summer.',
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json',
'Content-Language': 'en'
}
}
);
assert.equal(response.status, 201);
response;
To make the calls simple and the code examples clean, assign the id of the returned object to a summerShoes variable:
summerShoes = response.body.id;
Now, make a category for winter shoes:
response = categoryService.tenant(tenant).categories.post({
'name': 'Winter Shoes',
'code': 'winter_shoes',
'description': 'All kinds of shoes for a snowy winter.',
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json',
'Content-Language': 'en'
}
}
);
assert.equal(response.status, 201);
response;
As with the summer shoes category, store the id of the returned object in a variable. This time, the variable is winterShoes:
winterShoes = response.body.id;
Create media for a category
Pictures can sometimes say more than any word. Why not add media to your category? You can create and store media internally, in the YaaS media repository, and bind your media to categories, so that it visually appeals to your customers.
You can create media for empty categories, and add media to categories that contain media. Within a category, media are ordered according to the position property of each media item. If you do not include this property, each new media item is added to the end of the list.
Here are the example scenarios for creating media, described in the tutorials that follow:
- Create the first media item with a defined position
- Create the first media item without a defined position
- Create an additional media item without a defined position
- Create an additional media with a defined position
Creating the media item for a category consists of three steps. To avoid unnecessary repetition, this "three-step process" is described, in full, in the first scenario, Create the first media item with a position. After you complete the three-step process, the tutorial provides an example you can use to add the three steps to a function for quick use in the later scenarios.
Create the first media item with a position
In this tutorial, create a media item for a category that does not have any media. In this scenario, you define the position property of the media item. The first three labeled steps are the three-step process, followed by a step that allows you to add the steps to a function for later use.
Step 1
Create the upload link, which you will use later to upload the media item. To do so, you need:
response = categoryService.tenant(tenant).categories.categoryId(summerShoes).media.post({
'contentType' : 'image/gif',
'position' : 2,
'tags' : ['one']
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json'
}
}
)
assert.equal(response.status, 200);
mediaId = response.body.id;
uploadLink = response.body.uploadLink;
response;
Step 2
Use the PUT method to add a media item to the link you created and upload it to the service.
var status = jQuery.ajax({
url: uploadLink,
type: 'PUT',
contentType: 'image/gif',
data: atob('R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='),
processData: false,
async: false
}).status;
assert.equal(status, 200);
status;
Step 3
Confirm the upload is successful and receive the link to the created media item. No payload body is required in this step. All of the necessary information is already in the request URL and the headers.
response = categoryService.tenant(tenant).categories.categoryId(summerShoes).media.mediaId(mediaId).commit.post({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json',
'Content-Language': 'en'
}
}
)
assert.equal(response.status, 202);
link = response.body.link;
response;
true
, are added to a category but not yet committed.Add the three-step process to a function
For simplicity's sake, you can now add the three-step process to a function for later use:
//Step one
var createMediaForCategory = function(categoryId, position, tagName) {
var requestBody = {'contentType' : 'image/gif', 'tags' : [tagName]};
if (position != null) {
requestBody.position = position;
}
response = categoryService.tenant(tenant).categories.categoryId(categoryId).media.post(requestBody, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json'
}
}
);
assert.equal(response.status, 200);
var mediaId = response.body.id;
uploadLink = response.body.uploadLink;
//Step two
var status = jQuery.ajax({
url: uploadLink,
type: 'PUT',
contentType: 'image/gif',
data: atob('R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='),
processData: false,
async: false
}).status;
assert.equal(status, 200);
//Step three
response = categoryService.tenant(tenant).categories.categoryId(categoryId).media.mediaId(mediaId).commit.post({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json',
'Content-Language': 'en'
}
}
);
assert.equal(response.status, 202);
var mediaLink = response.body.link;
return {"mediaLink":mediaLink, "mediaId": mediaId};
};
What happens if you set the position property to -53, 0, or 213? Because there is currently only one media item in your category, the value in the position property does not matter, at this point. The media item is the first and last item in the list.
Now, run the code sample and verify the available media for the category:
response = categoryService.tenant(tenant).categories.categoryId(summerShoes).get({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json'
}
}
)
assert.equal(response.status, 200);
assert.isDefined(response.body.media[0].url);
assert.isUndefined(response.body.media[0].uncommittedMedia);
assert.equal(response.body.media[0].tags[0], 'one');
response;
The retrieved media does not contain the uncommittedMedia parameter, set to true
. This is because you completed the three-step process for adding media. Additionally, the media's url attribute is present and contains a link to the media content.
Create the first media item without a position
This operation is the same as the first, in that you are creating a media item for a category that does not yet have any media. However, because there will be only one media item for this category, you will not add a position property.
To create the first media item for a category, perform the three-step process, but without the position property in the payload. For example:
var result = createMediaForCategory(winterShoes, null, 'one');
link1 = result.mediaLink;
mediaId1 = result.mediaId;
result;
Create an additional media without a position
This tutorial shows how you can add more pictures to better appeal to your customers. Perform the three-step procedure to add media to a category that already has media with a defined order. However, when you create the new media, do not define the position property. The service adds the media item to the end of the existing media list.
var result = createMediaForCategory(winterShoes, null, 'two');
link2 = result.mediaLink;
mediaId2 = result.mediaId;
result;
Now, the Winter Shoes category has two media items. Retrieve the category and verify that the two media are assigned:
response = categoryService.tenant(tenant).categories.categoryId(winterShoes).get({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json'
}
}
)
assert.equal(response.status, 200);
assert.equal(response.body.media[0].tags[0], 'one');
assert.equal(response.body.media[1].tags[0], 'two');
response;
Create an additional media item with a position
In this exercise, you already have a list of media in your category. To add a new media item to the category, in a specific position in the media list, perform the three-step procedure and add the position property to the payload with a numerical value. The position property defines where to insert the new media item in the list. Set the value of position to 1
, as shown:
var result = createMediaForCategory(winterShoes, 1, 'three');
link3 = result.mediaLink;
mediaId3 = result.mediaId;
result;
You can set the value of position only when you insert a media item. After you insert the item, there is no other application for the position value, so it does not persist.
Here are a few examples that explain how the position value translates to the location in the media list:
- If
position=1
, the item inserts as the second media in the list. All media with a higher index move up one position. - If
position=7
, all media items at position 7 and higher move up one position to accommodate the new media item in position 8. - If
position=-53
, the item inserts at position 0, and all other media with a higher index move up one position.
response = categoryService.tenant(tenant).categories.categoryId(winterShoes).get({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json'
}
}
)
assert.equal(response.status, 200);
assert.equal(response.body.media[0].tags[0], 'one');
assert.equal(response.body.media[1].tags[0], 'three');
assert.equal(response.body.media[2].tags[0], 'two');
assert.isUndefined(response.body.media[0].position);
assert.isUndefined(response.body.media[1].position);
assert.isUndefined(response.body.media[2].position);
response;
Full update to edit media metadata
You might have a nice catalog with products assigned to multiple categories, and each category illustrated with images. Once you assign an image to the category, it stays there. However, you can use the update operation to reposition or resize images, or make other changes.
To perform a full update, provide a payload that fully describes the updated category. In other words, the payload must include all of the attributes that you want to see after update, as shown in this example:
response = categoryService.tenant(tenant).categories.categoryId(winterShoes).media.mediaId(mediaId2).put({
'position' : 0,
'tags' : ['two']
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json',
'Content-Language': 'en'
}
}
)
assert.equal(response.status, 200);
response;
Check the category to verify the latest modification:
response = categoryService.tenant(tenant).categories.categoryId(winterShoes).get({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json'
}
}
)
assert.equal(response.status, 200);
assert.equal(response.body.media[0].tags[0], 'two');
assert.equal(response.body.media[1].tags[0], 'one');
assert.equal(response.body.media[2].tags[0], 'three');
response;
After this update, the media with the tag two is in the first position.
Full update with no position specified
Perform a full update on a media item without specifying its position using the example shown:
response = categoryService.tenant(tenant).categories.categoryId(winterShoes).media.mediaId(mediaId2).put({
'tags' : ['two']
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json',
'Content-Language': 'en'
}
}
)
assert.equal(response.status, 200);
response;
Verify the update:
response = categoryService.tenant(tenant).categories.categoryId(winterShoes).get({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json'
}
}
)
assert.equal(response.status, 200);
assert.equal(response.body.media[0].tags[0], 'two');
assert.equal(response.body.media[1].tags[0], 'one');
assert.equal(response.body.media[2].tags[0], 'three');
response;
The media position remains unchanged. Based on the results, you can conclude that updating media without specifying a position does not change the order of the media.
Partial update to edit media metadata
You can also perform a partial update to modify one or more selected attribute, providing a payload that contains only the new value(s) for the modified attribute(s). To perform a partial update, use the partial query parameter.
Run the sample shown to update the media's position value, without changing any other attributes:
response = categoryService.tenant(tenant).categories.categoryId(winterShoes).media.mediaId(mediaId2).put({
'position' : 2
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json'
},
query: {
'partial': 'true'
}
}
)
assert.equal(response.status, 200);
response;
Verify the changes:
response = categoryService.tenant(tenant).categories.categoryId(winterShoes).get({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json'
}
}
)
assert.equal(response.status, 200);
assert.equal(response.body.media[0].tags[0], 'one');
assert.equal(response.body.media[1].tags[0], 'three');
assert.equal(response.body.media[2].tags[0], 'two');
response;
As expected, the tags parameter is present for the partially-updated category media. Because the service indexes the media position from zero (0), the media with the tag two is in the third position.
Retrieve all media for a category
If you have a large number of categories, you might not remember the category for each media item. You can retrieve all media that belong to a specified category, ordered by their position in the media collection.
response = categoryService.tenant(tenant).categories.categoryId(winterShoes).get({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json'
}
}
)
assert.equal(response.status, 200);
assert.equal(response.body.media[0].tags[0], 'one');
assert.equal(response.body.media[1].tags[0], 'three');
assert.equal(response.body.media[2].tags[0], 'two');
response;
Retrieve a particular media item for a category
You can also retrieve complete information for a specific media item, if for example, you want to retrieve one image from a category with many images. Extracting a specified media item is simple, as shown:
response = categoryService.tenant(tenant).categories.categoryId(winterShoes).media.mediaId(mediaId1).get({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json'
}
}
)
assert.equal(response.status, 200);
assert.equal(response.body.tags[0], 'one');
response;
Delete media
While images provide visual appeal for your customers, your marketing might evolve over time, requiring you to update the visual content. Or, you might need to remove outdated product images in favor of new product images, or replace old images with higher quality images. Delete your media as shown in this example:
response = categoryService.tenant(tenant).categories.categoryId(winterShoes).media.mediaId(mediaId2).delete({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json'
}
}
)
assert.equal(response.status, 204);
response;
In the example shown, the media item in the second position is deleted. Because the service indexes media from zero (0), the deleted image formerly occupied the first position in the list. The position of the two remaining media items adjusts automatically, as shown:
response = categoryService.tenant(tenant).categories.categoryId(winterShoes).get({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json'
}
}
)
assert.isDefined(response.body.media[0]);
assert.equal(response.body.media[0].tags[0], 'one');
assert.isDefined(response.body.media[1]);
assert.equal(response.body.media[1].tags[0], 'three');
assert.isUndefined(response.body.media[2]);
response;
Delete a category with media
When you no longer need a category, you can delete it, which deletes all media assigned to the category, as well:
response = categoryService.tenant(tenant).categories.categoryId(summerShoes).delete({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json'
}
}
);
assert.equal(response.status, 204);
response;
After the category is deleted, all of the media are also removed, as shown:
var parts = link.split('/');
var id = parts[parts.length - 1];
response = mediaService.public.files.fileId(id).get();
assert.equal(response.status, 404)
response;
Assignments
Introduction
Assigning a product to a category can help to better categorize huge amounts of products, making it easier for customers to find items through searches, rather than looking up products one-by-one.
Setup
Assertion
Define variable assert:
assert = chai.assert;
Get an access token
To perform any operations with a specific service, you always need an access token. For this purpose, create an API Client for the OAuth2 service:
API.createClient('oAuth2Service',
'/services/oauth2/v1/api.raml');
Now, get the tokens:
tenant = projectIdPlaceholder;
AccessToken = oAuth2Service.token.post({
'client_id' : clientIdPlaceholder,
'client_secret':clientSecretPlaceholder,
'grant_type' : 'client_credentials',
'token_type': 'Bearer',
'scope': 'hybris.tenant='+tenant+ ' hybris.category_create hybris.category_publish hybris.category_delete hybris.category_delete_all hybris.category_update hybris.category_read_unpublished'
});
ProductAccessToken = oAuth2Service.token.post({
'client_id' : clientIdPlaceholder,
'client_secret':clientSecretPlaceholder,
'grant_type' : 'client_credentials',
'token_type': 'Bearer',
'scope': 'hybris.tenant='+tenant+' hybris.product_read_unpublished hybris.product_create hybris.product_update hybris.product_delete hybris.product_delete_all'
});
To make the calls simple and the code clean, assign the access token to a variable:
access_token = AccessToken.body.access_token;
Additionally, you store the product access token in another variable:
product_access_token = ProductAccessToken.body.access_token;
Create an API client for the Category service
API.createClient('categoryService',
'/services/category/v1/api.raml');
Create an API client for the Product service
API.createClient('productService',
'/services/product/v2/api.raml');
Cleanup
Before you create a new category for the tutorial examples, delete all categories and products in the project:
response = categoryService.tenant(tenant).categories.delete({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json'
}
}
);
assert.equal(response.status, 204);
response;
response = productService.tenant(tenant).products.delete({}, {
headers: {
'Authorization': 'Bearer ' + product_access_token,
'Content-type' : 'application/json'
}
}
);
assert.equal(response.status, 204);
response;
Examples
In the examples shown, you retrieve assignments created for a category. Start by creating a few categories and assignments.
Category: Shoes
response = categoryService.tenant(tenant).categories.post({
'name': 'Shoes',
'code': 'shoes',
'description': 'All kinds of shoes.',
'position': 0
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json',
'Content-Language': 'en'
}
}
);
assert.equal(response.status, 201);
response;
Store the id of the category you created in a variable for further use:
shoesCategoryId = response.body.id;
Subcategory: Children shoes
response = categoryService.tenant(tenant).categories.post({
'name': 'Children shoes',
'code': 'children_shoes',
'description': 'All kinds of shoes for happy children.',
'position': 0,
'parentId': shoesCategoryId
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json',
'Content-Language': 'en'
}
}
);
assert.equal(response.status, 201);
response;
Store the id of the second category you created in another variable for further use:
childrenShoesCategoryId = response.body.id;
Product: Gnocci
response = productService.tenant(tenant).products.post({
'code': 'gnocci',
'name': 'Gnocci',
'description': 'Gnocci - classy handmade shoes for everybody.'
}, {
headers: {
'Authorization': 'Bearer ' + product_access_token,
'Content-Type' : 'application/json',
'Content-Language': 'en'
}
}
)
response;
Assign the id for the returned object to a variable:
gnocciId = response.body.id;
Assign the link of the returned object to a variable:
gnocciUrl = response.body.link;
Assigning a product to a category
To categorize the Gnocci product as a shoe, follow the example shown to create an assignment that links the category with a product.
response = categoryService.tenant(tenant).categories.categoryId(shoesCategoryId).assignments.post({
"ref" :
{
"id": gnocciId,
"type": "product",
"url": gnocciUrl
}
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json',
'Content-Language': 'en'
}
}
);
assert.equal(response.status, 201);
response;
Retrieve assignments in a category
The Category service provides a convenient way to retrieve all assignments for your categories. Follow the example shown to find and get all assignments in your category.
response = categoryService.tenant(tenant).categories.categoryId(shoesCategoryId).assignments.get({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json',
'Content-Language': 'en'
}
}
);
assert.equal(response.status, 200);
response;
Retrieve assignments in a category
You can assign subcategories to products, as well. Subcategories can refer to a distinct subset of items within a category. For example, the shoes category is linked with the Gnocci product. But what if you also provide shoes for children? You can create and link a new subcategory with a children's shoe product, specified by name.
Product: Starback 007
response = productService.tenant(tenant).products.post({
'code': 'starback_007',
'name': 'Starback 007',
'description': 'Starback 007 - classy handmade shoes for any child interested in adventures.'
}, {
headers: {
'Authorization': 'Bearer ' + product_access_token,
'Content-Type' : 'application/json',
'Content-Language': 'en'
}
}
)
response;
Assign the id of the returned object to a variable:
starbackId = response.body.id;
Assign the link of the returned object to a variable:
starbackUrl = response.body.link;
Now, link the product Starback 007 with the subcategory Children shoes.
response = categoryService.tenant(tenant).categories.categoryId(childrenShoesCategoryId).assignments.post({
"ref" :
{
"id": starbackId,
"type": "product",
"url": starbackUrl
}
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json',
'Content-Language': 'en'
}
}
);
assert.equal(response.status, 201);
response;
Finally, you can retrieve all assignments, whether they are created for a category or any subcategory in the category tree structure. If you provide the recursive query parameter, set to true
, as shown in this example, the service retrieves assignments from the subcategories, along with the assignments from the queried category.
response = categoryService.tenant(tenant).categories.categoryId(shoesCategoryId).assignments.get({
'q' : 'recursive:true'
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json',
'Content-Language': 'en'
}
}
);
assert.equal(response.status, 200);
response;
Category Extensibility
As an organizational unit, each category is identified by its own set of basic properties. When you have a category, you can assign products to it. When viewing your store online, customers can click on a category to view products that are assigned to a category.
When several categories share one property, you can create and reuse a mixin schema in each category. For example, if you have a group of categories that require an age restriction for the assigned products, you can use an age-restriction mixin instead of assigning the same property to all categories.
This tutorial describes how to create a mixin to extend the properties of categories.
Setup
Assertion
Define variable assert:
assert = chai.assert;
expect = chai.expect;
Get an access token
To perform any operation with a specific service, you need an access token. Create an API Client for the OAuth2 service:
API.createClient('oAuth2Service',
'/services/oauth2/v1/api.raml');
Get the token:
tenant = projectIdPlaceholder;
AccessToken = oAuth2Service.token.post({
'client_id' : clientIdPlaceholder,
'client_secret':clientSecretPlaceholder,
'grant_type' : 'client_credentials',
'token_type': 'Bearer',
'scope': 'hybris.tenant='+tenant+ ' hybris.category_create hybris.category_publish hybris.category_delete hybris.category_delete_all hybris.category_update hybris.category_read_unpublished hybris.schema_manage'
});
To make the calls simple and the code clean, assign the access token to a variable:
access_token = AccessToken.body.access_token;
Create an API client for the Category service
API.createClient('categoryService',
'/services/category/v1/api.raml');
Create an API client for the Schema service
API.createClient('schemaService', '/services/schema/v1/api.raml');
Cleanup
Before creating new categories for the tutorial examples, clean up the project:
response = categoryService.tenant(tenant).categories.delete({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json'
}
}
);
assert.equal(response.status, 204);
response;
Extend a category with an additional attribute
To share a property with multiple categories, create an appropriate schema for your mixins. When you have the schema, you can create one or more categories and import your schema. The sections that follow describe how to create and extend categories, and create and import schemas.
Follow the example shown to create a category that provides additional information about age restrictions for the products assigned to your category. Declare the property responsible for storing additional information in the schema that you create using the Schema service, as shown.
schema = 'age_restriction-version1.json';
response = schemaService.tenant(tenant).schema(schema).get({
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json'
}
}
)
if(response.status == 404){
response = schemaService.tenant(tenant).schema(schema).post({
'$schema': 'http://json-schema.org/draft-04/schema#',
'type': 'object',
'properties':{
'ageLimit': {
'type':'number'
}
}
},{
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json'
}
});
assert.equal(response.status, 201);
response.body ;
}
Follow this example to create a category that defines the minimum age required to buy items assigned to the category. You will define an additional property in the schema: ageLimit. When you create a category, you can use and set specified values for mixin-based properties such as ageLimit. Furthermore, you can create another category and use the property again, with the same or different value. Categories can share the property, but you can set the value separately for each category.
response = categoryService.tenant(tenant).categories.post({
'name': 'Computer Games, over 18',
'code': 'comp_games_18',
'description': 'Scary computer games for mature people. Genres: horror, thriller, crime, noir, and many other. ',
'position': 0,
'metadata': {
'mixins':{
'age_restriction': 'https://api.beta.yaas.io/hybris/schema/v1/'+tenant+'/age_restriction-version1.json'
}
},
'mixins': {
'age_restriction': {
'ageLimit': 18
}
}
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json',
'Content-Language': 'en'
}
}
);
assert.equal(response.status, 201);
response;
computerGameCatId = response.body.id;
Retrieve your newly-created category to verify whether the creation process ran without flaws.
response = categoryService.tenant(tenant).categories.categoryId(computerGameCatId).get({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json',
'Accept-Language': 'en'
}
}
)
assert.equal(response.status, 200);
assert.equal(response.body.name, 'Computer Games, over 18');
assert.equal(response.body.mixins.age_restriction.ageLimit, 18);
response;
Update an additional attribute in a category
Occasionally, you might need to modify some specifications for existing categories. For example, you no longer offer computer games labeled as 18+, but you still have some items that should be restricted for customers over the age of 16. You do not need to create new schemas or new categories. Instead, run a partial update using the PUT operation, and change only the category properties that require updates. Use the appropriate mixin schema.
response = categoryService.tenant(tenant).categories.categoryId(computerGameCatId).put({
'name': 'Computer Games, over 16',
'code': 'comp_games_16',
'description': 'Computer games for game-lovers. Genres: s-f, fantasy, adventure, and many other.',
'metadata': {
'mixins':{
'age_restriction': 'https://api.beta.yaas.io/hybris/schema/v1/'+tenant+'/age_restriction-version1.json'
}
},
'mixins': {
'age_restriction': {
'ageLimit': 16
}
}
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json',
'Content-Language': 'en'
},
query: {
'partial': true
}
});
assert.equal(response.status, 200);
response;
Check the results of your update. The category should now reflect the new age limit for customers who buy the products assigned to the updated category.
response = categoryService.tenant(tenant).categories.categoryId(computerGameCatId).get({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json',
'Accept-Language': 'en'
}
}
)
assert.equal(response.status, 200);
assert.equal(response.body.name, 'Computer Games, over 16');
assert.equal(response.body.description, 'Computer games for game-lovers. Genres: s-f, fantasy, adventure, and many other.');
assert.equal(response.body.mixins.age_restriction.ageLimit, 16);
response;
Create a category with additional properties while not allowed
You can prevent the addition of more properties to a category. In this exercise, extend the category by adding the additionalProperties property, and setting the value to false
. Consequently, no one can add an additional property to the mixins section of the extended category, and only the properties declared in the schema are allowed.
For contrast, look at the example in the Update an additional attribute in a category section. The version1
schema does not have an additionalProperties attribute. If the property is not in the schema, the default behavior applies and additional properties are allowed in the category definition, without restriction.
Follow this example to create the schema:
schema = 'age_restriction-version2.json';
response = schemaService.tenant(tenant).schema(schema).get({
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json'
}
}
)
if(response.status == 404){
response = schemaService.tenant(tenant).schema(schema).post({
'$schema': 'http://json-schema.org/draft-04/schema#',
'type': 'object',
'properties':{
'ageLimit': {
'type':'number'
}
},
'additionalProperties': false
},{
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json'
}
});
assert.equal(response.status, 201);
response.body ;
}
Now, create a product that uses the ageLimit property, and try to add an attribute in the mixins section to extend your category. Add any property that is not declared in the schema used for the category. For example: otherRestrictions=true
.
Run the example to see what happens when you try to add an extending property to the mixins section without previously declaring it in the appropriate schema. When you set the value of the additionalProperties property to false
, the service does not allow you to create additional properties.
response = categoryService.tenant(tenant).categories.post({
'code': 'Computer Games, PEGI 16',
'name': 'computer_pagi_16',
'description': 'A variety of computer games for all teenagers over 16.',
'metadata': {
'mixins':{
'age_restriction': 'https://api.beta.yaas.io/hybris/schema/v1/'+tenant+'/age_restriction-version2.json'
}
},
'mixins': {
'age_restriction': {
'ageLimit': 16 ,
'otherRestrictions': true
}
}
},{
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type' : 'application/json',
'Content-Language': 'en'
}
});
assert.equal(response.status, 400);
response;
Testing
Introduction
During development, you probably create a lot of data that will not necessarily be required after development ends. When this happens, you might want to remove all data in one fell swoop rather than remove each item separately. This tutorial describes how to remove everything at once. The scope hybris.category_delete_all is required to perform this operation.
Setup
Assertion
Define a variable assert:
assert = chai.assert;
Get an access token
To perform any operations with a specific service, you always need an access token. For this purpose, create an API Client for the OAuth2 service:
API.createClient('oAuth2Service',
'https://devportal.yaas.io/services/oauth2/v1/api.raml');
Now, get the token:
tenant = 'apinotebook';
AccessToken = oAuth2Service.token.post({
'client_id' : 'OLv6btMZEATHoLcxnHcP2NbC99NdG4ZM',
'client_secret':'8yRNij2c0eO57q7h',
'grant_type' : 'client_credentials',
'token_type': 'Bearer',
'scope': 'hybris.category_create hybris.category_publish hybris.category_delete_all'
});
To make the calls simple and the code clean, assign the id of the returned object to a variable:
access_token = AccessToken.body.access_token;
Create an API client for the Category service
Prepare an API client for the Category service, so you can run the examples that follow:
API.createClient('categoryService',
'https://devportal.yaas.io/services/category/v1/api.raml');
Examples
Because this tutorial requires some categories to be present in the tenant, create two categories. For example, vegetables and fruits.
response = categoryService.tenant(tenant).categories.post({
'name': 'vegetables',
'description': 'Category containing fresh vegetables',
'published': true
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json'
}
}
)
assert.equal(response.status, 201);
response = categoryService.tenant(tenant).categories.post({
'name': 'fruits',
'description': 'Category containing juicy fruits',
'published': false
}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json'
}
}
)
assert.equal(response.status, 201);
response;
Delete all categories and assignments
During your testing process, you might need a "clean" tenant. After you "clean" the tenant, you can remove all categories at once. Because categories also have assignments that cannot exist without categories, the operation also removes the assignments.
In the previous step, you created two categories. Remove the categories using the call shown:
response = categoryService.tenant(tenant).categories.delete({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json'
}
}
);
assert.equal(response.status, 204);
response;
Verify the category deleted
You removed all of the categories from your tenant. To make sure the categories are removed, verify the delete operation is successful using the example shown:
response = categoryService.tenant(tenant).categories.get({}, {
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-type' : 'application/json'
}
}
)
assert.equal(response.status, 200);
assert.equal(response.body.length, 0);
response;
As you can see by the response, the categories are successfully removed and are no longer available in the Category service.
Publish Categories
You can publish categories using POST or PUT methods on the /categories/{categoryId}
resource. This requires that you provide a proper authorization:
- Authorization: You must provide a proper scope that enables users to perform these operations. The scopes should be granted in an access token from OAuth 2.0 service. For more information about the authorization and authentication used in hybris services, see Authorization. For more information about the scopes in the Category service, see the Scopes in the Category Service section.
You can also use the PUT method to publish or unpublish an existing category. This action may have some influence on other categories in the category tree.
You can publish or unpublish a category by modifying the published property. There are some important rules to consider when publishing categories:
- The category to be published is specified in the URL path parameter categoryId.
- The published property specifies whether or not the category should be visible to anonymous users.
- If the published property is set to
true
, then it triggers publishing of the specified category and all ancestor categories, if these ancestors are not already published. - It is not possible to have a public subcategory if one of its ancestors is not published.
- If you set the published property to
true
and set the published.recursive query parameter totrue
, then the current category, its ancestors, and all category descendants are published. - If the published property is set to
false
, it triggers unpublishing of the specified category and all of its published descendants. All category ancestors, however, remain in the same state as before.
There are two ways to publish a category:
- Full replace: This is the default method. If you do not provide the partial query parameter or set the partial parameter to
false
, a full replace is performed. - Partial update: If you provide the partial query parameter set to
true
, then a partial replace is performed.
Publish a category using a full replace
- Method: PUT
- Request URL:
https://api.beta.yaas.io/hybris/category/v1/{tenant}/categories/{categoryId}
- URL Query Parameter:
- published.recursive: If the published property is set to
true
, then setting the URL query parameter totrue
also publishes all subcategories. If it is set tofalse
, only the updated category is published, while the child categories remain unchanged. When unpublishing the category by setting the published property tofalse
, all subcategories are automatically unpublished and this parameter has no effect.
- published.recursive: If the published property is set to
For example:
{
"name":{"en":"Books", "de":"Bücher"},
"parentId":"{oldParentId}",
"published":true
}
There are several other considerations when using the full replace method:
- If the published property is not provided in the request body, then triggering a full replace (by setting the partial query parameter to
false
or excluding it) forces the category to be unpublished together with all descendant categories. - If the category is unpublished by setting the published property to
false
, all its descendant categories also become unpublished. - Any category properties that are not provided are set to
null
if moved.
Publish a category using a partial update
- Method: PUT
- Request URL:
https://api.beta.yaas.io/hybris/category/v1/{tenant}/categories/{categoryId}?partial=true
- Query Parameters:
- published.recursive: If the published property is set to
true
, setting the URL query parameter totrue
also publishes all subcategories. When set tofalse
, only the updated category is published, keeping the child categories intact. When unpublishing the category (by setting the published property tofalse
), all subcategories are automatically unpublished and this parameter has no effect. - partial: Used to trigger a partial update. Set this parameter to
true
to trigger a full update.
- published.recursive: If the published property is set to
You can publish or unpublish a category by providing only the published property in the request body. However, in order to publish a category this way, you must provide the partial query parameter and set it to true
.
For example:
{
"published":true
}
Define Resource Properties For Category
You can define resource properties for a category to specify:
- Mixins namespace
- Link to the schema definition
The schema definition contains the information about additional properties that are common for the resources of a specified type, such as products, that belong to the category.
You can set the resourceMixins property when creating and updating categories. For more information about creating and updating categories, see Create New Category and Update Category.
Create a category with the 'resourceMixins' property
Request
- Method: POST
- Request URL:
https://api.beta.yaas.io/hybris/category/v1/{tenant}/categories
- Headers:
- Authorization: You must provide a proper scope that enables users to perform these operations. The scopes should be granted in an access token from OAuth 2.0 service. For more information about the authorization and authentication used in hybris services, see Authorization. For more information about the scopes in the Category service, see the Scopes in the Category Service section.
- content-language: en
- Body :
{ "name": "Smartphones", "description": "Category containing all smartphones.", "resourceMixins":{ "smartphoneSchema": "https://api.beta.yaas.io/hybris/schema/v1/myShopProjectId/smartphoneSchema_v1" } }
Response
- Status code:
201 Created
Add or update the 'resourceMixins' property
This request only updates the resourceMixins collection from the payload.
Request
- Method: PUT
- Request URL:
https://api.beta.yaas.io/hybris/category/v1/{tenant}/categories/{categoryId}
- Headers:
- Authorization: You must provide a proper scope that enables users to perform these operations. The scopes should be granted in an access token from OAuth 2.0 service. For more information about the authorization and authentication used in hybris services, see Authorization. For more information about the scopes in the Category service, see the Scopes in the Category Service section.
- Query Parameter:
- partial:
true
- partial:
- Body:
{ "resourceMixins":{ "smartphoneSchema":"https://api.beta.yaas.io/hybris/schema/v1/myShopProjectId/smartphoneSchema_v2" } }
Response
- Status code:
200 OK
Validation
The resourceMixins value property must be a URL. If it is not, then the validation fails and a feedback message is returned.
{
"type": "validation_violation",
"status": 400,
"message": "Field 'resourceMixins' provided url value 'urlWhichIsNotValid' is not a valid url"
}
Glossary
Term | Description |
---|---|
assignment | The attribution of an element to a category, for example attribution of a product to a category. |
resource reference | A data structure, such as a link, that points to another resource in the system, such as a product. |
If you find any information that is unclear or incorrect, please let us know so that we can improve the Dev Portal content.
Use our private help channel. Receive updates over email and contact our specialists directly.
If you need more information about this topic, visit hybris Experts to post your own question and interact with our community and experts.