Implementation:Langgenius Dify Service Base
| Knowledge Sources | |
|---|---|
| Domains | Frontend, API_Service |
| Last Updated | 2026-02-12 07:00 GMT |
Overview
Core HTTP request wrapper providing authenticated API communication with support for standard REST methods, Server-Sent Events (SSE) streaming, file uploads, CSRF protection, and automatic token refresh.
Description
base.ts is the central HTTP service layer for the Dify frontend application. It wraps the low-level fetch.ts module (which uses the ky library) and provides a higher-level API with convenience methods for all standard HTTP verbs (GET, POST, PUT, DELETE, PATCH). The module defines a comprehensive type system for streaming event callbacks (IOnData, IOnWorkflowStarted, IOnNodeFinished, etc.) used to handle real-time SSE responses from workflow and chat endpoints. It automatically handles 401 authentication errors by attempting a token refresh via refreshAccessTokenOrReLogin and retrying the request, or redirecting to the login page. For public API endpoints (shared web apps), it supports web SSO login redirection. The handleStream function processes SSE data lines, dispatching parsed events to the appropriate callback based on the event type (e.g., message, workflow_started, node_finished, tts_message). The module also provides a file upload function using XMLHttpRequest for progress tracking, and includes CSRF header injection via js-cookie.
Usage
Use this module whenever you need to make authenticated API calls to the Dify backend. Import get, post, put, del, or patch for standard REST operations. Use ssePost or sseGet for streaming endpoints such as chat completions or workflow execution. Use upload for file upload operations that require progress tracking. Use the Public variants (e.g., getPublic, postPublic) when calling public/shared webapp API endpoints.
Code Reference
Source Location
- Repository: Langgenius_Dify
- File: web/service/base.ts
- Lines: 1-877
Signature
// Core request function with automatic 401 handling and token refresh
export const request = async<T>(url: string, options = {}, otherOptions?: IOtherOptions) => Promise<T>
// HTTP method wrappers
export const get = <T>(url: string, options = {}, otherOptions?: IOtherOptions) => Promise<T>
export const post = <T>(url: string, options = {}, otherOptions?: IOtherOptions) => Promise<T>
export const put = <T>(url: string, options = {}, otherOptions?: IOtherOptions) => Promise<T>
export const del = <T>(url: string, options = {}, otherOptions?: IOtherOptions) => Promise<T>
export const patch = <T>(url: string, options = {}, otherOptions?: IOtherOptions) => Promise<T>
// Public API variants
export const getPublic = <T>(url: string, options = {}, otherOptions?: IOtherOptions) => Promise<T>
export const postPublic = <T>(url: string, options = {}, otherOptions?: IOtherOptions) => Promise<T>
export const putPublic = <T>(url: string, options = {}, otherOptions?: IOtherOptions) => Promise<T>
export const delPublic = <T>(url: string, options = {}, otherOptions?: IOtherOptions) => Promise<T>
export const patchPublic = <T>(url: string, options = {}, otherOptions?: IOtherOptions) => Promise<T>
// Marketplace API variants
export const getMarketplace = <T>(url: string, options = {}, otherOptions?: IOtherOptions) => Promise<T>
export const postMarketplace = <T>(url: string, options = {}, otherOptions?: IOtherOptions) => Promise<T>
// SSE streaming functions
export const ssePost = async (url: string, fetchOptions: FetchOptionType, otherOptions: IOtherOptions) => void
export const sseGet = async (url: string, fetchOptions: FetchOptionType, otherOptions: IOtherOptions) => void
// Stream handler
export const handleStream = (response: Response, onData: IOnData, ...callbacks) => void
// File upload via XMLHttpRequest
export const upload = async (options: UploadOptions, isPublicAPI?: boolean, url?: string, searchParams?: string) => Promise<UploadResponse>
// Text formatting utility
export function format(text: string): string
Import
import { get, post, put, del, patch, request } from '@/service/base'
import { getPublic, postPublic, delPublic, putPublic, patchPublic } from '@/service/base'
import { ssePost, sseGet, handleStream, upload } from '@/service/base'
import type { IOtherOptions, IOnData, IOnDataMoreInfo } from '@/service/base'
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| url | string | Yes | API endpoint path (relative to API_PREFIX or PUBLIC_API_PREFIX) |
| options | FetchOptionType | No | Fetch options including params, body, headers, and method |
| otherOptions | IOtherOptions | No | Extended options: isPublicAPI, isMarketplaceAPI, bodyStringify, needAllResponseContent, silent, fetchCompat, and streaming callbacks |
| otherOptions.isPublicAPI | boolean | No | Routes request through PUBLIC_API_PREFIX for shared webapp endpoints |
| otherOptions.isMarketplaceAPI | boolean | No | Routes request through MARKETPLACE_API_PREFIX |
| otherOptions.silent | boolean | No | Suppresses toast error notifications when true |
| otherOptions.onData | IOnData | No | Callback for SSE message/agent_message events |
| otherOptions.onCompleted | IOnCompleted | No | Callback invoked when SSE stream completes |
| otherOptions.onError | IOnError | No | Callback for error events |
| otherOptions.getAbortController | function | No | Receives the AbortController to allow external cancellation |
Outputs
| Name | Type | Description |
|---|---|---|
| response | Promise<T> | Parsed JSON response for standard requests (generic type T) |
| void | void | SSE functions (ssePost/sseGet) return void and communicate via callbacks |
| UploadResponse | { id: string, [key: string]: unknown } | Upload response containing the uploaded file ID |
Usage Examples
Standard GET Request
import { get } from '@/service/base'
const data = await get<{ accounts: Member[] }>('/workspaces/current/members', {
params: { page: 1, limit: 20 },
})
POST with Body
import { post } from '@/service/base'
const result = await post<CommonResponse>('/setup', {
body: { email: 'admin@example.com', password: 'secret' },
})
SSE Streaming for Chat
import { ssePost } from '@/service/base'
ssePost('/chat-messages', {
body: { query: 'Hello', conversation_id: '' },
}, {
isPublicAPI: true,
onData: (message, isFirstMessage, moreInfo) => {
console.log('Received:', message)
},
onCompleted: () => {
console.log('Stream finished')
},
onWorkflowStarted: (data) => {
console.log('Workflow started:', data.workflow_run_id)
},
getAbortController: (controller) => {
// Store controller to allow cancellation
abortRef.current = controller
},
})
File Upload with Progress
import { upload } from '@/service/base'
const xhr = new XMLHttpRequest()
const formData = new FormData()
formData.append('file', file)
const result = await upload({
xhr,
data: formData,
onprogress: (event) => {
const percent = (event.loaded / event.total) * 100
console.log(`Upload progress: ${percent}%`)
},
}, false)
Related Pages
- Principle:Langgenius_Dify_Service_Layer_Architecture
- Langgenius_Dify_Service_Fetch - Low-level ky-based fetch wrapper used by base.ts
- Langgenius_Dify_Refresh_Token - Token refresh coordination used on 401 responses
- Langgenius_Dify_Webapp_Auth - Webapp auth token management for public API calls