Introduce
In the previous section , we have completed the Authentication section for the API that works on Firebase Cloud Functions, in this section, we will continue to build the API based on GraphQL and Firebase Realtime DB.
Stack used this time:
- The Authentication Module is obtained from the previous section
- Firebase Cloud Functions: Serverless (FaaS) Platform
- Firebase Realtime Database
- Express: Nodejs framework (router, middleware)
- Apollo Server: GraphQL server tools
Learn and install
GraphQL
To begin, we’ll find out what the GraphQL pants are, right? There are many explanations on the viblo that are very specific and easy to understand, so I’ll explain briefly in the scope of this article. You can read this article to better understand GraphQL offline I will summarize by quoting the main points of the article Let’s learn about GraphQL
So, what is GraphQL?
GraphQL is a Graph Query Language for API. It was developed by Facebook. GraphQL has been almost completely replacing REST since its inception, being much more efficient, powerful and flexible.
How is GraphQL different from REST?
The problem that REST is having is that the response of the REST data is too much or too little. In both cases, the performance of the application is significantly affected. The solution that GraphQL offers is to allow data declaration where a client can determine exactly the data they need from an API.
Moreover, instead of having many endpoints like REST, GraphQL has only one endpoint. The client and server interact with each other via the POST protocol
GraphQL Schema Definition Language (SDL)
In order for the Client and the Server to have a common and unified understanding, we need to define the Schema to see what data the Client can access and what the Server returns to the client. Example Schema of User
1 2 3 4 5 | type Clothes { name: String! style: String! } |
(!! Means a schema field will be required)
Fetching Data (Query) and Mutation
The client will have to specify which fields are needed to send to the server
For example
1 2 3 4 5 6 7 | <span class="token punctuation">{</span> clothes <span class="token punctuation">{</span> name style <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Mutations are ways that clients transfer data to the server to perform operations: Create, Update, Delete
For example:
1 2 3 4 5 6 | mutation { addClothes(name:"adidas_ultraboost", style:"sport") { name } } |
Above are some concepts to use in this article, now go into your code
Dependencies
In addition to the init firebase like the previous articles, this time we need to install some more libraries
1 2 3 4 | npm install express npm install graphql npm install apollo-server-express |
Add the necessary libraries to the index.js
file
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <span class="token keyword">const</span> functions <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">"firebase-functions"</span> <span class="token punctuation">)</span> <span class="token keyword">const</span> express <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'express'</span> <span class="token punctuation">)</span> <span class="token keyword">const</span> firebaseAdmin <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'firebase-admin'</span> <span class="token punctuation">)</span> <span class="token keyword">const</span> productValidate <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'./validate/product.store'</span> <span class="token punctuation">)</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> ApolloServer <span class="token punctuation">,</span> gql <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">"apollo-server-express"</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">/* Express */</span> <span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">express</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token comment">// for cloud</span> firebaseAdmin <span class="token punctuation">.</span> <span class="token function">initializeApp</span> <span class="token punctuation">(</span> functions <span class="token punctuation">.</span> <span class="token function">config</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> firebase <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token keyword">const</span> api <span class="token operator">=</span> functions <span class="token punctuation">.</span> https <span class="token punctuation">.</span> <span class="token function">onRequest</span> <span class="token punctuation">(</span> app <span class="token punctuation">)</span> module <span class="token punctuation">.</span> exports <span class="token operator">=</span> <span class="token punctuation">{</span> api <span class="token punctuation">,</span> <span class="token punctuation">}</span> |
Defining Schema for Apollo Server
1 2 3 4 5 6 7 8 9 10 11 12 13 | <span class="token keyword">const</span> typeDefs <span class="token operator">=</span> gql <span class="token template-string"><span class="token string">` type Clothes { name: String style: String } type Query { clothes: [Clothes] } type Mutation { addClothes(name: String!, style: String!): Clothes } `</span></span> <span class="token punctuation">;</span> |
I will define a schema as Clothes. In Query, there will be clothes
return Clothes, like Mutation will have an addClothes
method
Defining resolvers for Apollo Server
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <span class="token keyword">const</span> resolvers <span class="token operator">=</span> <span class="token punctuation">{</span> Query <span class="token punctuation">:</span> <span class="token punctuation">{</span> clothes <span class="token punctuation">:</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> firebaseAdmin <span class="token punctuation">.</span> <span class="token function">database</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">ref</span> <span class="token punctuation">(</span> <span class="token string">"clothes"</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">once</span> <span class="token punctuation">(</span> <span class="token string">"value"</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">then</span> <span class="token punctuation">(</span> snap <span class="token operator">=></span> snap <span class="token punctuation">.</span> <span class="token function">val</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">then</span> <span class="token punctuation">(</span> val <span class="token operator">=></span> Object <span class="token punctuation">.</span> <span class="token function">keys</span> <span class="token punctuation">(</span> val <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">map</span> <span class="token punctuation">(</span> key <span class="token operator">=></span> val <span class="token punctuation">[</span> key <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> Mutation <span class="token punctuation">:</span> <span class="token punctuation">{</span> addClothes <span class="token punctuation">:</span> <span class="token keyword">async</span> <span class="token punctuation">(</span> root <span class="token punctuation">,</span> args <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> clothes <span class="token operator">=</span> <span class="token punctuation">{</span> name <span class="token punctuation">:</span> args <span class="token punctuation">.</span> name <span class="token punctuation">,</span> style <span class="token punctuation">:</span> args <span class="token punctuation">.</span> style <span class="token punctuation">}</span> <span class="token keyword">await</span> firebaseAdmin <span class="token punctuation">.</span> <span class="token function">database</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">ref</span> <span class="token punctuation">(</span> <span class="token string">"clothes"</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">push</span> <span class="token punctuation">(</span> clothes <span class="token punctuation">)</span> <span class="token keyword">return</span> clothes <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> |
Similar to typeDef, Resolver will tell Apollo Server where to get data.
- clothes : To fetch all the data from Firebase, because GraphQL needs array data while Firebase returns Object so we need to transform a bit
- addClothes : Add a record to Firebase
Finally we will create an instance of ApolloServer, then apply it to the express app
1 2 3 | <span class="token keyword">const</span> server <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ApolloServer</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> typeDefs <span class="token punctuation">,</span> resolvers <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> server <span class="token punctuation">.</span> <span class="token function">applyMiddleware</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> app <span class="token punctuation">,</span> path <span class="token punctuation">:</span> <span class="token string">"/products"</span> <span class="token punctuation">,</span> cors <span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
The complete index.js file now:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | <span class="token keyword">const</span> functions <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">"firebase-functions"</span> <span class="token punctuation">)</span> <span class="token keyword">const</span> express <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'express'</span> <span class="token punctuation">)</span> <span class="token keyword">const</span> firebaseAdmin <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'firebase-admin'</span> <span class="token punctuation">)</span> <span class="token keyword">const</span> productValidate <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'./validate/product.store'</span> <span class="token punctuation">)</span> <span class="token comment">/* Express */</span> <span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">express</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token comment">// for cloud</span> firebaseAdmin <span class="token punctuation">.</span> <span class="token function">initializeApp</span> <span class="token punctuation">(</span> functions <span class="token punctuation">.</span> <span class="token function">config</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> firebase <span class="token punctuation">)</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> ApolloServer <span class="token punctuation">,</span> gql <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">"apollo-server-express"</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> typeDefs <span class="token operator">=</span> gql <span class="token template-string"><span class="token string">` type Clothes { name: String style: String } type Query { clothes: [Clothes] } type Mutation { addClothes(name: String!, style: String!): Clothes } `</span></span> <span class="token punctuation">;</span> <span class="token keyword">const</span> resolvers <span class="token operator">=</span> <span class="token punctuation">{</span> Query <span class="token punctuation">:</span> <span class="token punctuation">{</span> clothes <span class="token punctuation">:</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> firebaseAdmin <span class="token punctuation">.</span> <span class="token function">database</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">ref</span> <span class="token punctuation">(</span> <span class="token string">"clothes"</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">once</span> <span class="token punctuation">(</span> <span class="token string">"value"</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">then</span> <span class="token punctuation">(</span> snap <span class="token operator">=></span> snap <span class="token punctuation">.</span> <span class="token function">val</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">then</span> <span class="token punctuation">(</span> val <span class="token operator">=></span> Object <span class="token punctuation">.</span> <span class="token function">keys</span> <span class="token punctuation">(</span> val <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">map</span> <span class="token punctuation">(</span> key <span class="token operator">=></span> val <span class="token punctuation">[</span> key <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> Mutation <span class="token punctuation">:</span> <span class="token punctuation">{</span> addClothes <span class="token punctuation">:</span> <span class="token keyword">async</span> <span class="token punctuation">(</span> root <span class="token punctuation">,</span> args <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> clothes <span class="token operator">=</span> <span class="token punctuation">{</span> name <span class="token punctuation">:</span> args <span class="token punctuation">.</span> name <span class="token punctuation">,</span> style <span class="token punctuation">:</span> args <span class="token punctuation">.</span> style <span class="token punctuation">}</span> <span class="token keyword">await</span> firebaseAdmin <span class="token punctuation">.</span> <span class="token function">database</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">ref</span> <span class="token punctuation">(</span> <span class="token string">"clothes"</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">push</span> <span class="token punctuation">(</span> clothes <span class="token punctuation">)</span> <span class="token keyword">return</span> clothes <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> server <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ApolloServer</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> typeDefs <span class="token punctuation">,</span> resolvers <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> server <span class="token punctuation">.</span> <span class="token function">applyMiddleware</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> app <span class="token punctuation">,</span> path <span class="token punctuation">:</span> <span class="token string">"/products"</span> <span class="token punctuation">,</span> cors <span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> api <span class="token operator">=</span> functions <span class="token punctuation">.</span> https <span class="token punctuation">.</span> <span class="token function">onRequest</span> <span class="token punctuation">(</span> app <span class="token punctuation">)</span> module <span class="token punctuation">.</span> exports <span class="token operator">=</span> <span class="token punctuation">{</span> api <span class="token punctuation">,</span> <span class="token punctuation">}</span> |
We start deploying using the command firebase deploy --only functions
Experiment
After successfully deploying we can use some GraphQL client tools like GraphiQL, Postman I will use Postman to test you guys. As I mentioned above, the Client and Server communicate with each other via the POST method, so they will set up for Postman similar to the image below:
Mutation
I will add a record to the DB and get my name back using the GraphQL query as shown below
Query
Get the name
attribute for all records
Get more style attributes as well
Conclusion
Above is my article on Google Firebase services with Nodejs and incorporating some other components that I learned. In addition to the services I used the last 3 articles, there are many other services to learn and apply, see you in the following articles.