cancel
Showing results for 
Search instead for 
Did you mean: 
Read only

SF API Select Using Navigation Property

huseyindereli
Active Contributor
0 Kudos
18,626

Hi,

I'm using Cloud SDK for Javascript to fetch some data from SF OData API. It's working smoothly. ( Foundation platform, User Management API )

const getUserData = async function (userId) {
  const userApi = new UserApi();
  const resp = await userApi
    .requestBuilder()
    .getAll()
    .select(
      userApi.schema.USER_ID,
      userApi.schema.JOB_CODE,
      userApi.schema.DIVISION,
      userApi.schema.CUSTOM_01,
      userApi.schema.CUSTOM_02,
      userApi.schema.CUSTOM_03,
      userApi.schema.CUSTOM_04,
      userApi.schema.TOTAL_TEAM_SIZE,
      userApi.schema.DEFAULT_FULL_NAME,
      userApi.schema.LOCATION,
      userApi.schema.TITLE
    )
    .filter(userApi.schema.USER_ID.equals(userId))
    .execute({ destinationName: _dest });
  return resp;
};

But when I add a navigation property to select at the bottom of the TITLE like;

userApi.schema.HR

it's throwing an error (Cannot read properties of undefined (reading '_fieldName'))

When I add it like this;

userApi.schema.HR.select(userApi.schema.USER_ID)

It also throws an error ( Cannot read properties of undefined (reading 'select') )

I also couldn't find a specific schema for that Navigation Property (HR).

Any ideas how to get navigation properties ?

Accepted Solutions (1)

Accepted Solutions (1)

frank_essenberger1
Product and Topic Expert
Product and Topic Expert

The service object contains all APIs, it is a sort of umbrella object. This object has all the apis. I generated the code and added a navigation property (HR). I have no SFSF to test a actual call so I just generated the URL:

const service = require('./plt-user-management-service/service')

const userApi = service.pltUserManagementService().userApi

userApi.requestBuilder().getAll().select(userApi.schema.NICKNAME, userApi.schema.HR)
.url({url: 'http://foo.com'})
.then(url => console.log(url))

which gives me in the console:

http://foo.com/successfactors/odata/v2/User?$select=hr/*,nickname&$expand=hr

which looks ok. Can you give it a try using the service and access the userApi not via the constructor directly. You can also remove the core package, since it is version 1 which is not needed when you have the more granular version 2 packages.BestFrank
huseyindereli
Active Contributor
0 Kudos

Thanks so much Frank! It worked. Though I didn't get why it wasn't working with the first approach. Or the difference between these two calls.

One thing to note, when I try getting specific fields of the navigation prop, it's woorking.

  const resp = await userApi
    .requestBuilder()
    .getAll()
    .select(
      userApi.schema.USER_ID,
      userApi.schema.TITLE,
      userApi.schema.HR.select(userApi.schema.USER_ID)
    )
But when I try to select all as you proposed above, it throws an error related with the * at the beginning of constructed url.
  const resp = await userApi
    .requestBuilder()
    .getAll()
    .select(
      userApi.schema.USER_ID,
      userApi.schema.TITLE,
      userApi.schema.HR
    )

Unable to understand API request with character sequence: hr/*,userId,jobCode,division,custom01,custom02,custom03,custom04,totalTeamSize,defaultFullName,location,title

Cheers.

frank_essenberger1
Product and Topic Expert
Product and Topic Expert

The difference is that when you access it via the service (intenden way) some getters are invoked which initialize some fields. The problem is that JS does not have any proper protection so even if we mark the constructor as private you could still use it.

Why the `*` is not working is not clear to me. I think it is proper OData notation, however sometimes the backend systems do not implement all OData features correctly. I hope the selection of the explicit fields is acceptable for your usecase?

huseyindereli
Active Contributor
0 Kudos

I've just seen your comment. Yes that is enough in my case. I had already found a workaround but I was curious about the cloud SDK call and your answer showed me the way of accessing the service via the service 🙂 . I did replace this with my workaround.

Thanks again for your help and your comment on the difference.

Answers (3)

Answers (3)

Junjie
Product and Topic Expert
Product and Topic Expert
0 Kudos

I guess Frank showed the key to solve the issue, which is the initialization of the "userApi"

const userApi = service.pltUserManagementService().userApi

In general, this documentation shows how to execute an odata request.

In addition, for odata v2 specific details you can check this documentation, where you can find e.g., how to "$select" properties here.

frank_essenberger1
Product and Topic Expert
Product and Topic Expert
0 Kudos

I also tried with the `new UserApi()` and I got the error `TypeError: Cannot read properties of undefined (reading '_fieldName')`. So I am pretty sure the error should go away when you access it via the service as indicated by the snippet above.

frank_essenberger1
Product and Topic Expert
Product and Topic Expert
0 Kudos

Great that you use the SDK and it also runs smooth in most cases.

Before I investigate the problem using your service, could you try one quick thing. Can you get the api via the service object as describede here: https://sap.github.io/cloud-sdk/docs/js/features/odata/v2-client#select

const { businessPartnerApi, businessPartnerAddressApi } =
businessPartnerService();
businessPartnerApi
.requestBuilder()
.getAll()
.select(
businessPartnerApi.schema.FIRST_NAME,
businessPartnerApi.schema.TO_BUSINESS_PARTNER_ADDRESS.select(
businessPartnerAddressApi.schema.ADDRESS_ID,
businessPartnerAddressApi.schema.CITY_CODE
)
)
.execute(destination);


We do some init stuff within the service object. Let me know if it helps. If not I try to reproduce the error. Also if you face issues in the future feel free to open an issue on our OS repo: https://github.com/SAP/cloud-sdk-js/issues

We monitor all channels but the repo is our preferred one since it integrates best with our daily work flow.

Best

Frank

huseyindereli
Active Contributor
0 Kudos

Thanks Frank for your quick response. Actually that link is a great source of information. I've been using it since the beginning but I couldn't find the type that HR navigation property is represented like businessPartnerAddressApi .

Also there is no UserService that I can use and I couldn't find HR definition in any of the classes.

Could this problem be specific to the SF APIs ? I can open an issue if you want to continue on that channel.

const { UserApi } = require("../generated/plt-user-mng/UserApi");

Dependencies;

"@sap-cloud-sdk/connectivity": "^2.10.0",

"@sap-cloud-sdk/core": "^1.54.2",

"@sap-cloud-sdk/odata-v2": "^2.10.0",

"@sap-cloud-sdk/generator": "^2.10.0",