{"id":15487171,"url":"https://github.com/arjunyel/firestore-apollo-graphql","last_synced_at":"2025-04-06T03:07:31.638Z","repository":{"id":45805023,"uuid":"137366578","full_name":"arjunyel/firestore-apollo-graphql","owner":"arjunyel","description":"An example of a GraphQL setup with a Firebase Firestore backend. Uses Apollo Engine/Server 2.0 and deployed to Google App Engine.","archived":false,"fork":false,"pushed_at":"2023-01-09T11:23:27.000Z","size":288,"stargazers_count":434,"open_issues_count":9,"forks_count":60,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-03-30T01:13:02.208Z","etag":null,"topics":["apollo","apollo-engine","apollo-server","app-engine","firebase","firestore","graphql"],"latest_commit_sha":null,"homepage":"https://youtu.be/8D9XnnjFGMs","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/arjunyel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-06-14T14:08:00.000Z","updated_at":"2024-09-06T20:39:40.000Z","dependencies_parsed_at":"2023-02-08T10:00:16.339Z","dependency_job_id":null,"html_url":"https://github.com/arjunyel/firestore-apollo-graphql","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arjunyel%2Ffirestore-apollo-graphql","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arjunyel%2Ffirestore-apollo-graphql/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arjunyel%2Ffirestore-apollo-graphql/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arjunyel%2Ffirestore-apollo-graphql/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/arjunyel","download_url":"https://codeload.github.com/arjunyel/firestore-apollo-graphql/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247427006,"owners_count":20937201,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["apollo","apollo-engine","apollo-server","app-engine","firebase","firestore","graphql"],"created_at":"2024-10-02T06:21:36.311Z","updated_at":"2025-04-06T03:07:31.600Z","avatar_url":"https://github.com/arjunyel.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# firebase-firestore-graphql\n\nAn example of a [GraphQL](https://graphql.org/) setup with a Firebase Firestore backend. Uses [Apollo Engine/Server 2.0](https://www.apollographql.com/) and deployed to Google App Engine.\n\n## Initial setup\n\n```bash\nnpm init --yes\nnpm install apollo-server@beta firebase-admin graphql graphql-tag\nnpm install --save-dev typescript tslint\n```\n\nYou'll also want to set up some scripts and other settings, as of writing here is what the package.json looks like\n\n```json\n{\n  \"name\": \"firebase-firestore-graphql\",\n  \"scripts\": {\n      \"build\": \"tsc\",\n      \"serve\": \"npm run build \u0026\u0026 node lib/index.js\",\n      \"start\": \"node lib/index.js\",\n      \"deploy\": \"npm run build \u0026\u0026 gcloud app deploy\"\n  },\n  \"main\": \"lib/index.js\",\n  \"dependencies\": {\n      \"apollo-server\": \"^2.0.0-beta.10\",\n      \"firebase-admin\": \"^5.12.1\",\n      \"graphql\": \"^0.13.2\",\n      \"graphql-tag\": \"^2.9.2\"\n  },\n  \"devDependencies\": {\n      \"tslint\": \"^5.10.0\",\n      \"typescript\": \"^2.9.1\"\n  }\n}\n```\n\n## Firebase setup\n\nDownload Firebase service account as `service-account.json` and put in root of this directory.\n\nIn your firestore database setup two collections, one of tweets and one of users. The userId in tweets should point to a user Id that the tweet came from.\n\n```typescript\ninterface User {\n  id: string;\n  name: string;\n  screenName: string;\n  statusesCount: number;\n}\n\ninterface Tweet {\n  id: string;\n  name: string;\n  screenName: string;\n  statusesCount: number;\n  userId: string;\n}\n```\n\n## Typescript\n\nCopy the tslint and tsconfig json files from this repo into your own.\n\n## GraphQL\n\nMake a src directory and a index.ts file inside. Setup the imports\n\n```typescript\nimport * as admin from 'firebase-admin';\n\nconst serviceAccount = require('../service-account.json');\n\nadmin.initializeApp({\n  credential: admin.credential.cert(serviceAccount)\n});\n\nimport { ApolloServer, ApolloError, ValidationError, gql } from 'apollo-server';\n\ninterface User {\n  id: string;\n  name: string;\n  screenName: string;\n  statusesCount: number;\n}\n\ninterface Tweet {\n  id: string;\n  name: string;\n  screenName: string;\n  statusesCount: number;\n  userId: string;\n}\n```\n\n## Schema\n\nNow we setup our GraphQL schema\n\n```typescript\nconst typeDefs = gql`\n  # A Twitter User\n  type User {\n    id: ID!\n    name: String!\n    screenName: String!\n    statusesCount: Int!\n    tweets: [Tweets]!\n  }\n\n  # A Tweet Object\n  type Tweets {\n    id: ID!\n    text: String!\n    userId: String!\n    user: User!\n    likes: Int!\n  }\n\n  type Query {\n    tweets: [Tweets]\n    user(id: String!): User\n  }\n`;\n```\n\nThe ! signifies that this property is guaranteed to not be null. You'll notice that a user has an array of Tweets and a tweet has a user object in it, despite them being separate collections in our database. This is the magic of GraphQL, we can combine things across collections.\n\nFor the purpose of this tutorial we have two queries, an array of all tweets and a specific user based on their ID.\n\n## Resolver\n\nNext we setup our resolver, this turns GraphQL queries into data. First we setup our resolver for the base queries\n\n```typescript\nconst resolvers = {\n  Query: {\n    async tweets() {\n      const tweets = await admin\n        .firestore()\n        .collection('tweets')\n        .get();\n      return tweets.docs.map(tweet =\u003e tweet.data()) as Tweet[];\n    },\n    async user(_: null, args: { id: string }) {\n      try {\n        const userDoc = await admin\n          .firestore()\n          .doc(`users/${args.id}`)\n          .get();\n        const user = userDoc.data() as User | undefined;\n        return user || new ValidationError('User ID not found');\n      } catch (error) {\n        throw new ApolloError(error);\n      }\n    }\n  }\n};\n```\n\nThis will get an array of tweets or a user but how do we add the graph part of GraphQL and interconnect different collections such as all the Tweets a user has made or the details of a user that made a certain tweet?\n\n```typescript\nconst resolvers = {\n  Query: {\n    ...\n  },\n  User: {\n    async tweets(user) {\n      try {\n        const userTweets = await admin\n          .firestore()\n          .collection('tweets')\n          .where('userId', '==', user.id)\n          .get();\n        return userTweets.docs.map(tweet =\u003e tweet.data()) as Tweet[];\n      } catch (error) {\n        throw new ApolloError(error);\n      }\n    }\n  },\n  Tweets: {\n    async user(tweet) {\n      try {\n        const tweetAuthor = await admin\n          .firestore()\n          .doc(`users/${tweet.userId}`)\n          .get();\n        return tweetAuthor.data() as User;\n      } catch (error) {\n        throw new ApolloError(error);\n      }\n    }\n  }\n};\n```\n\nTake getting all the tweets a user has made as an example. You can see in our resolver we have a user object with a tweets property. Because tweets is a child of user, we can use the parent user to then query the tweets collection for all the tweets with that user ID.\n\n### Apollo Server\n\nFinally we setup our Apollo server, to work on App Engine we need to grab the port from the enviroment variables\n\n```typescript\nconst server = new ApolloServer({\n  typeDefs,\n  resolvers,\n  introspection: true\n});\n\nserver.listen({ port: process.env.PORT || 4000 }).then(({ url }) =\u003e {\n  console.log(`🚀  Server ready at ${url}`);\n});\n```\n\nIf you setup your npm scripts you should be able to run\n\n```bash\nnpm run serve\n```\n\nIf you navigate to the URL you shoud be able to see a GraphQL playground where you can query your API, congrats!\n\n## Apollo Engine\n\n[Apollo Engine](https://www.apollographql.com/engine) gives use awesome features such as caching, tracing, and error logging. First get an [Apollo Engine API key](https://engine.apollographql.com/) then change your Apollo server config to turn on engine\n\n```typescript\nconst server = new ApolloServer({\n  typeDefs,\n  resolvers,\n  engine: {\n    apiKey: \"\u003cAPOLLO ENGINE API KEY HERE\u003e\"\n  },\n  introspection: true\n});\n```\n\nNow when you npm serve and run some queries you should see some data populate the Apollo Engine dashboard with things like how fast your queries resolved. Cool!\n\n## App Engine\n\nFinally we can deploy to App engine so the world can access our GraphQL endpoint. In the root project folder create a file app.yaml. Inside is just one line\n\n```yaml\nruntime: nodejs8\n```\n\nAlso add the .gcloudignore file from this repo to your folder. Setup the gcloud SDK then point it to your Firebase project.\n\n```bash\ngcloud config set project \u003cprojectID\u003e\nnpm run build\ngcloud app deploy\n```\n\nYou should get a deployed URL, you can then query that using an GraphQL tool. I personally use [Insomnia’s GraphQL mode](https://support.insomnia.rest/article/61-graphql).\n\nCongratulations, you've setup a GraphQL server!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farjunyel%2Ffirestore-apollo-graphql","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farjunyel%2Ffirestore-apollo-graphql","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farjunyel%2Ffirestore-apollo-graphql/lists"}