In this exercise you'll enhance the service definition with annotations that restrict the OData operations that are allowed.
At the end of these steps, your OData service will have different levels of access for each of the entities.
👉 In the same way that you did in exercise 05, import a collection of HTTP requests into your Postman client via the URL to postman-06.json resource.
This contains a number of different requests ready for you to try.
Note: If you still want to use the command line, you'll find the invocations in the appropriate steps below.
Right now the Books
and Authors
entities are exposed in the CatalogService
service. In the subsequent steps in this exercise we'll be tightening the restrictions down to read-only. Before we do, let's check to see that, at least currently, we have write access. We'll do that by making a couple of OData Create operations, one to create a new author, and the other to add a book by that author.
👉 In the Postman collection you imported, try out the requests in the folder "(A) Before @readonly annotations", running them in the order they're presented (the creation of the new book is for the new author, which needs to exist first).
If you want to use curl
on the command line instead of Postman, use the following invocations.
First, add the author "Iain M Banks":
curl \
-d '{"ID": 162, "name": "Iain M Banks"}' \
-H 'Content-Type: application/json' \
http://localhost:4004/catalog/Authors
For Windows users:
curl ^
-d "{\"ID\": 162, \"name\": \"Iain M Banks\"}" ^
-H "Content-Type: application/json" ^
http://localhost:4004/catalog/Authors
Now add the book "Consider Phlebas":
curl \
-d '{"ID": 44138, "title": "Consider Phlebas", "stock": 541, "author_ID": 162 }' \
-H 'Content-Type: application/json' \
http://localhost:4004/catalog/Books
For Windows users:
curl ^
-d "{\"ID\": 44138, \"title\": \"Consider Phlebas\", \"stock\": 541, \"author_ID\": 162 }" ^
-H "Content-Type: application/json" ^
http://localhost:4004/catalog/Books
Check that the creation requests are successful, and that you can see the new author and book in an OData Query operation: http://localhost:4004/catalog/Authors?$expand=books.
Now, we want to only allow read-only operations on the master data. This can be achieved with OData annotations that are encapsulated into a convenient @readonly
shortcut.
👉 Add this @readonly
shortcut to each of the Books
and Authors
specifications in the CatalogService
thus:
service CatalogService {
@readonly entity Books as projection on my.Books;
@readonly entity Authors as projection on my.Authors;
entity Orders as projection on my.Orders;
}
What does this do, precisely? Let's find out.
👉 After saving the file, start up cds watch
to get back into the auto restart mode. The, examine the OData service's metadata. You should find annotations that look like this:
Are these annotations just recommendations that can be overridden? Let's find out.
We can think of the annotations that we saw in the metadata document as guidelines for a UI, but we want to ensure that the restrictions are really in effect in the service itself. Let's try to create another entry in the Books
entityset.
👉 In the same Postman collection you imported, try out the first request in the folder "(B) After @readonly annotations". If you want to use curl
on the command line instead of Postman, use the following invocation to add the book "The Player of Games":
curl \
-d '{"ID": 47110, "title": "The Player of Games", "stock": 405, "author_ID": 162 }' \
-H 'Content-Type: application/json' \
http://localhost:4004/catalog/Books
For Windows users:
curl ^
-d "{\"ID\": 47110, \"title\": \"The Player of Games\", \"stock\": 405, \"author_ID\": 162 }" ^
-H "Content-Type: application/json" ^
http://localhost:4004/catalog/Books
The request is an OData Create request for a new book. You should see that this request is rejected with HTTP status code 405 "Method Not Allowed", with an error like this supplied in the response body:
{
"error": {
"code": "405",
"message": "Method Not Allowed"
}
}
You should also see a line in the terminal (where you invoked cds serve all
) like this:
[2019-05-29T15:16:39.694Z | WARNING | 1939700]: Method Not Allowed
👉 Next, try out the second request in that same folder - it's an OData Delete operation, to remove the book "The Raven". If you want to use curl
on the command line instead of Postman, use this invocation:
curl \
-X DELETE \
'http://localhost:4004/catalog/Books(251)'
For Windows users:
curl ^
-X DELETE ^
"http://localhost:4004/catalog/Books(251)"
It should also fail in a similar way.
TIP: If you end up destroying your test data, you can easily restore it by redeploying (cds deploy
), as the test data will be re-seeded from the CSV files.
In a similar way to how we restricted access to the Books
and Authors
entitysets to read-only operations, we will now restrict access to the Orders
entityset so that orders can only be created, and not viewed, amended or removed.
As you might have guessed, this is achieved via the @insertonly
annotation shortcut.
👉 Before making this edit, switch back (if you haven't already) to using cds watch
so that restarts will be automatic after changes.
👉 In the CatalogService
service definition in srv/service.cds
, annotate the Orders
entity with @insertonly
so it looks like this:
service CatalogService {
@readonly entity Books as projection on my.Books;
@readonly entity Authors as projection on my.Authors;
@insertonly entity Orders as projection on my.Orders;
}
👉 Now create a couple of orders using the Postman collection from exercise 05 - there should be a couple of POST requests against the Orders
entityset (refer to the step in exercise 05 for the command line invocations if you wish).
Note at this point that the requests are successful: HTTP status code 201 is returned for each request, along with the newly created entity in the response payload, like this example:
{
"@odata.context": "$metadata#Orders/$entity",
"@odata.metadataEtag": "W/\"qItYMyHC4RMSWG6mehaOHDxo+o/HzUCPMchqSx7hd1k=\"",
"ID": "527ef85a-aef2-464b-89f6-6a3ce64f2e14",
"modifiedAt": null,
"createdAt": "2019-03-26T06:51:52Z",
"createdBy": "anonymous",
"modifiedBy": null,
"quantity": 9,
"book_ID": 427,
"country_code": null
}
Further, you can see the request logged in the terminal, with no sign of any errors:
POST /catalog/Orders
This confirms we can insert new orders. But can we see what they are?
👉 Try to perform an OData Query operation on the Orders
entityset, simply by requesting this URL: http://localhost:4004/catalog/Orders.
The operation should be denied, and you'll receive something like this in the body of the response in your browser:
<error xmlns="http://docs.oasis-open.org/odata/ns/metadata">
<code>405</code>
<message>Method Not Allowed</message>
</error>
In this exercise you used shortcut annotations to restrict access to the entities expose in the service definition. The annotations provide not only information to be used by consumers (such as frontends) but also control access at the HTTP level.
- Did you notice anything special about your request to http://localhost:4004/catalog/Authors?$expand=books in step 2?
- How might the annotations relating to the read-only restrictions be useful in a UI context?
- What was the format of the OData Delete operation - did we need to supply a payload?