简体   繁体   English

GraphQL (Apollo) 如何在参数中传递数据结构?

[英]GraphQL (Apollo) how to pass datastructure in parameter?

I'd like to make a query with lot of input parameter:我想使用大量输入参数进行查询:

 apollo_client.mutate({mutation: gql
  `mutation mutation($title: String!, $caption: String!, $id: Int!){
    mutatePmaHome(pmaData: {id:$id, title: $title, caption: $caption}) {
      pma{
        title
        caption
      }
    }
  }`,
  variables: {
    title: this.state.title,
    caption: this.state.caption,
    id: this.state.id
  },
}).then(console.log);

This is how look my query when I pass simple datastructure (Int, String) But my question is: How can I pass a dictionnary or object in the mutation query.这是我传递简单数据结构(Int,String)时查询的外观,但我的问题是:如何在变异查询中传递字典或对象。 I don't have any idea how can I type it.我不知道如何输入它。

The doc from graphQL say I must create an input object. graphQL 的文档说我必须创建一个输入对象。 But here I'm on js with apollo, so how can I pass a dictionnary on my query in order to not type all data (here 3, but it can be 10 to 20).但是这里我使用的是带有 apollo 的 js,所以我如何在查询中传递字典以便不输入所有数据(这里是 3,但可以是 10 到 20)。 I'd like a cleaner approach with an input type field, but I can't find a single example.我想要一个带有输入类型字段的更简洁的方法,但我找不到一个例子。

Thanks谢谢

The way I see it, there are two approaches you can take.在我看来,您可以采取两种方法。

The safer approach is to create a type containing a key and a value.更安全的方法是创建一个包含键和值的类型。 Then, your dictionary would be a list of keys and values.然后,您的字典将是键和值的列表。 Instead of accessing a property as let value = dictionary[key] , you would then need to use let entry = dictionary.find((entry) => entry.key === key); let value = entry && entry.value而不是访问属性为let value = dictionary[key] ,然后您需要使用let entry = dictionary.find((entry) => entry.key === key); let value = entry && entry.value let entry = dictionary.find((entry) => entry.key === key); let value = entry && entry.value . let entry = dictionary.find((entry) => entry.key === key); let value = entry && entry.value

// Before
{
  red: 1,
  blue: 2,
  green: 3,
}

// After
[
  {key: 'red', value: 1},
  {key: 'blue', value: 2},
  {key: 'green', value: 3},
]

Typedefs:类型定义:

type IntegerProperty {
    key: ID!
    value: Int
}

type IntegerDictionary {
    values: [IntegerProperty!]!
}

A quicker but less typesafe approach is to use something like graphql-type-json or graphql-json-object-type .一种更快但类型安全性较低的方法是使用类似graphql-type-jsongraphql-json-object-type These permit you to include arbitrary JSON in your GraphQL query;这些允许您在 GraphQL 查询中包含任意 JSON; however, you then lose the guarantees that GraphQL makes on the format of your data.但是,您将失去 GraphQL 对数据格式的保证。

Swift 5.1, Apollo 0.21.0斯威夫特 5.1,阿波罗 0.21.0

The keys and values in your dictionary need to adhere to the Apollo JSONEncodable protocol:字典中的键和值需要遵守 Apollo JSONEncodable 协议:

public protocol JSONEncodable: GraphQLInputValue {
  var jsonValue: JSONValue { get }
}

You need to loop through your Dictionary and return each Object with a .jsonValue (JSONEncodable protocol).您需要遍历您的 Dictionary 并使用 .jsonValue(JSONEncodable 协议)返回每个对象。

[String : Any?] vs [String : String] [字符串:任何?] vs [字符串:字符串]

If you pass a Dictionary of [String : String] into Apollo, it will automagically work because String conforms to the JSONEncodable protocol.如果您将 [String : String] 的字典传递给 Apollo,它会自动工作,因为 String 符合 JSONEncodable 协议。 Both key and value are type String.键和值都是字符串类型。

JSON is usually represented in Swift as [String : Any?] which means the key must be String, but the value can by Any object (Array, Bool, Double, Null, String, Dictionary). JSON 在 Swift 中通常表示为 [String : Any?],这意味着键必须是 String,但值可以是 Any 对象(Array、Bool、Double、Null、String、Dictionary)。

Because Apollo doesn't know what the Any object is, it will cause a SIGABRT.因为 Apollo 不知道 Any 对象是什么,所以会导致 SIGABRT。 This is because the value could be a custom class you wrote that is not JSON compatible.这是因为该值可能是您编写的与 JSON 不兼容的自定义类。

You must cast the Any object to a class that conforms to the JSONEncodable protocol.您必须将 Any 对象强制转换为符合 JSONEncodable 协议的类。

Since [String : Any?] by default cannot define the Any objects, the Generic JSON library does this by creating a new class to represent the JSON data.由于 [String : Any?] 默认情况下无法定义 Any 对象,因此通用 JSON 库通过创建一个新类来表示 JSON 数据来实现这一点。

The example below extends the JSONEncodable protocol to the GenericJSON class to ensure the value adheres to the JSONEncodable protocol Apollo requires for a mutation.下面的示例将 JSONEncodable 协议扩展到 GenericJSON 类,以确保该值符合 Apollo 进行突变所需的 JSONEncodable 协议。

Building a Dictionary that adheres to the JSONEncodable Protocol构建符合 JSONEncodable 协议的字典

  1. Add the Generic JSON library to your pod file:将通用 JSON 库添加到您的 pod 文件中:

https://github.com/zoul/generic-json-swift https://github.com/zoul/generic-json-swift

pod 'GenericJSON'

  1. Import the GenericJSON library and create an alias for your custom JSON GraphQL scalar in some ApolloExtensions.swift file.导入GenericJSON库并在某些ApolloExtensions.swift文件中为您的自定义 JSON GraphQL 标量创建别名。 This alias will map to the GenericJSON library:此别名将映射到 GenericJSON 库:
import GenericJSON

// CUSTOM JSON SCALAR

public typealias MyJsonScalar = JSON
  1. In the ApolloExtensions.swift file, add a JSONEncodable extension for the GenericJSON JSON:ApolloExtensions.swift文件中,为 GenericJSON JSON 添加一个 JSONEncodable 扩展:
extension JSON: JSONEncodable {

    public var jsonValue: JSONValue {

        if self.objectValue != nil {

            return jsonObject as JSONObject

        }

        if self.arrayValue != nil {

            var array : Array<JSONEncodable> = []

            for obj in self.arrayValue! {

                if obj.arrayValue != nil {

                    array.append(obj.jsonValue as! Array<JSONEncodable>)

                } else if obj.objectValue != nil {

                    array.append(obj.jsonValue as! JSONObject)

                } else {

                    array.append(obj.jsonValue as! JSONEncodable)

                }

            }

            return array as Array<JSONEncodable>

        }

        if self.stringValue != nil {

            return self.stringValue! as String

        }

        if self.doubleValue != nil {

            return self.doubleValue! as Double

        }

        if self.boolValue != nil {

            return self.boolValue! as Bool

        }

        if self.isNull {

            return "" as String

        }

        return "" as String

    }

    public var jsonObject: JSONObject {

        var jsonObject : JSONObject = JSONObject(minimumCapacity: self.objectValue!.count)

        for (key, value) in self.objectValue! {

            if value.arrayValue != nil {

                jsonObject[key] = value.jsonValue as! Array<JSONEncodable>

            } else if value.objectValue != nil {

                jsonObject[key] = value.jsonValue as! JSONObject

            } else {

                jsonObject[key] = value.jsonValue as! JSONEncodable

            }

        }

        return jsonObject

    }

}
  1. Create a JSON object from your dictionary and pass it into your GraphQL mutation:从您的字典中创建一个 JSON 对象并将其传递到您的 GraphQL 变更中:
func createJSONDictionary() {

    let myDictionary : [String: Any?] = ["foo" : "foo", "bar" : 2]

    do {

        let jsonData : Data = try JSONSerialization.data(withJSONObject: myDictionary, options: [])

        if let jsonObject = try JSONSerialization.jsonObject(with: jsonData, options: []) as? [String : Any?] {

            let json: JSON = try JSON(jsonObject)

            self.myGraphQLMutation(json: json)

        } else {

            // casting error

        }

    } catch {

        // json error

    }

}

func myGraphQLMutation(json: JSON) {

    // apollo

    let apollo : ApolloClient = ApolloHelper.shared.client

    // myMutation

    let myMutation = MyMutation(json: json)

    // perform

    apollo.perform(mutation: myMutation, queue: DispatchQueue.global()) { result in

        switch result {

            case .success(let graphQLResult):

                // Deal with GraphQLResult and its data and/or errors properties here

                break

            case .failure(let error):

                // deal with network errors here

                return

        }

    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM