Skip to content

Commit 622e27b

Browse files
authored
docs: update handling custom occ endpoints recipe (#7405)
1 parent a8b041e commit 622e27b

File tree

1 file changed

+90
-79
lines changed

1 file changed

+90
-79
lines changed
+90-79
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,36 @@
11
# Handling custom OCC endpoints
22

33
It is a common task to add support for a custom (non-standard) SAP OCC API endpoint not covered by the Alokai intergration.
4-
This guide will show you how can do it using Alokai.
4+
There are two ways how you can do it:
55

6-
## Prerequisites
6+
1. Generate new API client based on OpenAPI (swagger) specification.
7+
2. Add support for a custom endpoint manually.
78

8-
Before we start make sure that you are familiar with [Adding New API Methods](https://docs.alokai.com/storefront/integration-and-setup/storefront-extension#adding-new-api-methods) guide. With that guide, you would be able to
9+
## Generating new API client
10+
11+
Generation of new API client allows you to add support for all custom endpoints at once. You just run a script and all the endpoints will be added to the integration.
12+
13+
How to do this is described in the [Generated API guide](/integrations/sapcc/features/generated-api).
14+
15+
This should be your default approach, because it is the most scalable and maintainable way.
16+
17+
## Adding support for a custom endpoint manually
18+
19+
If you don't want or cannot generate a new API client, you can add support for a custom endpoint manually.
20+
It boils down to adding a new API method to the middleware that calls the custom endpoint. This guide shows how to do it efficiently.
21+
22+
When to use this approach?
23+
24+
- When for some reason you cannot generate a new API client, e.g. OpenAPI specification is not available.
25+
- When you are iterating fast both on the API and the front-end and you don't want to regenerate the API client for each change.
26+
27+
### Prerequisites
28+
29+
Before we start make sure that you are familiar with [Adding New API Methods](/unified-data-layer/integration-and-setup/creating-new-api-methods) guide. With that guide, you would be able to
930
communicate with OCC API but it would require manual retrieval of context parameters (baseSiteId, userId, language,
1031
and currency) and preparation of authorization headers. Read on to see how to streamline that process.
1132

12-
## Communicating with OCC API effectively
33+
### Communicating with OCC API effectively
1334

1435
OCC endpoints have a given structure
1536

@@ -35,74 +56,69 @@ Here's where to find the parameters:
3556

3657
- `baseUrl` - is configured in .env file as `SAPCC_API_URI`. The api client already knows it and prepends each URL with it.
3758
- `baseSiteId` - is defined in the middleware configuration. That configuration is exposed to api method via context.
38-
- `userId` - can be found in the request cookies under [`AUTH_USER_COOKIE_NAME`](https://docs.alokai.com/integrations/sapcc/api/sapcc-api/AUTH_USER_COOKIE_NAME).
39-
- `language` - can be found in the request cookies under [`VSF_LOCALE_COOKIE`](https://docs.alokai.com/storefront/features/internationalization/internatialization-support).
40-
- `currency` - can be found in the request cookies under [`VSF_CURRENCY_COOKIE`](https://docs.alokai.com/storefront/features/internationalization/currency-switching).
41-
- authorization token - can be found in the request cookies under [`AUTH_USER_TOKEN_COOKIE_NAME`](https://docs.alokai.com/integrations/sapcc/api/sapcc-api/AUTH_USER_TOKEN_COOKIE_NAME)
59+
- `userId` - can be found in the request cookies under [`AUTH_USER_COOKIE_NAME`](/integrations/sapcc/api/sapcc-api/AUTH_USER_COOKIE_NAME).
60+
- `language` - can be found in the request cookies under [`VSF_LOCALE_COOKIE`](/storefront/features/internationalization/internatialization-support).
61+
- `currency` - can be found in the request cookies under [`VSF_CURRENCY_COOKIE`](/storefront/features/internationalization/currency-switching).
62+
- authorization token - can be found in the request cookies under [`AUTH_USER_TOKEN_COOKIE_NAME`](/integrations/sapcc/api/sapcc-api/AUTH_USER_TOKEN_COOKIE_NAME)
4263

4364
You don't have to parse the cookies yourself. Alokai provides helper methods for that. Here’s a code example of how to do it:
4465

45-
```typescript
46-
import {
47-
SapccIntegrationContext,
48-
TokenModes,
49-
createRequestOptions,
50-
getUserIdFromRequest,
51-
} from "@vsf-enterprise/sapcc-api";
52-
import { BaseProps, BaseUserId } from "@vsf-enterprise/sapcc-types";
66+
```typescript [apps/storefront-middleware/api/custom-methods/types.ts]
67+
import { BaseProps, BaseUserId } from '@vsf-enterprise/sapcc-types';
5368

54-
export interface CustomEndpointProps extends BaseProps, BaseUserId {
69+
export interface CustomMethodArgs extends BaseProps, BaseUserId {
5570
customField: any;
5671
}
5772

58-
export interface CustomResponse {
73+
export interface CustomMethodResponse {
5974
whatever: any;
6075
}
76+
```
77+
78+
```typescript [apps/storefront-middleware/api/custom-methods/custom.ts]
79+
import { createRequestOptions, getUserIdFromRequest, TokenModes } from '@vsf-enterprise/sapcc-api';
80+
import { type IntegrationContext } from '../../types';
81+
import type { CustomMethodArgs, CustomMethodResponse } from './types';
6182

62-
const callCustomEndpoint = async (
63-
context: SapccIntegrationContext,
64-
props: CustomEndpointProps
65-
): Promise<CustomResponse> => {
83+
export async function exampleCustomMethod(
84+
context: IntegrationContext,
85+
args: CustomMethodArgs,
86+
): Promise<CustomMethodResponse> {
6687
const { config, req, client } = context;
6788

68-
const userId = getUserIdFromRequest({ req, props } as any); // retrieves userID from props or cookies
89+
const userId = getUserIdFromRequest({ context, props: args }); // retrieves userID from props or cookies
6990

7091
const res = await client.get(
71-
`/${config.api.baseSiteId}/users/${userId}/customEndpoint/${props.customField}`,
92+
`/${config.api.baseSiteId}/users/${userId}/customEndpoint/${args.customField}`,
7293
createRequestOptions({
7394
// adds authorization headers and language & currency parameters
7495
context,
75-
props,
96+
props: args,
7697
tokenMode: TokenModes.CUSTOMERORAPPLICATION,
77-
})
98+
}),
7899
);
79100

80101
return res.data;
81-
};
102+
}
103+
82104
```
83105

84106
Read more about the helper methods:
85107

86-
- [getUserIdFromRequest](https://docs.alokai.com/integrations/sapcc/api/sapcc-api/getUserIdFromRequest)
87-
- [createRequestOptions](https://docs.alokai.com/integrations/sapcc/api/sapcc-api/createRequestOptions)
108+
- [getUserIdFromRequest](/integrations/sapcc/api/sapcc-api/getUserIdFromRequest)
109+
- [createRequestOptions](/integrations/sapcc/api/sapcc-api/createRequestOptions)
88110

89-
## Real life example
111+
### Real life example
90112

91-
Here's an example implementation of the product interest feature. This feature is available in OCC API, but not in the middleware and SDK integration.
113+
Here's an example implementation of the product interest feature.
92114
Let's add support for it.
93115

94-
First, you need to add a new API method in the middleware. (For simplicity, this guide shows how to do it in one file, but we recommend splitting it into multiple files to maintain cleaner code.)
116+
First, you need to add a new API method in the middleware.
95117

96-
```typescript [storefront-middleware/middleware.config.ts]
97-
import {
98-
SapccIntegrationContext,
99-
TokenModes,
100-
createRequestOptions,
101-
getUserIdFromRequest,
102-
} from "@vsf-enterprise/sapcc-api";
103-
import { BaseProps, BaseUserId, Product } from "@vsf-enterprise/sapcc-types";
118+
```typescript [apps/storefront-middleware/api/custom-methods/types.ts]
119+
import { BaseProps, BaseUserId, Product } from '@vsf-enterprise/sapcc-types';
104120

105-
export interface GetProductInterestsProps extends BaseProps, BaseUserId {
121+
export interface GetProductInterestsArgs extends BaseProps, BaseUserId {
106122
productCode?: string;
107123
}
108124
export interface ProductInterestEntry {
@@ -118,66 +134,61 @@ export interface UserInterestsResponse {
118134
results: Array<ProductInterestRelation>;
119135
}
120136

121-
const getProductInterests = async (
122-
context: SapccIntegrationContext,
123-
props: GetProductInterestsProps
124-
): Promise<UserInterestsResponse> => {
125-
const { config, req, client } = context;
137+
```
126138

127-
const userId = getUserIdFromRequest({ req, props } as any);
139+
```typescript [apps/storefront-middleware/api/custom-methods/custom.ts]
140+
import { createRequestOptions, getUserIdFromRequest, TokenModes } from '@vsf-enterprise/sapcc-api';
141+
import { type IntegrationContext } from '../../types';
142+
import type { GetProductInterestsArgs, UserInterestsResponse } from './types';
143+
144+
export async function getProductInterests(
145+
context: IntegrationContext,
146+
args: GetProductInterestsArgs,
147+
): Promise<UserInterestsResponse> {
148+
const { config, client } = context;
149+
150+
const userId = getUserIdFromRequest({ context, props: args });
128151

129152
const requestOptions = createRequestOptions({
130153
context,
131-
props,
154+
props: args,
132155
tokenMode: TokenModes.CUSTOMERORAPPLICATION,
133156
});
134157

135-
const res = await client.get(
136-
`/${config.api.baseSiteId}/users/${userId}/productinterests`,
137-
{
138-
...requestOptions,
139-
params: {
140-
...requestOptions.params,
141-
productCode: props.productCode,
142-
},
143-
}
144-
);
158+
const res = await client.get(`/${config.api.baseSiteId}/users/${userId}/productinterests`, {
159+
...requestOptions,
160+
params: {
161+
...requestOptions.params,
162+
productCode: args.productCode,
163+
},
164+
});
145165

146166
return res.data;
147-
};
148-
149-
const apiMethods = methods<typeof normalizers>();
150-
const unifiedApiExtension = createUnifiedExtension<Context, Config>()({
151-
normalizers,
152-
apiMethods: {
153-
...apiMethods,
154-
getProductInterests,
155-
},
156-
config: {
157-
/* ... */
158-
},
159-
});
167+
}
168+
```
169+
170+
```typescript [apps/storefront-middleware/api/custom-methods/index.ts]
171+
export { getProductInterests } from './custom';
172+
export * from './types';
160173
```
161174

162175
Then, in your frontend application, you need to add a custom hook to retrieve the product interests on the front end.
163176

164177
```typescript [storefront-unified-nextjs/hooks/useProductInterests/useProductInterests.ts]
165-
import { useQuery } from "@tanstack/react-query";
166-
import { InferSdkArgs, useSdk } from "~/sdk";
178+
import { useQuery } from '@tanstack/react-query';
167179

168-
export type GetProductInterestsArgs = InferSdkArgs<"getProductInterests">;
180+
import { useSdk } from '@/sdk/alokai-context';
169181

170-
export function useProductInterests({ productCode }: GetProductInterestsArgs) {
182+
export function useProductInterests({ productCode }: { productCode: string }) {
171183
const sdk = useSdk();
172184

173185
return useQuery({
174-
queryKey: ["product interests", productCode],
175186
queryFn: () =>
176-
sdk.unified.getProductInterests({
187+
sdk.customExtension.getProductInterests({
177188
productCode,
178189
}),
179-
refetchOnMount: false,
180-
refetchOnWindowFocus: false,
190+
queryKey: ['product interests', productCode],
181191
});
182192
}
193+
183194
```

0 commit comments

Comments
 (0)