diff --git a/Pag50102.ContactRelationApi.al b/Pag50102.ContactRelationApi.al
index 52c2392..ced2116 100644
--- a/Pag50102.ContactRelationApi.al
+++ b/Pag50102.ContactRelationApi.al
@@ -1,12 +1,12 @@
page 50102 "Contact Relation Api"
{
- APIGroup = 'nav';
+ APIGroup = 'queries';
APIPublisher = 'publisher';
APIVersion = 'v1.0';
DelayedInsert = true;
- EntityName = 'relation';
- EntitySetName = 'relations';
+ EntityName = 'contactRelation';
+ EntitySetName = 'contactRelations';
ODataKeyFields = "No.";
PageType = API;
SourceTable = "Contact Relation";
@@ -17,26 +17,10 @@ page 50102 "Contact Relation Api"
{
repeater(General)
{
- field(number; "No.")
- {
- ApplicationArea = All;
- Caption = 'no';
- }
- field(contactNo; "Contact No.")
- {
- ApplicationArea = All;
- Caption = 'contactNo';
- }
- field(relationToContactNo; "Relation to Contact No.")
- {
- ApplicationArea = All;
- Caption = 'relationToContactNo';
- }
- field(description; "Description")
- {
- ApplicationArea = All;
- Caption = 'description';
- }
+ field(number; "No.") { }
+ field(contactNo; "Contact No.") { }
+ field(description; "Description") { }
+ field(relationToContactNo; "Relation to Contact No.") { }
}
}
}
diff --git a/Pag50103.ContactApi.al b/Pag50103.ContactApi.al
index 424dd65..0a3ef6a 100644
--- a/Pag50103.ContactApi.al
+++ b/Pag50103.ContactApi.al
@@ -1,7 +1,7 @@
page 50103 "Contact Api"
{
- APIGroup = 'nav';
+ APIGroup = 'queries';
APIPublisher = 'publisher';
APIVersion = 'v1.0';
DelayedInsert = true;
@@ -16,42 +16,15 @@ page 50103 "Contact Api"
{
repeater(General)
{
- field(number; "No.")
- {
- ApplicationArea = All;
- Caption = 'number', Locked = true;
- }
- field(firstName; "First Name")
- {
- ApplicationArea = All;
- Caption = 'firstName', Locked = true;
- }
- field(surname; Surname)
- {
- ApplicationArea = All;
- Caption = 'surname', Locked = true;
- }
- field(name; Name)
- {
- ApplicationArea = All;
- Caption = 'name', locked = true;
- }
- field(id; SystemId)
- {
- ApplicationArea = All;
- Caption = 'id';
- }
- field(companyNo; "Company No.")
- {
- ApplicationArea = All;
- Caption = 'companyNo';
- }
-
+ field(number; "No.") { }
+ field(firstName; "First Name") { }
+ field(surname; Surname) { }
+ field(name; Name) { }
+ field(companyNo; "Company No.") { }
part(relations; 50102)
{
- ApplicationArea = All;
- EntityName = 'relation';
- EntitySetName = 'relations';
+ EntityName = 'contactRelation';
+ EntitySetName = 'contactRelations';
}
}
}
diff --git a/app.json b/app.json
new file mode 100644
index 0000000..ffd5a7f
--- /dev/null
+++ b/app.json
@@ -0,0 +1,37 @@
+{
+ "id": "6d2eaf41-642c-41ff-81ce-c3cc06d9d3c4",
+ "name": "api navigation",
+ "publisher": "publisher",
+ "version": "1.0.0.0",
+ "brief": "",
+ "description": "",
+ "privacyStatement": "",
+ "EULA": "",
+ "help": "",
+ "url": "",
+ "logo": "",
+ "dependencies": [
+ {
+ "id": "63ca2fa4-4f03-4f2b-a480-172fef340d3f",
+ "publisher": "Microsoft",
+ "name": "System Application",
+ "version": "16.0.0.0"
+ },
+ {
+ "id": "437dbf0e-84ff-417a-965d-ed2bb9650972",
+ "publisher": "Microsoft",
+ "name": "Base Application",
+ "version": "16.0.0.0"
+ }
+ ],
+ "screenshots": [],
+ "platform": "16.0.0.0",
+ "idRanges": [
+ {
+ "from": 50100,
+ "to": 50149
+ }
+ ],
+ "showMyCode": true,
+ "runtime": "5.0"
+ }
\ No newline at end of file
diff --git a/readme.md b/readme.md
index a12af28..e6437a7 100644
--- a/readme.md
+++ b/readme.md
@@ -3,7 +3,7 @@
This is a spike project to explore both the OData Webservices and the new custom API of Business Central.
-My attention is on querying object hierarchies with a single request using the OData navigation features and the query option $expand.
+My attention is on querying object hierarchies with a single request using the OData navigation features and the query option `$expand`.
## Setup
### A simple relation between contacts
@@ -154,7 +154,7 @@ This page needs to be published as web service with the service name `Contact`.
```
-These associations have the name of the field with the table relation followed by `_Link`. Please note the type of the navigation property. While a table relation is a lookup, which points to a single entity, the type indicates a _collection_ of type Contact.
+These associations have the name of the field with the table relation followed by `_Link`. Please note the type of navigation property. While a table relation is a lookup, which points to a single entity, the type indicates a _collection_ of type Contact.
`...ContactRelation('R01')?$expand=Relation_to_Contact_No_Link, Contact_No_Link` will return for our example data:
@@ -352,4 +352,169 @@ Lets give it a try and lets query `...Contact('KT200038')?$expand=ContactRelatio
}
]
}
-```
\ No newline at end of file
+```
+
+## Custom APIs
+
+Business Central introduced a new default API and also the ability to create custom APIs. These APIs do not reuse pages that were originally designed and intended for the user interface for web services. Besides, these APIs support versioning. A new service endpoint must also be used.
+
+Big advantage: Each API is decoupled from others and can develop on its own.
+
+For this purpose, there is a new page type: API.
+
+Following our example from above, a page for ContactRelations now looks like this:
+
+```AL
+page 50102 "Contact Relation API"
+{
+ PageType = API;
+ APIGroup = 'query';
+ APIPublisher = 'publisher';
+ APIVersion = 'v1.0';
+ EntityName = 'contactRelation';
+ EntitySetName = 'contactRelations';
+ ODataKeyFields = "No.";
+ SourceTable = "Contact Relation";
+
+ layout
+ {
+ area(content)
+ {
+ repeater(General)
+ {
+ field(number; "No.") { }
+ field(contactNo; "Contact No.") { }
+ field(description; "Description") { }
+ field(relationToContactNo; "Relation to Contact No.") { }
+ }
+ }
+ }
+}
+```
+
+May I be forgiven for not using GUIDs as Ids here. Right now I just want to read, not write.
+
+As you notice, a few changes in the properties of the page. ApplicationArea and UsageCategory make no sense any more, instead `APIGroup`, `APIPublisher`, and `APIVersion` have to be defined.
+
+Also we define `EntityName` and `EntitySetName` here.
+
+I also did not set any `ApplicationArea` or `Caption` for fields. Any value of caption is ignored anyway.
+
+The data itself is again OData V4.
+
+Therfore we can query $metadata and check the entity type:
+
+```xml
+
+
+
+
+
+
+
+
+
+```
+### Association
+
+No navigation properties yet. Well, as the custom API is independent of the OData web service, it is required to define also an API for Contact:
+
+``` al
+page 50103 "Contact API"
+{
+ APIGroup = 'queries';
+ APIPublisher = 'publisher';
+ APIVersion = 'v1.0';
+ DelayedInsert = true;
+ EntityName = 'contact';
+ EntitySetName = 'contacts';
+ PageType = API;
+ SourceTable = Contact;
+
+ layout
+ {
+ area(content)
+ {
+ repeater(General)
+ {
+ field(number; "No.") { }
+ field(firstName; "First Name") { }
+ field(surname; Surname) { }
+ field(name; Name) { }
+ field(companyNo; "Company No.") { }
+ }
+ }
+ }
+}
+```
+
+Now both `contactRelation` and `contact` are listed as types in $metadata:
+
+```
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+Also, both types have now a _single_ navigation property `contact`. This looks weird to me, as I expected at least two navigation properties for contactRelation.
+
+When I query the API with $expand and examine the data, it turns out that `contact` in contactRelation holds the contact for **contactNo**. Similarly when investigating the contact type, there the contact of the **companyNo** is revealed.
+
+It turns out that when I change the order of the fields for Contact Relation Api and move the position of field relationToContactNo above the field contactNo, `contact` will hold the contact for **relationToContactNo**.
+
+So far I have not found a way to get and use both navigation properties 🤷♂️. And I dislike the idea that EntityName is used as the name of the navigation 🤦♂️.
+
+### Containments
+
+Maybe we get more insight into containments.
+
+Therefore I add the following part to ContactRelationApi:
+```
+ part(relations; 50102)
+ {
+ EntityName = 'contactRelation';
+ EntitySetName = 'contactRelations';
+ }
+```
+
+Now the navigation properties for contact look like this:
+```xml
+
+
+```
+The name of the part relations is ignored. Instead, we have to declare EntityName and EntitySchema **again**. And it has to be the very same values as defined before on page 50102.
+
+### Conclusion
+The right way is to separate APIs from other APIs or even the UI and develop them independently. Also, a simple association no longer results in a collection.
+
+I don't think I'll get used to the Custom API that quickly, at least when I want to use custom APIs for querying data.
+
+I hope I'm wrong and overlook something obvious.
+
+
+
+
+
+
+
+
+