惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Microsoft Azure Blog
Microsoft Azure Blog
GbyAI
GbyAI
P
Proofpoint News Feed
Engineering at Meta
Engineering at Meta
Recent Announcements
Recent Announcements
L
LangChain Blog
B
Blog
阮一峰的网络日志
阮一峰的网络日志
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
M
MIT News - Artificial intelligence
D
Docker
WordPress大学
WordPress大学
J
Java Code Geeks
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
The GitHub Blog
The GitHub Blog
博客园 - 叶小钗
Last Week in AI
Last Week in AI
Stack Overflow Blog
Stack Overflow Blog
有赞技术团队
有赞技术团队
MyScale Blog
MyScale Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
MongoDB | Blog
MongoDB | Blog
博客园 - Franky

szhshp 的第三边境研究所

假设, AI 把我代替的那一刻真的到来 | szhshp 的第三边境研究所 小傻瓜都能懂的 AstrBot QQ 机器人集成 MCP 功能实战指南 | szhshp 的第三边境研究所 《智人之上: 从石器时代到 AI 时代的信息网络简史》阅读笔记 | szhshp 的第三边境研究所 iPadOS 26 无法设置空间场景图片壁纸的解决方法 | szhshp 的第三边境研究所 《一路云海》(终) | szhshp 的第三边境研究所 《一路云海》(四): 如何不按套路旅行 | szhshp 的第三边境研究所 《一路云海》(三): In Ya Mellow Tone | szhshp 的第三边境研究所 《一路云海》(二): 关西世博参观纪实 | szhshp 的第三边境研究所 《一路云海》(一): 新的征程 | szhshp 的第三边境研究所 2025 大阪世博会 [ 3 天前-先到先得 ] 阶段 场馆预约必中独家攻略 | szhshp 的第三边境研究所 Hackathon 随想 | szhshp 的第三边境研究所 一杯双皮奶 | szhshp 的第三边境研究所 Armbian + CasaOS + NAS 配置指南 | szhshp 的第三边境研究所 Docker 构建镜像报错: error getting credentials - err: exit status 1, out: `` | szhshp 的第三边境研究所 Disqus RIP! 论过高的维护成本如何治疗固执的坏习惯 | szhshp 的第三边境研究所 炸弹猫桌游变体规则 | szhshp 的第三边境研究所 《小岛经济学》阅读笔记 | szhshp 的第三边境研究所 《金钱心理学》阅读笔记 | szhshp 的第三边境研究所 为知笔记 RIP: 迁移剩余的笔记 | szhshp 的第三边境研究所 2025 博客第十年展望 - 再见我的过去 | szhshp 的第三边境研究所 我在独立游戏里面致敬的作品 | szhshp 的第三边境研究所 《How to make thing faster》阅读笔记 | szhshp 的第三边境研究所 《The Art of Clean Code》阅读笔记 | szhshp 的第三边境研究所 《Clean Architecture: A Craftsman Guide to Software Structure and Design》阅读笔记 | szhshp 的第三边境研究所 《How AI Works》阅读笔记 | szhshp 的第三边境研究所 游戏策划废案 - Project Uranus | szhshp 的第三边境研究所 游戏策划废案 - Project X | szhshp 的第三边境研究所 人生第一款独立游戏开发复盘 | szhshp 的第三边境研究所 Trap of Life | szhshp 的第三边境研究所 如果我用手搓了个暗物质雏形 | szhshp 的第三边境研究所
GraphQL: File Upload & Troubleshooting | szhshp 的第三边...
2020-10-20 · via szhshp 的第三边境研究所

Meta

目录

GraphQL File Upload

All implementations and extensions are based on graphql-multipart-request-spec

Client

ApolloClient Setup

Client is using apollo-upload-client which implemented graphql-multipart-request-spec

Replace HttpLink with createUploadLink

Those two do the same thing, feel free to replace it!

import {
    ApolloClient,
    InMemoryCache
} from '@apollo/client';
import {
    createUploadLink
} from 'apollo-upload-client';

const client = new ApolloClient(config);

Add Scalar

Upload scalar

Due to different dependencies, this may cause some error, see Troubleshooting below

Add Schema

type Mutation {
    singleUpload(file: Upload!): File!
}

type File {
    filename: String!
    mimetype: String!
    encoding: String!
}

Frontend

Provide an input or use other frontend components to select a file:

<input type="file" onchange={fileUpload}>

Then validate the selected file:

const uploadOnChange = async (files: File[]) => {
    if (files.length === 0) return
    if (files.filter((file) => file.size > 10 * 1024 * 1024).length > 0) {
        /* throw error: file size exceed */
        return
    }
    if (
        files.filter(
            (file) => [ `image/png` , `image/jpeg` ].findIndex(
                (type) => file.type === type
            ) === -1
        ).length > 0
    ) {
        /* throw error: unacceptable file type */
        return
    }

    /* trigger mutation here */
}

Backend

GraphQL port it to assets server

If you are using Javascript, skip the import of graphql-upload

If you are using Typescript, you can use graphql-upload for type check, which implemented graphql-multipart-request-spec

import { FileUpload } from "graphql-upload";

const uploadFile = async (filePromise: {
  file: FileUpload;
}): Promise<boolean> => {
  try {
    const { file }: { file: FileUpload } = await filePromise;
    const fileReadStream = file.createReadStream(); // get the file readstream 

    /* ----------------------------- `*/
    /* Option 1: You can save the file on current server */
    /* const writeStream = fs.createWriteStream('fakepath/output.png') */
    /* Convert stream to file */
    /* readStream.pipe(writeStream) */

    /* ----------------------------- */
    /* Option 2: You can port the file to assets server if you need */
    const formData = new FormData();
    formData.append("attachmentData", fileReadStream, file.filename);

    await http.post( `assetsServer/fileUpload` , formData, {
      headers: {
        ...formData.getHeaders(),
      },
      timeout: 30000,
    });
    return true;
  } catch (error) {
    return false;
  }
};

const resolvers = {
  Query: {
    files: () => {
      // Return the record of files uploaded from your DB or API or filesystem.
    }
  },
  Mutation: {
    uploadFile
  },
};

Troubleshooting

There can be only one type named “Upload”

Possibly you included one lib which ALREADY implemented Upload Type, so you just need to delete scalar Upload

Unknown type “Upload”. Did you mean “Float”?

You forget to add the scalar Upload

scalar Upload always causes error :(

  • If I add it -> Error: There can be only one type named "Upload"
  • If I remove it -> Error: Unknown type "Upload". Did you mean "Float"? Oh you got some tricky dependencies.

Try use other names like:

scalar FileUpload

That may help your issue, GraphQL may regard it as custom scalar.

createReadStream() crashes-RangeError: Maximum call stack size exceeded

RangeError: Maximum call stack size exceeded
        at _openReadFs (internal/fs/streams.js:1:1) 

This is due to outdated dependency of fs-capacitor .

To prevent future compatibility issue, set resolutions in package.json :

"resolutions": {
  "graphql-upload": "11.0.0"
},

Be aware that resolutions property is currently only handled by yarn package manager, not by npm

with npm, you have to preinstall an aditionnal module to force resolutions :

"scripts": {
  "preinstall": "npx npm-force-resolutions",
}

References