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.