Add serverFetch hook
#1465
Pull request
This PR base on #1417 (comment) and on all discussion for direct external API requests ( #1417) and headers manipulation from #696.
Basically, now we provide developers full control of how to retrieve data on the server-side and even UNIX sockets can be an option. The test implementation is a little tricky but looks like we have already a similar thing for handles large responses.
Thanks.
Info
This looks cool but right now, let's say i have an external api which depends on users cookies, the cookies only gets send through internal sk endpoints while ssr even if its the same domain. Couldn't we pass the 'server' request to the serverFetch hook? I would currently have to patch package svelte kit to pass request headers to the external api or create an sk endpoint which proxies the request.
Couldn't we pass the 'server' request to the serverFetch hook?
I also thought about it... it will be greater to have, but I am not sure about @Rich-Harris opinion. In that case, we will break the fetch API.
@Kapsonfire-DE thanks! Fixed.
I haven't gotten a chance to take a look at this one to think about whether I think this is the best solution or not yet, but it would probably need the documentation to be updated as well
@benmccann ok, I will prepare it. Also, my project has already used it with good results. Also, please check @pixelmund idea, probably serverFetch shouldn't reproduce fetch API.
I added some documentation but I think changelog will be better to add after final approves of the concept.
Kudos for getting this going. I was struggling the logic flow with how SK handles requests and getting that to work with an app that only connects with external APIs (no frontend page protection).
Question with this new serverFetch method....what is the pattern for capturing cookies?
I have an external API that operates in this way:
- Call an endpoint to identify the type of authentication that is configured on the backend server. This returns a session_id cookie.
- Depending on the response value, it may require username/password, some kind of existing authentication token (i.e. SAML), auto-negotiate, or OAuth2.
- If OAuth2, we have to display their authentication page to capture the token and update the cookies accordingly.
I am building a wrapper class library for this API that will take care of all the external api communication (not using routes).
Will headers be available to the serverFetch without having to put code in the frontend (i.e hooks.js and routes)?
Will headers be available to the serverFetch without having to put code in the frontend (i.e hooks.js and routes)?
The serverFetch reuses the Request object from your fetch call in load function and you can copy your headers into a new request. Probably you are talking about @pixelmund idea?
I realize @pixelmund was also asking about headers, but wasn't sure if this enhancement addressed that or not from the comments I read above (which is why I was asking).
In my use case, the application connects to multiple external APIs (i.e. Salesforce, Snowflake, etc.) not for access to the application itself, but for usage of the systems it interacts with. For this to go through the current hooks and /route endpoints makes writing a wrapper API class awkward in that it has to depend on a tight frontend integration (which is what I am trying to avoid by creating a wrapper class in the first place).
If this serverFetch is not going to address this use case, should I open an enhancement request?
My original thought was to propose something like the following:
export default class MyAPI {
#baseurl;
#data;
async Init (url) {
this.#baseurl = url + "/api/v1/";
let url = this.#baseurl + 'Server'
let resp = await fetch(url, {
method: 'GET',
render: 'client', // (could also be 'server' but headers will be undefined)
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
credentials: 'same-origin',
})
if (resp.status != 200) {
console.log(`${url} => ${resp.status}:${resp.statusText}`)
throw new Error(`Unable to connect to server at specified URL [${this.#baseurl}]`)
}
// Available in this wrapper class when render = 'client'
let sessionID = resp.headers.cookie('session_id')
this.#data = await resp.json()
}
}
When the render option of 'client' is received by SK, it will force the fetch request to be executed client side so that the cookies can be returned back to the caller without requiring boilerplate-y code in hooks and routes. If the value is 'server' (default) then it would operate the same as it does today.
Thoughts?
ok, I will back soon
If this serverFetch is not going to address this use case, should I open an enhancement request?
serverFetch can help here in your case, because you can write your communication with external API directly without proxy on the SvelteKit side.
serverFetchcan help here in your case, because you can write your communication with external API directly without proxy on the SvelteKit side.
Excellent! 👏 I am curious to see how it operates with an OAuth2 credentialed API. If you have any examples of how we would render (the "SK way") the authentication url to the client using serverFetch, that would be really helpful.
I updated SK to .114 and see that ServerFetch is defined in hooks.d.ts. So I implemented the serverFetch callback in my hooks.js, but I am not sure how it is supposed to be triggered.
In my app, I am using a non-relative path (i.e. http://....) but it is not calling the serverFetch hook. Is there a different way this is supposed to be triggered?
@SGarno this PR has not been checked in or released yet, which is indicated by its open status. I'm not sure what you're talking about, but the feature is not available
finally got round to reviewing/merging this. thank you!
Related #1784 This breaks the node-adapter sveltekit builds
Pro tip: You can prefix GitHub URLs of issues, PRs or discussions with svcl.dev/ to view them on this page! Also try it on a GitHub release ;)