Merge pull request #15 from trevorblades/enums

IDs, Booleans, and nullability
This commit is contained in:
Trevor Blades
2020-03-27 10:29:04 -07:00
committed by GitHub
6 changed files with 66 additions and 47 deletions

1
.gitignore vendored
View File

@@ -1,2 +1 @@
node_modules node_modules
.env

View File

@@ -1,14 +1,21 @@
<img align="right" src="https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/120/apple/155/earth-globe-americas_1f30e.png" alt="globe" width="120"> <p align="center">
<img src="./logo.png" alt="globe" width="150">
</p>
# Countries GraphQL API <h1 align="center">Countries GraphQL API</h1>
<div align="center">
[![Build Status](https://github.com/trevorblades/countries/workflows/Node%20CI/badge.svg)](https://github.com/trevorblades/countries/actions) [![Build Status](https://github.com/trevorblades/countries/workflows/Node%20CI/badge.svg)](https://github.com/trevorblades/countries/actions)
[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-v2.0%20adopted-ff69b4.svg)](CODE_OF_CONDUCT.md) [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-v2.0%20adopted-ff69b4.svg)](CODE_OF_CONDUCT.md)
[![Twitter Follow](https://img.shields.io/twitter/follow/trevorblades?style=social)](https://twitter.com/trevorblades)
</div>
A public GraphQL API for information about countries, continents, and languages. This project uses [Countries List](https://annexare.github.io/Countries/) and [`provinces`](https://github.com/substack/provinces) as data sources, so the schema follows the shape of that data, with a few exceptions: A public GraphQL API for information about countries, continents, and languages. This project uses [Countries List](https://annexare.github.io/Countries/) and [`provinces`](https://github.com/substack/provinces) as data sources, so the schema follows the shape of that data, with a few exceptions:
1. The codes used to key the objects in the original data are available as a `code` property on each item returned from the API. 1. The codes used to key the objects in the original data are available as a `code` property on each item returned from the API.
2. The `continent` and `languages` properties are now objects and arrays of objects, respectively. 2. The `country.continent` and `country.languages` are now objects and arrays of objects, respectively.
3. Each `Country` has an array of `states` populated by their states/provinces, if any. 3. Each `Country` has an array of `states` populated by their states/provinces, if any.
## Writing queries ## Writing queries
@@ -18,6 +25,7 @@ A public GraphQL API for information about countries, continents, and languages.
country(code: "BR") { country(code: "BR") {
name name
native native
capital
emoji emoji
currency currency
languages { languages {
@@ -36,6 +44,7 @@ The above GraphQL query will produce the following JSON response:
"country": { "country": {
"name": "Brazil", "name": "Brazil",
"native": "Brasil", "native": "Brasil",
"capital": "Brasília",
"emoji": "🇧🇷", "emoji": "🇧🇷",
"currency": "BRL", "currency": "BRL",
"languages": [ "languages": [
@@ -49,6 +58,8 @@ The above GraphQL query will produce the following JSON response:
} }
``` ```
## Docs
Check out [the playground](https://countries.trevorblades.com) to explore the schema and test out some queries. Check out [the playground](https://countries.trevorblades.com) to explore the schema and test out some queries.
## Examples ## Examples
@@ -58,6 +69,7 @@ Check out [the playground](https://countries.trevorblades.com) to explore the sc
- [ReasonML](https://medium.com/@idkjs/reasonml-and-graphql-without-graphql-part-1-192c2e9e349c) - [ReasonML](https://medium.com/@idkjs/reasonml-and-graphql-without-graphql-part-1-192c2e9e349c)
- [Country quiz app](https://github.com/byrichardpowell/Country-Quiz) (React, TypeScript) - [Country quiz app](https://github.com/byrichardpowell/Country-Quiz) (React, TypeScript)
- [Python](./examples/python) - [Python](./examples/python)
- [Seed](https://github.com/seed-rs/seed/tree/master/examples/graphql)
## License ## License

View File

@@ -1,5 +0,0 @@
module.exports = {
endpoint: {
url: `http://localhost:${process.env.PORT}`
}
};

View File

@@ -4,44 +4,45 @@ const {continents, countries, languages} = require('countries-list');
const typeDefs = gql` const typeDefs = gql`
type Continent { type Continent {
code: String code: ID!
name: String name: String!
countries: [Country] countries: [Country!]!
} }
type Country { type Country {
code: String code: ID!
name: String name: String!
native: String native: String!
phone: String phone: String!
continent: Continent continent: Continent!
currency: String capital: String!
languages: [Language] currency: String!
emoji: String languages: [Language!]!
emojiU: String emoji: String!
states: [State] emojiU: String!
states: [State!]!
} }
type State { type State {
code: String code: String
name: String name: String!
country: Country country: Country!
} }
type Language { type Language {
code: String code: ID!
name: String name: String
native: String native: String
rtl: Int rtl: Boolean!
} }
type Query { type Query {
continents: [Continent] continents: [Continent!]!
continent(code: String!): Continent continent(code: ID!): Continent
countries: [Country] countries: [Country!]!
country(code: String!): Country country(code: ID!): Country
languages: [Language] languages: [Language!]!
language(code: String!): Language language(code: ID!): Language
} }
`; `;
@@ -84,12 +85,20 @@ const resolvers = {
})); }));
} }
}, },
Language: {
rtl(language) {
return Boolean(language.rtl);
}
},
Query: { Query: {
continent(parent, {code}) { continent(parent, {code}) {
return { const name = continents[code];
code, return (
name: continents[code] name && {
}; code,
name
}
);
}, },
continents() { continents() {
return Object.entries(continents).map(([code, name]) => ({ return Object.entries(continents).map(([code, name]) => ({
@@ -99,10 +108,12 @@ const resolvers = {
}, },
country(parent, {code}) { country(parent, {code}) {
const country = countries[code]; const country = countries[code];
return { return (
...country, country && {
code ...country,
}; code
}
);
}, },
countries() { countries() {
return Object.entries(countries).map(([code, country]) => ({ return Object.entries(countries).map(([code, country]) => ({
@@ -112,10 +123,12 @@ const resolvers = {
}, },
language(parent, {code}) { language(parent, {code}) {
const language = languages[code]; const language = languages[code];
return { return (
...language, language && {
code ...language,
}; code
}
);
}, },
languages() { languages() {
return Object.entries(languages).map(([code, language]) => ({ return Object.entries(languages).map(([code, language]) => ({
@@ -136,6 +149,6 @@ const server = new ApolloServer({
} }
}); });
server.listen({port: process.env.PORT}).then(({url}) => { server.listen({port: process.env.PORT || 4000}).then(({url}) => {
console.log(`🚀 Server ready at ${url}`); console.log(`🚀 Server ready at ${url}`);
}); });

BIN
logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -1,7 +1,7 @@
{ {
"scripts": { "scripts": {
"start": "nodemon -r dotenv/config index.js", "start": "nodemon index.js",
"pretest": "eslint index.js apollo.config.js", "pretest": "eslint index.js",
"test": "echo \"Error: no test specified\" && exit" "test": "echo \"Error: no test specified\" && exit"
}, },
"eslintConfig": { "eslintConfig": {