NodeJS 使用 GQL 创建和 POST 文件

NodeJS create and POST file with GQL

我一直无法弄清楚在 NodeJS 中如何:

  1. 从原始字符串在内存中创建一个“文件”;并且,
  2. 如何 POST 将数据发送到另一个需要 multipart/form-data 负载的服务器。

似乎您不能在 NodeJS 中使用 BlobFile classes。 我读过的模式应该是使用Buffer class。 我仍然无法让它与缓冲区一起工作。

我的 GQL 数据源 class 看起来像:

const { RESTDataSource } = require('apollo-datasource-rest');
const FormData = require('form-data');

export default class MyDatasource extends RESTDataSource {

  async postFileToServer({ string }) {

    const inMemoryFile = Buffer.from(string, 'utf-8');

    const myForm = new FormData();
    myForm.append('file', inMemoryFile, 'file.txt');

    const url = 'http://examnple.com';
    const opts = { headers: { 'Content-Type': 'multipart/form-data' } };

    return await this.post(url, myForm, opts);
  }
}

当我使用 Postman 使用来自本地计算机的文件进行 API 调用时,我想要访问的端点工作正常。但是,我需要 GQL 服务器从原始字符串创建文件,然后调用需要 multipart/form-data.

的 example.com 端点

上面的示例代码总是给我一个Status 400SyntaxError: Unexpected token - in JSON at position 0

的错误

我使用 apollo-datasource-rest 包上传文件。这是一个例子:

server.ts:

import { ApolloServer, gql } from 'apollo-server';
import MyDatasource from './datasource';

const typeDefs = gql`
  type Query {
    dummy: String
  }
  type Mutation {
    upload: String
  }
`;
const resolvers = {
  Mutation: {
    upload(_, __, { dataSources }) {
      return dataSources.uploadAPI.postFileToServer({ str: '1234' });
    },
  },
};

const server = new ApolloServer({
  typeDefs,
  resolvers,
  dataSources: () => {
    return {
      uploadAPI: new MyDatasource(),
    };
  },
});
const port = 3001;
server.listen(port).then(({ url }) => console.log(` Server ready at ${url}`));

datasource.ts:

import { RESTDataSource } from 'apollo-datasource-rest';
import FormData from 'form-data';

export default class MyDatasource extends RESTDataSource {
  public async postFileToServer({ str }) {
    const inMemoryFile = Buffer.from(str, 'utf-8');
    const myForm = new FormData();
    myForm.append('file', inMemoryFile, 'file.txt');
    const url = 'http://localhost:3000/upload';

    return this.post(url, myForm);
  }
}

uploadServer.ts:

import multer from 'multer';
import express from 'express';
import path from 'path';

const upload = multer({ dest: path.resolve(__dirname, 'uploads/') });
const app = express();
const port = 3000;

app.post('/upload', upload.single('file'), (req, res) => {
  console.log(req.file);
  console.log(req.body);
  res.sendStatus(200);
});

app.listen(port, () => {
  console.log(`upload server is listening on http://localhost:${port}`);
});

/uploadAPI控制器打印的日志:

{
  fieldname: 'file',
  originalname: 'file.txt',
  encoding: '7bit',
  mimetype: 'text/plain',
  destination: '/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/src/Whosebug/63181608/uploads',
  filename: '3cba4dded6089479ad495e2fb2daac21',
  path: '/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/src/Whosebug/63181608/uploads/3cba4dded6089479ad495e2fb2daac21',
  size: 4
}
[Object: null prototype] {}

源代码:https://github.com/mrdulin/apollo-graphql-tutorial/tree/master/src/Whosebug/63181608