Apollo Server 2.6中的未知类型“上传”

时间:2019-06-03 08:38:59

标签: node.js graphql apollo-server

我想通过GraphQL上传文件,并遵循此article

这是我的模式:

Ares=[]
Bres=[]
a = [4, 5, 2]
b = [3, 5, 4]
al=len(a)
for i in range(0,al):
        if a[i]>b[i]:
            Ares.append("1")
        if a[i]<b[i]:
            Ares.append("0")
        if b[i]>a[i]:
            Bres.append("1")
        if b[i]<a[i]:
            Bres.append("0") 
        if a[i]==b[i]:
            Ares.append("0")
            Bres.append("0")
Adata= list(map(int, Ares))
Aresult=sum(list(Adata))
Bdata= list(map(int, Bres))
Bresult=sum(list(Bdata))
RES=[Aresult,Bresult]
print(RES)

但是,当我运行应用程序时,这会给我这个错误:

  

未知类型“上传”。您是说“浮动”吗?

上面的文章之后,Apollo Server将自动生成Upload标量,但是为什么会发生这种情况?

还手动定义了“上传标量”也无效:

extend type Mutation {
  bannerAdd(
    title: String!
    image: Upload
  ): ID
}

给我这个错误:

  

错误:只能有一种名为“上传”的类型。

我的代码似乎没有错。有什么我想念的吗?使用Node @ 10.14.2,Apollo Server @ 2.6.1,Apollo Server Express@2.6.1和polka@0.5.2。

任何建议都会非常感谢。

3 个答案:

答案 0 :(得分:2)

使用Apollo服务器的GraphQLUpload解决此问题,以创建名为FileUpload的自定义标量。

使用Apollo服务器进行服务器设置:

const {ApolloServer, gql, GraphQLUpload} = require('apollo-server');

const typeDefs = gql`
  scalar FileUpload

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

  type Query {
    uploads: [File]
  }

  type Mutation {
    singleUpload(file: FileUpload!): File!
  }
`;

const resolvers = {
  FileUpload: GraphQLUpload,
  Query: {
    uploads: (parent, args) => {},
  },
  Mutation: {
    singleUpload: async (_, {file}) => {
      const {createReadStream, filename, mimetype, encoding} = await file;
      const stream = createReadStream();

      // Rest of your code: validate file, save in your DB and static storage

      return {filename, mimetype, encoding};
    },
  },
};

const server = new ApolloServer({
  typeDefs,
  resolvers,
});

server.listen().then(({url}) => {
  console.log(`? Server ready at ${url}`);
});

使用Apollo Client和React.js的客户端设置:

您还需要安装apollo-upload-client软件包。

import React from 'react';
import ReactDOM from 'react-dom';
import { ApolloClient, InMemoryCache, ApolloProvider, gql, useMutation } from '@apollo/client';
import { createUploadLink } from 'apollo-upload-client';

const httpLink = createUploadLink({
  uri: 'http://localhost:4000'
});

const client = new ApolloClient({
  link: httpLink,
  cache: new InMemoryCache()
});


const UPLOAD_FILE = gql`
  mutation uploadFile($file: FileUpload!) {
    singleUpload(file: $file) {
      filename
      mimetype
      encoding
    }
  }
`;

function FileInput() {
  const [uploadFile] = useMutation(UPLOAD_FILE);

  return (
    <input
      type="file"
      required
      onChange={({target: {validity, files: [file]}}) =>
        validity.valid && uploadFile({variables: {file}})
      }
    />
  );
}

function App() {
  return (
    <ApolloProvider client={client}>
      <div>
        <FileInput/>
      </div>
    </ApolloProvider>
  );
}

ReactDOM.render(
  <React.StrictMode>
    <App/>
  </React.StrictMode>,
  document.getElementById('root')
);

答案 1 :(得分:1)

此问题可能是由于在初始化服务器时传递可执行模式(schema选项)而不是较新的API分别传递typeDefsresolvers引起的。

旧:

const server = new ApolloServer({
    schema: makeExecutableSchema({ typeDefs, resolvers })
})

新功能:

const server = new ApolloServer({
    typeDefs,
    resolvers,
})

或如docs中所述:

注意:使用typeDefs时,Apollo Server将scalar Upload添加到您的架构中,因此应删除类型定义中所有现有的标量Upload声明。如果您使用makeExecutableSchema创建架构,并使用架构参数将其传递给ApolloServer构造函数,请确保包含scalar Upload

答案 2 :(得分:0)

这是我所做的解决方案,添加名为“ FileUpload”的自定义标量,并添加GraphQLUpload作为解析器,如下所示:

import { GraphQLUpload } from 'graphql-upload';

export const resolvers = {
  FileUpload: GraphQLUpload
};

效果很好,但是可能不是完美的解决方案。希望阿波罗尽快解决此问题。

P.S。要从浏览器上传文件,您还需要在Apollo Client中正确设置上传链接。这是我的代码:

import { ApolloLink, split } from 'apollo-link';
import { createHttpLink } from 'apollo-link-http';
import { createUploadLink } from 'apollo-upload-client';

// Create HTTP Link
const httpLink = createHttpLink({
  uri: ...,
  credentials: 'include'
});

// Create File Upload Link
const isFile = value =>
  (typeof File !== 'undefined' && value instanceof File) || (typeof Blob !== 'undefined' && value instanceof Blob);
const isUpload = ({ variables }) => Object.values(variables).some(isFile);
const uploadLink = createUploadLink({
  uri: ...
  credentials: 'include'
});

const terminatingLink = (isUpload, uploadLink, httpLink);

const link = ApolloLink.from([<Some Other Link...>, <Another Other Link...>, terminatingLink]);

const apolloClient = new ApolloClient({
  link,
  ...
});