Skip to content

Commit ffc6d70

Browse files
committed
Merge branch 'main' of https://github.com/vuestorefront/vue-storefront into docs/multibrand2
2 parents 9e06cb8 + 431463b commit ffc6d70

38 files changed

+5684
-773
lines changed

.node-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
18
1+
22.14.0
Lines changed: 90 additions & 79 deletions
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
```

docs/content/guides/1.index.md

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,26 @@ Alokai is not a cookie-cutter solution, it is meant to be able to handle even th
3434
Learn how to create efficient and unified multigeo/multibrand/multivendor setups with Alokai.
3535
::
3636

37-
#section-4
38-
:card{to="/guides/kubernetes-probe" title="Kubernetes Probes" description="Alokai Cloud customers' middleware and frontend apps are deployed in Kubernetes. Check how Kubernetes mechanisms are used by Alokai Cloud" icon="tabler:heart-rate-monitor"}
37+
::
38+
39+
## Advanced
3940

40-
#section-5
41-
:card{to="/guides/best-practices" title="Best Practices" description="Check what to follow to keep your storefront in the best possible shape" icon="tabler:rosette-discount-check"}
41+
::card{title="Kubernetes Probes" to="/guides/kubernetes-probe" class="mb-5" icon="tabler:heart-rate-monitor"}
42+
#description
43+
Learn how to implement health check endpoints for your Alokai Cloud applications running on Kubernetes. This guide covers liveness and readiness probes implementation to ensure proper application monitoring and reliability.
44+
::
4245

46+
## Best Practices
4347

48+
::card{title="Performance" to="/guides/best-practices/performance" class="mb-5" icon="tabler:rosette-discount-check"}
49+
#description
50+
Every 100ms added to loading time costed Amazon 1% less sales. Don't let the poor performance to ruin your sales. Learn how to optimize your store for speed.
4451
::
4552

53+
::card{title="Data Fetching" icon="tabler:mobiledata" to="/guides/best-practices/data-fetching" }
54+
#description
55+
Learn how to optimize your data fetching strategy to improve performance and avoid caching errors.
56+
::
4657

4758
## Advanced
4859

@@ -61,4 +72,3 @@ Every 100ms added to loading time costed Amazon 1% less sales. Don't let the poo
6172
::info
6273
Can't find what you're looking for? Check out our [cookbook](/cookbook) for more guides and tutorials.
6374
::
64-
Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
1+
---
2+
title: Guides
3+
layout: default
4+
---
5+
16
# Best Practices
27

38
In this guide, we have compiled a collection of best practices to help you optimize your development workflow, improve code quality, and ensure maintainability.
49

5-
::card{title="Data Fetching" icon="tabler:mobiledata" to="/guides/best-practices/data-fetching" }
10+
::card{title="Performance" to="/guides/best-practices/performance" class="mb-5" icon="tabler:rosette-discount-check"}
11+
#description
12+
Every 100ms added to loading time costed Amazon 1% less sales. Don't let the poor performance to ruin your sales. Learn how to optimize your store for speed.
13+
::
14+
15+
::card{title="Data Fetching" icon="tabler:mobiledata" to="/guides/best-practices/data-fetching" }
16+
#description
17+
Learn how to optimize your data fetching strategy to improve performance and avoid caching errors.
18+
::

docs/content/guides/6.best-practices/2.data-fetching.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ The rule of thumb is: _always use server-side fetching except for_:
4242

4343
Alokai architecture introduces the Middleware in between the front-end application and the APIs. This adds two additional possible routes to our diagram, but most of the traffic should go through the middleware, because:
4444

45-
- it is cached on the CDN
45+
<!-- Uncomment below when CDN caching is availavble -->
46+
<!-- - it is cached on the CDN -->
4647
- it keeps your architecture simple
4748
- you can easily monitor middleware traffic in the console
4849
- enables [data federation](/middleware/guides/federation)
@@ -58,13 +59,17 @@ Fortunately, we can reject the route between the server and the API, because:
5859
The direct route between the browser and API should be avoided, because it:
5960

6061
- tightly couples storefront with the API,
61-
- reduces performance by bypasses CDN cache.
62+
<!-- Uncomment below when CDN caching is availavble -->
63+
<!-- - reduces performance by bypassing CDN cache. -->
6264

6365
Use direct direct browser to API calls only when communicating via middleware is not possible or requires unnecessary effort. Sample scenarios when it might be valid to communicate directly between client and API:
6466

6567
- the communication requires extremely low latency - e.g. voice or video stream
6668
- communication with API is done via some SDK that requires direct client (browser) interaction - e.g. analytics or authentication services
6769

70+
71+
<!-- Uncomment below when CDN caching is availavble -->
72+
<!-- ## CDN Caching
6873
## CDN Caching
6974
7075
To further improve your application performance we encourage you to enable the CDN. The CDN is capable of caching responses from the server and the middleware to the browser.
@@ -73,7 +78,7 @@ To further improve your application performance we encourage you to enable the C
7378
7479
::info
7580
[Read more about caching here.](/storefront/features/cdn/making-ssr-cacheable)
76-
::
81+
:: -->
7782

7883
## Examples
7984

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
title: Performance
2+
sidebarRoot: true
3+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
title:
3+
layout: default
4+
---
5+
6+
# Multistore
7+
8+
On this page you'll find a set of guides that will help you to understand the fundamentals of Alokai and how different parts of our stack will help you to build your Alokai application.
9+
10+
Below you will find a list of guides to help you get started with Alokai.
11+
12+
::card{title="Introduction" icon="tabler:align-box-center-middle" to="/guides/multistore/introduction" }
13+
14+
#description
15+
Learn what challenges the Alokai Multistore solution addresses and how it can help you solve them.
16+
::
17+
18+
<br />
19+
20+
::card{title="Tooling and concepts" icon="tabler:tools" to="/guides/multistore/tooling-and-concepts" }
21+
22+
#description
23+
Learn the concepts and tools behind the Alokai Multistore solution.
24+
::
25+
26+
<br />

0 commit comments

Comments
 (0)