diff --git a/README.md b/README.md index afaa7d26..4ab248c8 100755 --- a/README.md +++ b/README.md @@ -257,6 +257,36 @@ window.storyblok.on('input', (event) => { }) ``` +## customFetch Function + +The `customFetch` function is a custom implementation of the fetch API to be used alongside the client's calls. It is designed to handle different types of `BodyInit` in the `SbFetch` methods (`get`, `post`, `put`, `delete`). + +### Examples + +Here's an example of how to use the `customFetch` function: + +```typescript +const client = new StoryblokClient({ + accessToken: ACCESS_TOKEN, + oauthToken: OAUTH_TOKEN, +}) + +// GET request +client + .customFetch(`spaces/${SPACE_ID}/stories`, { method: 'GET' }) + .then((response) => console.log(response)) + .catch((error) => console.error(error)) + +// POST request with JSON body +client + .customFetch(`spaces/${SPACE_ID}/stories`, { + method: 'POST', + body: JSON.stringify({ key: 'value' }), + }) + .then((response) => console.log(response)) + .catch((error) => console.error(error)) +``` + ### Method `Storyblok#get` With this method you can get single or multiple items. The multiple items are paginated and you will receive 25 items per page by default. If you want to get all items at once use the `getAll` method. diff --git a/src/index.ts b/src/index.ts index de886491..7529e32d 100755 --- a/src/index.ts +++ b/src/index.ts @@ -85,19 +85,13 @@ class Storyblok { public constructor(config: ISbConfig, pEndpoint?: string) { let endpoint = config.endpoint || pEndpoint - if (!endpoint) { - const getRegion = new SbHelpers().getRegionURL - const protocol = config.https === false ? 'http' : 'https' - - if (!config.oauthToken) { - endpoint = `${protocol}://${getRegion(config.region)}/${ - 'v2' as Version - }` - } else { - endpoint = `${protocol}://${getRegion(config.region)}/${ - 'v1' as Version - }` - } + const getRegion = new SbHelpers().getRegionURL + const protocol = config.https === false ? 'http' : 'https' + + if (!config.oauthToken) { + endpoint = `${protocol}://${getRegion(config.region)}/${'v2' as Version}` + } else { + endpoint = `${protocol}://${getRegion(config.region)}/${'v1' as Version}` } const headers: Headers = new Headers() @@ -160,6 +154,40 @@ class Storyblok { }) } + public customFetch(url: string, options: RequestInit) { + // Create a new SbFetch instance with the custom fetch function + const customClient = new SbFetch({ + baseURL: this.client.baseURL, + headers: this.client.headers, + fetch: (...args: [any]) => fetch(...args), + }) + + let method + let params + switch ((options.method || 'get').toLowerCase()) { + case 'get': + method = customClient.get.bind(customClient) + params = {} // GET requests typically don't have a body + break + case 'post': + method = customClient.post.bind(customClient) + params = JSON.parse(options.body as string) + break + case 'put': + method = customClient.put.bind(customClient) + params = JSON.parse(options.body as string) + break + case 'delete': + method = customClient.delete.bind(customClient) + params = JSON.parse(options.body as string) + break + default: + throw new Error(`Invalid method: ${options.method}`) + } + + return method(`/${url}`, params) + } + public setComponentResolver(resolver: ComponentResolverFn): void { this.richTextResolver.addNode('blok', (node: ISbNode) => { let html = '' diff --git a/src/sbFetch.ts b/src/sbFetch.ts index 1199f3c8..ef8b7a94 100644 --- a/src/sbFetch.ts +++ b/src/sbFetch.ts @@ -16,9 +16,9 @@ interface ISbFetch { } class SbFetch { - private baseURL: string + public baseURL: string private timeout?: number - private headers: Headers + public headers: Headers private responseInterceptor?: ResponseFn private fetch: typeof fetch private ejectInterceptor?: boolean diff --git a/tests/customFetch.test.js b/tests/customFetch.test.js new file mode 100644 index 00000000..38ec5048 --- /dev/null +++ b/tests/customFetch.test.js @@ -0,0 +1,82 @@ +import { expect, test, describe, beforeEach } from 'vitest' +import StoryblokClient from '../' + +const generateJibberishWord = (length) => { + const characters = 'abcdefghijklmnopqrstuvwxyz' + let jibberishWord = '' + + for (let i = 0; i < length; i++) { + const randomIndex = Math.floor(Math.random() * characters.length) + jibberishWord += characters.charAt(randomIndex) + } + + return jibberishWord +} + +console.log('env =>', process.env) + +describe('define environment variables', () => { + test('Accessing Environment Variables', () => { + const accessToken = process.env.VITE_ACCESS_TOKEN; + const oauthToken = process.env.VITE_OAUTH_TOKEN; + const spaceId = process.env.VITE_SPACE_ID; + + expect(accessToken).not.toEqual(''); + expect(oauthToken).not.toEqual(''); + expect(spaceId).not.toEqual(''); + }); +}) + +describe('customFetch', () => { + let client + const url = `spaces/${process.env.VITE_SPACE_ID}/stories` + + beforeEach(() => { + client = new StoryblokClient({ + oauthToken: process.env.VITE_OAUTH_TOKEN, + }) + }) + + test('should call GET method', async () => { + const response = await client.customFetch( + url, + { + method: 'GET', + body: {}, + } + ) + expect(response).toHaveProperty('data') + }) + + test('should call POST method', async () => { + const jibberish = generateJibberishWord(8) + const postObject = { + story: { + name: 'Test', + slug: jibberish, + content: { + component: 'page', + text: 'test', + }, + }, + } + const response = await client.customFetch( + url, + { + method: 'POST', + body: JSON.stringify(postObject), + } + ) + expect(response.data.story.id).toBeTruthy() + }) + + test('should return an error for invalid method', async () => { + try { + await client.customFetch(url, { + method: 'INVALID', + }) + } catch (error) { + expect(error).toHaveProperty('message') + } + }) +})