简体   繁体   中英

GraphQL type with a variable field name

I'm trying to expose the Rest Countries API (restcountries.com) as a GraphQL API. However I'm struggling to figure out what's the bast way to create a type definition in GraphQL to display the field name.nativeName .

For example: If you send a request to fetch information about a country like Canada (GET https://restcountries.com/v3.1/alpha/ca ), then we will get a response like this:

"name": {
    "common": "Canada",
    "official": "Canada",
    "nativeName": {
        "eng": {
            "official": "Canada",
            "common": "Canada"
        },
        "fra": {
            "official": "Canada",
            "common": "Canada"
        }
    }
}

As you can see in the response above the nativeName field is an object with two inner fields eng and fra . However, if I send a request to fetch another country, like Finland (GET https://restcountries.com/v3.1/alpha/fi ) the response will look like this:

"name": {
    "common": "Finland",
    "official": "Republic of Finland",
    "nativeName": {
        "fin": {
            "official": "Suomen tasavalta",
            "common": "Suomi"
        },
        "swe": {
            "official": "Republiken Finland",
            "common": "Finland"
        }
    }
}

But this time, for Finland, the nativeName has different fields fin and swe . In other words, the inner fields for nativeName change depending on the country that we are querying.

So how can I create the proper typeDefs and resolvers in my GraphQL API to support this scenario, with field names that unpredictable? This is my typeDef so far, but I have no idea how I can create a type for nativeName .

type Query {
    all: [Country!]!
}

type Country {
    name: CountryName!
}

type CountryName {
    common: String!
    official: String!
    nativeName: ... # I have no idea how to map nativeName
}

Is there a way to make one of the field name in this type variable? Can anyone suggest a way to complete this typeDef with the nativeName and also how the resolver should look like?

This is a commonly asked question you can usually find it under "GraphQL Map", eg here . You cannot have dynamic fields in GraphQL.

Now you should ask yourself how important is it to keep the original shape of the reponse. If you don't care about the shape, the GraphQL dogmatic way would be to simply return a list:

type NativeName {
  lang: String!
  official: String 
  common: String
}

type CountryName {
  nativeName: [NativeName!]!
}

Your response shape would change of course. Your resolver could be:

resolve(parent) {
  return Object.entries(parent.nativeName).map(([lang, rest]) => ({ lang, ...rest }));
}

If you care about the result shape and you want it as close as possible to the original, you can go the way it is proposed in most questions (like the one above) and use a JSON scalar. You lose the typing though.

And one last complete madness approach: There is a finite amount of three digit language codes. You could add each of them to an object:

type NativeName {
  official: String 
  common: String
}

type NativeNameMap {
  afr: NativeName
  ain: NativeName
  aka: NativeName
  ...
}

type CountryName {
  nativeName: NativeNameMap
}

This sounds crazy, but if the caller knows ahead of time what languages will be returned, it might be feasable.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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