Implementation:Langgenius Dify Service Fetch
| Knowledge Sources | |
|---|---|
| Domains | Frontend, API_Service |
| Last Updated | 2026-02-12 07:00 GMT |
Overview
Low-level ky-based HTTP fetch wrapper that handles URL prefix resolution, CSRF header injection, credential management, content-type negotiation, and error hook orchestration for all Dify API requests.
Description
fetch.ts provides the foundational HTTP client used by base.ts and is built on top of the ky library. It defines the base function that orchestrates every API call in the application. The module resolves the correct URL prefix (API_PREFIX, PUBLIC_API_PREFIX, or MARKETPLACE_API_PREFIX) based on IOtherOptions flags. It automatically injects CSRF headers from cookies using js-cookie and handles content-type header management (including deletion for multipart uploads). For public API calls, a beforeRequestPublicWithCode hook adds the Authorization header from the webapp access token and sets share code and passport headers extracted from the URL path. The module configures ky hooks: afterResponse204 converts 204 responses to JSON success responses, afterResponseErrorCode handles non-2xx/3xx responses with toast notifications and 401 rejection, and beforeErrorToast displays error messages. The base function supports a fetchCompat mode that skips base options for raw Request objects, and a custom fetch wrapper that merges headers from both the Request object and options. It also exports postWithKeepalive for fire-and-forget POST requests during page unload that use keepalive: true to survive navigation. The ContentType constant provides common MIME type strings, and getBaseOptions returns default request initialization options.
Usage
This module is primarily consumed internally by base.ts and should not typically be imported directly by application code. Use it when you need access to the ContentType constants, getBaseOptions for SSE request setup, or the postWithKeepalive function for page-unload analytics or cleanup calls.
Code Reference
Source Location
- Repository: Langgenius_Dify
- File: web/service/fetch.ts
- Lines: 1-269
Signature
// Content type constants
export const ContentType = {
json: 'application/json',
stream: 'text/event-stream',
audio: 'audio/mpeg',
form: 'application/x-www-form-urlencoded; charset=UTF-8',
download: 'application/octet-stream',
downloadZip: 'application/zip',
upload: 'multipart/form-data',
}
// Fetch option type
export type FetchOptionType = Omit<RequestInit, 'body'> & {
params?: Record<string, any>
body?: BodyInit | Record<string, any> | null
}
// Response error type
export type ResponseError = {
code: string
message: string
status: number
}
// Default request options
export const getBaseOptions = (): RequestInit
// Core fetch function wrapping ky
async function base<T>(
url: string,
options?: FetchOptionType,
otherOptions?: IOtherOptions
): Promise<T>
// Fire-and-forget POST for page unload
export function postWithKeepalive(
url: string,
body: Record<string, unknown>
): void
export { base }
Import
import { base, ContentType, getBaseOptions } from '@/service/fetch'
import { postWithKeepalive } from '@/service/fetch'
import type { FetchOptionType, ResponseError } from '@/service/fetch'
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| url | string | Yes | API endpoint path relative to the resolved prefix |
| options | FetchOptionType | No | Request options including params (query string), body, headers, and standard RequestInit fields |
| otherOptions.isPublicAPI | boolean | No | Routes through PUBLIC_API_PREFIX, enables share code and passport headers |
| otherOptions.isMarketplaceAPI | boolean | No | Routes through MARKETPLACE_API_PREFIX with omitted credentials |
| otherOptions.bodyStringify | boolean | No | When true (default), serializes body as JSON via ky's json option |
| otherOptions.needAllResponseContent | boolean | No | When true, returns the raw Response object instead of parsed JSON |
| otherOptions.deleteContentType | boolean | No | When true, removes Content-Type header (for multipart uploads) |
| otherOptions.fetchCompat | boolean | No | When true, skips base options for raw Request compatibility |
| otherOptions.silent | boolean | No | Suppresses error toast notifications |
| otherOptions.request | Request | No | Raw Request object to use instead of URL string |
Outputs
| Name | Type | Description |
|---|---|---|
| T | Promise<T> | Parsed JSON response by default |
| Response | Response | Raw Response when needAllResponseContent or fetchCompat is true |
| Blob | Blob | Binary blob for download/audio content types |
| void | void | postWithKeepalive returns void (fire-and-forget) |
Usage Examples
Internal Usage by base.ts
import { base, ContentType, getBaseOptions } from './fetch'
// Used internally by the request() function in base.ts
const result = await base<MyResponseType>('/api/endpoint', {
method: 'POST',
body: { key: 'value' },
}, {
isPublicAPI: false,
})
Fire-and-Forget on Page Unload
import { postWithKeepalive } from '@/service/fetch'
window.addEventListener('beforeunload', () => {
postWithKeepalive('/api/analytics/page-leave', {
timestamp: Date.now(),
page: window.location.pathname,
})
})
Using Content Types
import { ContentType } from '@/service/fetch'
const headers = new Headers({
'Content-Type': ContentType.json,
})
Related Pages
- Principle:Langgenius_Dify_Service_Layer_Architecture
- Langgenius_Dify_Service_Base - Higher-level wrapper that consumes the base function
- Langgenius_Dify_Webapp_Auth - Provides getWebAppAccessToken and getWebAppPassport used in hooks