How call local endpoint from .js file in svelte

268 views Asked by At

I have this routing structure in svelte

lib
 addLog.ts
routes
 +page.svelte
 remote
  log
   +server.js

Server.js is not important as it uses fetch() to call REMOTE api, and add log entry. But it has some credentials thats why it is server only.

+page.svelte contains code (simpliefied)

<script>
import { addLog } from '../lib/addLog';

const userId = 'ai5jkha788sd9';

const addLogOnClick = async () => { await addLog(userId) };
</script>

<main>
    <button on:click={addLogOnClick}>Add user</button>
</man>

but main problem is with lib/addLog.ts

export const addLog = async (userId) => {
    const response = await fetch('/remote/log', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          'logData': {uid: userId}
        }),
      });

      const jResp = await response.json();

      console.log(jResp)
}

But when I click button I get error

Error: Cannot use relative URL (/remote/log) with global fetch — use `event.fetch` instead: https://kit.svelte.dev/docs/web-standards#fetch-apis

Given help reference: https://kit.svelte.dev/docs/web-standards#fetch-apis is not helping very much.

1

There are 1 answers

1
José Ramírez On BEST ANSWER

SvelteKit has this nice thing: Its own fetch() for server-side. This version is very nice because it allows relative URL's and just works. The "regular" fetch() found in NodeJS cannot do that and one must always pass full URL's.

This, however, I mention for clarity because the error you have jumps in code outside the boundaries of this fancy fetch(). It happens inside a regular module. Well, this module should work just fine when running in the browser because the browser's fetch() indeed allows relative URL's. Sveltekit, however, is SSR'ing your code, which requires the use of this module. It is at this time when the problem happens: Now this fetch() in addLog.ts no longer refers to the browser version, it is the NodeJS version because SvelteKit is running your code in the server as part of its SSR functionality.

The solution? You either make the pages that use addLog.ts CSR (client-side rendered) only, or you improve your module so it only runs when run in the client side. For example, a common IF statment would be if (browser):

import { browser } from '$app/environment';

export const addLog = async (userId) => {
    if (!browser) {
        return;
    }
    const response = await fetch('/remote/log', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          'logData': {uid: userId}
        }),
      });

      const jResp = await response.json();

      console.log(jResp)
}

Adding the IF statement on top prevents the code from running in the server side.