Edits history of script submission #23554 for ' Call Windmill API (windmill)'

  • bunnative
    One script reply has been approved by the moderators
    Ap­pro­ved
    //native
    
    import * as wmill from "windmill-client"
    
    export type DynSelect_operation = string
    
    // Every operation of the instance's own OpenAPI document, so the list always matches its version.
    async function listOperations() {
      const response = await fetch(`${wmill.OpenAPI.BASE}/openapi.json`)
      if (!response.ok) {
        throw new Error(`${response.status} ${await response.text()}`)
      }
      const spec = (await response.json()) as {
        paths: { [path: string]: { [method: string]: { operationId?: string } } }
      }
      return Object.entries(spec.paths).flatMap(([path, methods]) =>
        Object.entries(methods)
          .filter(([, op]) => op?.operationId)
          .map(([method, op]) => ({
            id: op.operationId!,
            value: `${method.toUpperCase()} ${path}`,
          }))
      )
    }
    
    export async function operation() {
      return (await listOperations())
        .map((op) => ({ value: op.value, label: `${op.id}: ${op.value}` }))
        .sort((a, b) => a.label.localeCompare(b.label))
    }
    
    /**
     * Call Windmill API
     * Call any operation of this instance's own API, picked from its OpenAPI document. Runs with the job's token, which only reaches the job's workspace; pass a user API token to call instance-level operations or another workspace.
     */
    export async function main(
      operation: DynSelect_operation,
      path_params: { [key: string]: any } | undefined,
      query: { [key: string]: any } | undefined,
      body: { [key: string]: any } | undefined,
      token: string | undefined
    ) {
      // `operation` is "METHOD /path" (what the dropdown stores) or a bare operationId
      const resolved = operation.includes(" ")
        ? operation
        : (await listOperations()).find((op) => op.id === operation)?.value
      if (!resolved) {
        throw new Error(`Unknown operation ${operation}`)
      }
      const [method, path] = resolved.split(" ")
    
      const params: { [key: string]: any } = {
        workspace: wmill.getWorkspace(),
        ...path_params,
      }
      const url = new URL(
        wmill.OpenAPI.BASE +
          path.replace(/\{(\w+)\}/g, (_, name) => {
            if (params[name] == null || params[name] === "") {
              throw new Error(`Missing path parameter ${name} for ${resolved}`)
            }
            return encodeURI(String(params[name]))
          })
      )
      for (const [name, value] of Object.entries(query ?? {})) {
        if (value != null && value !== "") {
          url.searchParams.append(name, String(value))
        }
      }
    
      const hasBody = body != null && method !== "GET"
      const response = await fetch(url, {
        method,
        headers: {
          // the job's own token only reaches its workspace: pass an API token for anything else
          Authorization: `Bearer ${token || wmill.OpenAPI.TOKEN}`,
          ...(hasBody ? { "Content-Type": "application/json" } : {}),
        },
        body: hasBody ? JSON.stringify(body) : undefined,
      })
    
      if (!response.ok) {
        throw new Error(`${response.status} ${await response.text()}`)
      }
    
      const text = await response.text()
      return response.headers.get("Content-Type")?.includes("json")
        ? JSON.parse(text)
        : text
    }
    

    Submitted by hugo989 5 hours ago