Modern API Development (Part 3) : Add GraphQL
Tags: graphql, apolloserver, express, api
Published: 2023-11-13 08:11:55

>*This post is a follow-up to the previous one at [Part 2: Initiating Server](https://dev.to/mitch1009/modern-api-developmentpart-2-initialize-server-1b7j). If you're looking to integrate GraphQL into an existing REST API, this guide is tailored for you. For those aiming to incorporate GraphQL into a new REST API, please refer to the instructions provided in the earlier posts. you can also follow the guide on my blog [Mitch Guru](https://blog.mitch.guru/guides)*


I'm delighted that you've reached this point, and I hope you're finding the journey enjoyable. As we continue with this series, there's still much more ground to cover. Now, let's shift our focus to the modernization of the API. I understand if you've been pondering, "What's considered modern about this server?" especially since it relies on the trusted 'express.' Take a moment to relax because you're about to delve into the contemporary aspects of this series.

we are going to cover the following topcs in this guide:


- Install additional dependencies - [GraphQl Tools](https://the-guild.dev/graphql/tools/docs/introduction), [Apollo Server 4](https://www.apollographql.com/docs/apollo-server/getting-started)
- Reconfigure the API to have separate routes, one for Graphql and one for REST
   
- Implement GraphQL Endpont and resolvers
- Test the API 



Alright, no more talking – let's jump right in!

```bash
# install all dependencies for graphql to work in our API
pnpm api add graphql @apollo/server @graphql-tools/load @graphql-tools/graphql-file-loader
```

The `graphql` package is now installed. we can proceed to configure our API.
firstly we need to create a `graphql` folder in the `api` folder. this is where our graphql files will be stored. i will create a `main.graphql` file in that folder.

We are going to have three types initialized in this file:
-  Response - custom type for responses
-  Query - required root graphql query type
-  Mutation  - required root mution type

```graphql
#api/graphql/main.graphql file
type Response {
    message: String!
    success: Boolean!
    error: String
}

type Query {
    hello: String
}

type Mutation {
    hello: String
}
```

Up next we need to move some code from `main.ts` to be isolated to their own module. i am refering to the router which is set inside the main file.

```js 
//api/src/main.ts file
// ... rest of code
const router = express.Router();
// Set initial route
router.get("/", (_req, res) => {
    res.send({ message: "Monorepo API Configured!", success: true});
});
// .. rest of code 
```

We are moving this part to a separate module called `api/src/endpoints/rest/restEndpoints.ts`. where we will do some modifications and export the module

```js 

// api/src/endpoints/rest/restEndpoints.ts
import express, { Router } from "express";

const restEndpoint: Router = express.Router();
// define routes
restEndpoint.get("/", (_req, res) => {
    res.send({ message: "Rest Endpoint Initialized!" });
})

export { restEndpoint }
```

Now lets updated `api/src/main.ts` to use the rest endpoint.

```js 
// api/src/main.ts file
import { restEndpoint } from './endpoints';

// ... rest of code
// Set v1/api endpoint
app.use("/v1/api", restEndpoint);
// .. rest of code 
```


>As observed, the import originates from the `./endpoint` module rather than `./endpoint/rest/restEndpoint`. This is accomplished by incorporating a `barrel` file within the `endpoints` folder, which exports all submodule functionalities.
[read more on what a barrel file is here](https://basarat.gitbook.io/typescript/main-1/barrel).


We can run our server again to be sure that we did not break anything.

```shell
# run server
pnpm api dev
# our server should be running properly  as expected. 
# http://localhost:9100 or http://localhost:9000 depending on the PORT set in .env file
```

Hold on, this isn't GraphQL yet; we're still operating a REST API! yes you are right, its one of the steps toward adding multiple routes tou our API.
Up next we are going to create another route for our API inside `api/src/endpoints/graphql/graphqlEndpoints.ts` module. Additionally we also need to create a resolver module `api/src/endpoints/graphql/resolvers.ts` which is going to be responsible for implementating all resolvers. 

<Tabs>
<TabItem value="graphqlEndpoints.ts" label="api/src/endpoints/graphql/graphqlEndpoints.ts">

```js 
// api/src/endpoints/graphql/graphqlEndpoints.ts
import { ApolloServer } from '@apollo/server';
import { loadSchemaSync } from '@graphql-tools/load';
import { GraphQLFileLoader } from '@graphql-tools/graphql-file-loader';
import { resolvers } from '.';
// load schema from graphql files
const typeDefs=loadSchemaSync('./graphql/*.graphql', {
    loaders: [
        new GraphQLFileLoader()
    ]
});

// create apollo server
const server = new ApolloServer({
    typeDefs,
    resolvers
});

// export server
 export {  server}
 ``` 
 </TabItem>
 <TabItem value="resolvers.ts" label="api/src/endpoints/graphql/resolvers.ts">

> please note this is a minimal configuration for now.
```js 
// api/src/endpoints/graphql/resolvers.ts

export const resolvers = {
    Query: {
        hello: () => `Hello there welcome to api monorepo`
    },
    Mutation: {
        hello: (_: unknown, args: { name: string }) => `Hello ${args.name} welcome to api monorepo`

    }
}
```
</TabItem>
 </Tabs>

A sigh of relief we are now ready to test our REST + GraphQL APIs running on the same server.

```shell 
# run server
pnpm api dev
# our server should be running properly  as expected. 
# http://localhost:9100/v1/rest and http://localhost:9000/v1/graphql 
```


>We can now happily commit our changes.  and push them to our remote repository under the  [feature/part3](https://github.com/mitch1009/api-monorepo/tree/feature/part3)  branch.

Watch out for **Part 4** where we are going to integrate prisma ORM and **part 5** Where we are going to introduce Hasura