Skip to content

Commit 6d8a9dc

Browse files
committed
feat: Implement order confirmation page with server-side loading and error handling
feat: Create product listing page with add to cart functionality and sample products feat: Add favicon for the application chore: Configure SvelteKit with adapter and preprocessors chore: Set up TypeScript configuration for the project chore: Configure Vite for SvelteKit chore: Add TypeScript configuration for the backend
0 parents  commit 6d8a9dc

46 files changed

Lines changed: 9409 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
dist/
2+
node_modules/
3+
.DS_Store
4+
*.tgz

README.md

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
# Commercify API Client
2+
3+
This package provides a convenient way to interact with the Commercify e-commerce backend API from your frontend application.
4+
5+
## Installation
6+
7+
```bash
8+
npm install commercify-api-client
9+
# or
10+
yarn add commercify-api-client
11+
```
12+
13+
This client uses `axios` as a peer dependency, so you will also need to install it in your project:
14+
15+
```bash
16+
npm install axios
17+
# or
18+
yarn add axios
19+
```
20+
21+
## Getting Started
22+
23+
First, create an instance of the API client, providing the base URL of your Commercify backend.
24+
25+
```typescript
26+
import { CommercifyApiClient } from "commercify-api-client";
27+
28+
const apiClient = new CommercifyApiClient("https://api.your-store.com");
29+
```
30+
31+
## Authentication
32+
33+
For endpoints that require authentication, you can set the JWT using the `setAuthToken` method. This is typically done after a user logs in.
34+
35+
```typescript
36+
const jwt = "your-user-jwt-token";
37+
apiClient.setAuthToken(jwt);
38+
```
39+
40+
The client will then automatically include the `Authorization: Bearer <token>` header in all subsequent requests.
41+
42+
### Cookie Handling
43+
44+
The client is also configured to automatically handle cookies. By setting `withCredentials: true`, it will send and receive session cookies, such as the `checkout_session_id`, which is necessary for persisting a user's cart between requests.
45+
46+
---
47+
48+
## Usage in a SvelteKit 5 Application
49+
50+
SvelteKit's server-side capabilities allow you to use this API client securely without exposing your API URL or credentials to the browser.
51+
52+
### 1. Set Environment Variables
53+
54+
In your `.env` file, store your API URL. Prefixing it with `PRIVATE_` ensures it is only available on the server.
55+
56+
**/.env**
57+
58+
```env
59+
PRIVATE_API_URL="https://api.your-store.com"
60+
```
61+
62+
### 2. Create a Server-Side API Module
63+
64+
Create a reusable module to instantiate the client on the server.
65+
66+
**/src/lib/server/api.ts**
67+
68+
```typescript
69+
import { CommercifyApiClient } from "commercify-api-client";
70+
import { PRIVATE_API_URL } from "$env/static/private";
71+
72+
export const createApiClient = (authToken?: string | null) => {
73+
const client = new CommercifyApiClient(PRIVATE_API_URL);
74+
if (authToken) {
75+
client.setAuthToken(authToken);
76+
}
77+
return client;
78+
};
79+
```
80+
81+
### 3. Use Server Hooks
82+
83+
Use a server hook to create a client instance for every request and attach it to the `event.locals` object. This makes the client available to all your `load` functions and `actions`.
84+
85+
First, update your `app.d.ts` to type `locals`:
86+
87+
**/src/app.d.ts**
88+
89+
```typescript
90+
declare global {
91+
namespace App {
92+
interface Locals {
93+
api: import("commercify-api-client").CommercifyApiClient;
94+
}
95+
}
96+
}
97+
98+
export {};
99+
```
100+
101+
Next, create the hook. This example reads an auth token from a secure, `httpOnly` cookie.
102+
103+
**/src/hooks.server.ts**
104+
105+
```typescript
106+
import { createApiClient } from "$lib/server/api";
107+
import type { Handle } from "@sveltejs/kit";
108+
109+
export const handle: Handle = async ({ event, resolve }) => {
110+
const authToken = event.cookies.get("auth_token");
111+
event.locals.api = createApiClient(authToken);
112+
return await resolve(event);
113+
};
114+
```
115+
116+
### 4. Fetch Data in a `load` Function
117+
118+
Now you can access the pre-configured client in any `+page.server.ts` or `+layout.server.ts` file.
119+
120+
**/src/routes/products/+page.server.ts**
121+
122+
```typescript
123+
import type { PageServerLoad } from "./$types";
124+
125+
export const load: PageServerLoad = async ({ locals }) => {
126+
// locals.api is the client instance from our hook
127+
const products = await locals.api.products.search({});
128+
129+
return {
130+
products: products.items,
131+
};
132+
};
133+
```
134+
135+
---
136+
137+
## Usage in a React Application
138+
139+
In a client-side React app, you'll initialize the client and use it within your components.
140+
141+
### 1. Set Environment Variables
142+
143+
Store your public API URL in a `.env` file.
144+
145+
**/.env**
146+
147+
```env
148+
REACT_APP_API_URL="https://api.your-store.com"
149+
```
150+
151+
### 2. Create an API Client Instance
152+
153+
It's good practice to create a single, shared instance of the client.
154+
155+
**/src/apiClient.ts**
156+
157+
```typescript
158+
import { CommercifyApiClient } from "commercify-api-client";
159+
160+
export const apiClient = new CommercifyApiClient(
161+
process.env.REACT_APP_API_URL!
162+
);
163+
```
164+
165+
### 3. Fetch Data in a Component
166+
167+
You can use the `useEffect` and `useState` hooks to fetch data when a component mounts.
168+
169+
**/src/components/ProductList.tsx**
170+
171+
```tsx
172+
import React, { useState, useEffect } from "react";
173+
import { apiClient } from "../apiClient";
174+
import { ProductDTO } from "commercify-api-client";
175+
176+
const ProductList: React.FC = () => {
177+
const [products, setProducts] = useState<ProductDTO[]>([]);
178+
const [loading, setLoading] = useState(true);
179+
180+
useEffect(() => {
181+
const fetchProducts = async () => {
182+
try {
183+
setLoading(true);
184+
const response = await apiClient.products.search({});
185+
setProducts(response.items);
186+
} catch (error) {
187+
console.error("Failed to fetch products:", error);
188+
} finally {
189+
setLoading(false);
190+
}
191+
};
192+
193+
fetchProducts();
194+
}, []);
195+
196+
if (loading) {
197+
return <div>Loading...</div>;
198+
}
199+
200+
return (
201+
<ul>
202+
{products.map((product) => (
203+
<li key={product.id}>{product.name}</li>
204+
))}
205+
</ul>
206+
);
207+
};
208+
209+
export default ProductList;
210+
```
211+
212+
**Tip**: For larger applications, consider using React Context to provide the `apiClient` instance to your component tree, avoiding the need to import it in every file.
213+
214+
---
215+
216+
## Using Mappers
217+
218+
If you need to transform the API data transfer objects (DTOs) into a different shape for your application, you can pass an optional `mapper` function to any API method.
219+
220+
```typescript
221+
// 1. Define your application-specific type
222+
interface ApplicationProduct {
223+
id: number;
224+
productName: string;
225+
}
226+
227+
// 2. Create a mapper function
228+
const productMapper = (dto: ProductDTO): ApplicationProduct => {
229+
return {
230+
id: dto.id,
231+
productName: dto.name,
232+
};
233+
};
234+
235+
// 3. Pass the mapper to the API call
236+
const myProduct: ApplicationProduct = await apiClient.products.get(
237+
123,
238+
productMapper
239+
);
240+
241+
console.log(myProduct.productName); // Already in your desired format!
242+
```

package-lock.json

Lines changed: 29 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"name": "commercify-api-client",
3+
"version": "1.0.1",
4+
"description": "API client for the Commercify backend",
5+
"main": "dist/index.js",
6+
"types": "dist/index.d.ts",
7+
"scripts": {
8+
"build": "tsc"
9+
},
10+
"devDependencies": {
11+
"typescript": "^5.0.0"
12+
},
13+
"packageManager": "pnpm@10.12.4+sha512.5ea8b0deed94ed68691c9bad4c955492705c5eeb8a87ef86bc62c74a26b037b08ff9570f108b2e4dbd1dd1a9186fea925e527f141c648e85af45631074680184"
14+
}

0 commit comments

Comments
 (0)