Skip to content

Commit

Permalink
Merge pull request #7629 from apollographql/watson/mern-updates
Browse files Browse the repository at this point in the history
Add MERN documentation and update introduction
  • Loading branch information
michael-watson authored Aug 21, 2023
2 parents 4cda3b5 + d3b9884 commit 716e8db
Show file tree
Hide file tree
Showing 7 changed files with 260 additions and 94 deletions.
1 change: 1 addition & 0 deletions cspell-dict.txt
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ loglevel
Luca
MAXAGE
memjs
MERN
mget
Mget
microrouter
Expand Down
3 changes: 2 additions & 1 deletion docs/source/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
},
"Web Frameworks": {
"Integrations": "/integrations/integration-index",
"Building integrations": "/integrations/building-integrations"
"Building integrations": "/integrations/building-integrations",
"MERN stack tutorial": "/integrations/mern"
},
"Development Workflow": {
"Build and run queries": "/workflow/build-run-queries",
Expand Down
88 changes: 0 additions & 88 deletions docs/source/images/frontend_backend_diagram.svg

This file was deleted.

Binary file added docs/source/images/introduction.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/images/sandbox-mern-stack.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 3 additions & 5 deletions docs/source/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,18 @@ title: Introduction to Apollo Server

> 📣 **Apollo Server 4 is generally available!**
>
> [See what's new](./migration/)!
> [See what's new](./migration/)!
>
> Docs for Apollo Server 3 are [available here](/apollo-server/v3/).
**Apollo Server is an [open-source](https://github.com/apollographql/apollo-server), spec-compliant GraphQL server** that's compatible with any GraphQL client, including [Apollo Client](/react). It's the best way to build a production-ready, self-documenting GraphQL API that can use data from any source.

<img src="./images/frontend_backend_diagram.svg" width="500" alt="Diagram showing Apollo Server bridging frontend and backend" />
<img src="./images/introduction.jpg" width="600" alt="Diagram showing Apollo Server bridging GraphQL Operations to web apps and frameworks" />

#### You can use Apollo Server as:

* The GraphQL server for a [subgraph](./using-federation/apollo-subgraph-setup) in a federated supergraph
* A [stand-alone GraphQL server](./api/standalone)
* An add-on to your application's existing Node.js [middleware](./integrations/integration-index) (such as [Express](./api/express-middleware), AWS Lambda, or Fastify)
* An add-on to any new or existing Node.js apps—this includes apps running on [Express](./api/express-middleware) (including [MERN stack](./integrations/mern) apps), [AWS Lambda](https://www.npmjs.com/package/@as-integrations/aws-lambda), [Azure Functions](https://www.npmjs.com/package/@as-integrations/azure-functions), [Cloudflare](https://www.npmjs.com/package/@as-integrations/cloudflare-workers), [Fastify](https://www.npmjs.com/package/@as-integrations/fastify), and [more](./integrations/integration-index)

#### Apollo Server provides:

Expand All @@ -25,7 +24,6 @@ title: Introduction to Apollo Server
* **Universal compatibility** with any data source, any build tool, and any GraphQL client
* **Production readiness**, enabling you to confidently run your graph in production


#### Ready to try it out?

<div align="center">
Expand Down
254 changes: 254 additions & 0 deletions docs/source/integrations/mern.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
---
title: Teaching the MERN stack to speak GraphQL
---

Apollo Server is designed to work seamlessly with MERN stack (MongoDB, Express, React, Node) applications. This tutorial shows how to add Apollo Server to an existing MERN stack project. Specifically, this tutorial demonstrates how to:

- Run an Apollo Server instance that lets you execute GraphQL operations
- Expose a GraphQL route in a MERN stack application

## Prerequisites

This tutorial assumes that you're familiar with the command line and JavaScript. Additionally, it requires the following:
- You've installed a recent Node.js version (`v14.16.0+`).
- You've completed MongoDB's [MERN stack tutorial](https://www.mongodb.com/languages/mern-stack-tutorial) or have your own existing MERN stack application.
- The tutorial's code examples build off the tutorial, but you can adapt them to your application's requirements.
- You have a MongoDB database with a `records` collection that has `name`, `position`, and `level` columns.
- The tutorial's code examples use these column names, but you can adapt them to your database's schema.

## Step 1: Install dependencies

In your server folder, run the following command to install these packages and save them in
your server project's `node_modules` directory:

```bash
npm install graphql graphql-tag @apollo/subgraph @apollo/server
```

- [`graphql`](https://www.npmjs.com/package/graphql) is the JavaScript reference implementation for GraphQL
- [`graphql-tag` ](https://www.npmjs.com/package/graphql-tag) is a utility package to parse a GraphQL string into the standard GraphQL abstract syntax tree (AST)
- [`@apollo/subgraph`](https://www.npmjs.com/package/@apollo/subgraph) is a utility package for creating GraphQL microservices
- [`@apollo/server`](https://www.npmjs.com/package/@apollo/server) is a spec-compliant GraphQL server that exposes a `/graphql` endpoint

## Step 2: Define your GraphQL schema

Every GraphQL server (including Apollo Server) uses a schema to define the data that clients can query. The following example creates a schema for the [prerequisite tutorial](https://www.mongodb.com/languages/mern-stack-tutorial)'s `records` collection:

In your server's `/src` folder, create a `schema.graphql` file and paste in the following schema:

```graphql
type Query {
record(id:ID!): Record
records: [Record]
}

type Mutation {
createRecord(name: String!, position: String, level: String): Record
deleteRecord(id: ID!): Boolean
updateRecord(id: ID! name: String, position: String, level: String): Record
}

type Record {
id: ID
name: String
position: String
level: String
}
```
This schema lets you perform various actions on records: fetching single or multiple records, creating new records, deleting records, and updating existing records. For more information on schema definition, check out the [schema basics](../schema/schema/) docs.

## Step 3: Define the resolvers

Resolver functions are responsible for performing the actions defined in the schema—for example, fetching and updating records. In a MERN stack application, they're how you connect the GraphQL schema to your MongoDB instance.

In your server's `/src` folder, create a new `resolvers.ts` file and paste in the following resolvers:

```ts
import db from "./db/conn.ts";

const resolvers = {
Record: {
id: (parent) => parent.id ?? parent._id,
},
Query: {
async record(_, { id }) {
let collection = await db.collection("records");
let query = { _id: new ObjectId(id) };

return await collection.findOne(query);
},
async records(_, __, context) {
let collection = await db.collection("records");
const records = await collection.find({}).toArray();
return records;
},
},
Mutation: {
async createRecord(_, { name, position, level }, context) {
let collection = await db.collection("records");
const insert = await collection.insertOne({ name, position, level });
if (insert.acknowledged)
return { name, position, level, id: insert.insertedId };
return null;
},
async updateRecord(_, args, context) {
const id = new ObjectId(args.id);
let query = { _id: new ObjectId(id) };
let collection = await db.collection("records");
const update = await collection.updateOne(
query,
{ $set: { ...args } }
);

if (update.acknowledged)
return await collection.findOne(query);

return null;
},
async deleteRecord(_, { id }, context) {
let collection = await db.collection("records");
const dbDelete = await collection.deleteOne({ _id: new ObjectId(id) });
return dbDelete.acknowledged && dbDelete.deletedCount == 1 ? true : false;
},
},
};

export default resolvers;
```

You may have noticed the code for each resolver function is similar to the code in your application's `/record` route. That's because these resolvers provide the same logic as performing CRUD operations on your records collection.

To learn more about writing resolver functions, check out the [resolver docs](../data/resolvers).

## Step 4: Add Apollo Server to your Express server

Now you can begin integrating Apollo Server into your Express server. Wherever you instantiate your `express` server (usually `mern/server/server.ts`), import `@apollo/server` and its `expressMiddleware`. Then, instantiate and `start` the Apollo Server:

```ts
import express, { json } from 'express';
import cors from 'cors';
import "./loadEnvironment.mjs";
import records from "./routes/record.mjs";
//highlight-start
import gql from "graphql-tag";
import { ApolloServer } from '@apollo/server';
import { buildSubgraphSchema } from '@apollo/subgraph';
import { expressMiddleware } from '@apollo/server/express4';
import resolvers from "./resolvers.mjs";
import { readFileSync } from "fs";
//highlight-end

const PORT = process.env.PORT || 5050;
const app = express();

app.use(cors());
app.use(express.json());

//highlight-start
const typeDefs = gql(
readFileSync("schema.graphql", {
encoding: "utf-8",
})
);

const server = new ApolloServer({
schema: buildSubgraphSchema({ typeDefs, resolvers }),
});
// Note you must call `start()` on the `ApolloServer`
// instance before passing the instance to `expressMiddleware`
await server.start();
//highlight-end

app.use("/record", records);

// start the Express server
app.listen(PORT, () => {
console.log(`Server is running on port: ${PORT}`);
});
```

Next, you'll use the middleware to integrate the [previously defined resolvers](#step-3-define-the-resolvers) into a route.

## Step 5: Add the `/graphql` route to your server API endpoints

In the same server file, add the `/graphql` route:

```ts
app.use("/record", records);
// Specify the path to mount the server
//highlight-start
app.use(
'/graphql',
cors(),
json(),
expressMiddleware(server),
);
//highlight-end

app.listen(PORT, () => {
console.log(`Server is running on port: ${PORT}`);
});
```

This route provides access to the Apollo Server's [resolver functions you previously defined](#step-3-define-the-resolvers). Note that the `/records` route hasn't been removed. That means your Express server can handle both GraphQL and RESTful routes.

## Step 6: Start the server

You're ready to start your server! Run the following from your project's server
directory:

```bash
npm start
```

Your console output should display `Server is running on port: 5050`.

## Step 7: Execute your first query

You can now execute GraphQL queries on the server. To execute your first query, you can use [**Apollo Sandbox**](/graphos/explorer/sandbox/).

Visit your MERN server in your browser at the `/graphql` route, which will open the Apollo Sandbox:

<img class="screenshot" src="../images/sandbox-mern-stack.jpg" alt="Apollo Sandbox" />

The Sandbox UI includes:

- A URL input bar for connecting to other GraphQL servers (in the upper left)
- Tabs for schema exploration, search, and settings (on the left)
- An **Operations** panel for writing and executing queries (in the middle)
- A **Response** panel for viewing query results (on the right)

To learn more about what Sandbox offers, check out the [Sandbox docs](/graphos/explorer/sandbox/).

The server supports querying the `records`, so let's do it! Paste this GraphQL query string for executing the `records` query into the **Operations** panel and click the run button.

```graphql
query GetRecords {
records {
name
position
level
}
}
```

You should see your records appear in the **Response** panel.

## Complete example

You can view and fork the complete server example on Code Sandbox:

<a href="https://codesandbox.io/s/github/apollographql/docs-examples/tree/main/apollo-server/v4/mern-stack?fontsize=14&hidenavigation=1&theme=dark">
<img
alt="Edit server-getting-started"
src="https://codesandbox.io/static/img/play-codesandbox.svg"
/>
</a>

## Next steps

Congrats on completing the tutorial! 🎉 Incorporating a GraphQL server into your MERN application marks a pivotal step towards creating more efficient, flexible, and user-centric web experiences. And now that you've integrated Apollo Server into your MERN stack application, you can use [GraphOS](/graphos/) to build and scale even faster.

While this tutorial only covers the server portion of the MERN stack, the `/client` folder in the [completed example](#complete-example) picks up where the tutorial left off and implements [`@apollo/client`](/react/) to interact with the server. For more information on implementing the Apollo Client, head to the [getting started docs](/react/get-started).

For more hands-on learning on GraphQL and Apollo's server and client libraries, check out our interactive [Odyssey tutorials](https://www.apollographql.com/tutorials/).

0 comments on commit 716e8db

Please sign in to comment.