Create a Reusable Service
- How to write an entity definition
- How to use some generic CAP artifacts like aspects and types
- What associations and compositions are
- How to make the project reusable
The previous tutorial was about quickly setting up a working CAP application and read/write some mock data. This tutorial is about learning how to extend the application to a complete products service.
You will take advantage of many of the out-of-the-box features provided by the CAP Java SDK such as using H2 as a database for local development. As a result, you will remove your custom handlers written in the first tutorial. In subsequent tutorials you will swap out H2 with the SAP HANA service, when preparing your application for the cloud.
- Step 1
In the previous tutorial, you defined a service, which defined its own entity. When modeling with CDS the best practice is to separate services from the domain model.
Therefore, you will now define the complete domain model that is used by the products service. The domain model is stored in the
db
folder of your CAP application.-
Go to your
db
folder and create a file calledschema.cds
. -
Add the following code to your newly created
schema.cds
file and make sure you Save the file:CDSCopynamespace sap.capire.products; using { Currency, cuid, managed, sap.common.CodeList } from '@sap/cds/common'; entity Products : cuid, managed { title : localized String(111); descr : localized String(1111); stock : Integer; price : Decimal(9,2); currency : Currency; category : Association to Categories; } entity Categories : CodeList { key ID : Integer; parent : Association to Categories; children : Composition of many Categories on children.parent = $self; }
-
- Step 2
As you can see, the domain model defines two entities:
Products
Categories
It also imports various common definitions from the
@sap/cds/common
package (a globally available reuse package):Currency
cuid
managed
CodeList
In addition, the domain model uses the CDS keywords
localized
,Association
, andComposition
. Let’s explain these imports and keywords in more detail: - Step 3
The
localized
keyword can be used to mark elements, which require translation. The ability to store translations for different languages and to store a default fallback translation is automatically handled by CDS for you. You will see this in action in more detail in the next tutorial. - Step 4
Associations and compositions can be used to define relationships between entities. They often allow you to define these relationships without explicitly working with foreign keys.
While associations define a rather loose coupling between the entities, compositions define a containment relationship. Compositions can also be thought of as defining deep structures. You can perform
deep inserts
andupserts
along these structures.In your domain model, the
Categories
entity defines aparent
andchildren
element. This enables a hierarchy of categories. The children of a category are modelled as a composition. A category with all of its children defines a deep nested structure. Deleting a category would automatically delete all of its children. However, the parent of a category is modelled as an association. Deleting a category obviously shouldn’t delete its parent. - Step 5
Both
cuid
andmanaged
are aspects. Aspects extend an entity with additional elements. Thecuid
aspect adds akey
elementID
of typeUUID
to the entity.The
managed
aspect adds four additional elements to the entity. These capture the time of the creation and last update of the entity, and the user, which performed the creation and last update. - Step 6
CodeLists
can be used to store global, translatable definitions based on codes, such as currencies, countries, or languages. Especially for UIs, aCodeList
can be useful to provide a value help for certain input fields.The
Currency
definition is a type. It defines an association to aCurrencies
entity. TheCurrencies
entity is based on ISO 4217 and uses three-letter alpha codes as keys such asEUR
orUSD
and provides the possibility to store the corresponding currency symbol such as€
or$
. - Step 7
Look at these explained keywords yourself and learn more about it.
-
To jump to the imported definitions directly in your editor, press
CTRL
, hover over the keyword, and click. This will open the source file in a separate editor tab. -
Hold
CTRL
and hover over a keyword, then move the hand cursor over the keyword. This opens up you a tiny overlay with the definition of this particular item. -
A right-click (or use
F12
) on the definition opens up the context menu. There you can find, for example, Peek definition to get a much bigger overlay. Not only the definition of this particular item is displayed, you also have the ability to navigate through the whole source file of this definition without opening the file itself.
As you have now learned how to have a look at definitions coming from @sap/cds/common. How many properties does the Products entity effectively have?
-
- Step 8
In the first tutorial, you defined a simple service, called
AdminService
, which directly defined the entityProducts
. As you now have defined theProducts
entity in your domain model, theAdminService
just needs to expose it. In addition, you defined theCategories
entity, which should also be part of your service.This can be achieved by using projections. Services expose projections of the entities defined in the domain model. These projections can be used to include (and also exclude) only certain elements of an entity or to rename the entity’s elements.
In this example you will use the most simple projection, which exposes the domain model entity without any changes.
-
Go to your
srv
folder and open theadmin-service.cds
file. -
Replace the content with the following code and make sure you Save the file:
CDSCopyusing { sap.capire.products as db } from '../db/schema'; service AdminService { entity Products as projection on db.Products; entity Categories as projection on db.Categories; }
-
- Step 9
The CAP Java SDK provides out-of-the-box capabilities to store and retrieve entities from a database. Therefore, no custom coding is required if entities are stored in the database. The entities defined in your
AdminService
will be automatically served via OData and you can just delete theAdminService.java
file that was created earlier.- Delete the
AdminService.java
file in thehandlers
folder.
By default, the CAP Java SDK uses an in-memory H2 database. The content of this database will be lost when the application is stopped.
In case you need a persistent database between application runs you can use a file-based
SQLite
database as described in section Using Databases in the CAP documentation. - Delete the
- Step 10
-
Stop your application if it is still running. Now restart your application by running
mvn spring-boot:run
in the terminal and open it in a new tab. -
You will now create some
Categories
through a HTTP request. Add the following request to therequests.http
file you have created earlier by pasting the following content:HTTPCopy### Create Categories POST http://localhost:8080/odata/v4/AdminService/Categories Content-Type: application/json {"ID": 1, "name": "TechEd", "descr": "TechEd related topics", "children": [{"ID": 10, "name": "CAP Java", "descr": "Run on Java"}, {"ID": 11, "name": "CAP Node.js", "descr": "Run on Node.js"}]}
Choose
Send Request
which appears over the new request. This request will create multiple, nested categories, at once through a deep insert. -
Try to query individual categories, for example by adding the following to the end of your app URL:
/odata/v4/AdminService/Categories(10)
-
You can also expand the nested structures. Add the following to the end of your app URL:
/odata/v4/AdminService/Categories?$expand=children
/odata/v4/AdminService/Categories(10)?$expand=parent
/odata/v4/AdminService/Categories(1)?$expand=children
-
Make sure to stop your application after testing it by using
CTRL+C
.
-
- Step 11
In the following tutorial, the application will be reused by a bookstore application. The reuse of models can be achieved by publishing NPM modules with the models and defining dependencies to these NPM modules in other applications. There are a two steps we need to perform to prepare the
products-service
application for reuse.-
The name of the
products-service
reuse module, should be@sap/capire-products
. Therefore, open thepackage.json
file within the~/projects/products-service
folder and change the value ofname
field fromproducts-service-cds
to@sap/capire-products
. If you want to you can also provide a meaningful description in thedescription
field. -
To make it easier to reuse the module, an
index.cds
file can be added to theproducts-service
. This ensures a better decoupling from other applications. Create a new fileindex.cds
in the~/projects/products-service
folder and place the following content inside this file, making sure you Save the file:CDSCopyusing from './db/schema'; using from './srv/admin-service';
Congratulations! You have successfully developed the products service application, which is based on a CDS domain model and service definition.
In the next tutorial, you will build a bookstore application, reusing the products service application. You will later extend the bookstore application with custom business logic and deploy it to the cloud, using SAP HANA as the database.
-
- Define the domain model
- Understand keywords
- The `localized` keyword
- Associations and compositions
- The `cuid` and `managed` aspects
- The `CodeList` aspect and the `Currency` type
- Get more information about `@sap/cds/common`
- Rewrite the `AdminService`
- Use CAP's generic persistence handling
- Run and test your application
- Set up for reuse