{"id":3166,"date":"2020-10-02T11:15:00","date_gmt":"2020-10-02T11:15:00","guid":{"rendered":"http:\/\/the-codest.localhost\/blog\/deploy-graphql-mongodb-api-using-netlify-functions\/"},"modified":"2026-04-27T09:55:11","modified_gmt":"2026-04-27T09:55:11","slug":"wdrozenie-graphql-mongodb-api-przy-uzyciu-funkcji-netlify","status":"publish","type":"post","link":"https:\/\/thecodest.co\/pl\/blog\/deploy-graphql-mongodb-api-using-netlify-functions\/","title":{"rendered":"Wdra\u017canie API GraphQL\/MongoDB przy u\u017cyciu funkcji Netlify"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Goals<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Configure both local and lambda servers.<\/li>\n\n\n\n<li>Connect both to MongoDB.<\/li>\n\n\n\n<li>Implement basic authentication.<\/li>\n\n\n\n<li>Deploy serverless Apollo <a href=\"https:\/\/thecodest.co\/blog\/graphql-lessons-learned-in-production\/\">GraphQL<\/a> <a href=\"https:\/\/thecodest.co\/pl\/blog\/compare-staff-augmentation-firms-that-excel-in-api-team-staffing-for-financial-technology-projects\/\">API<\/a> with Netlify.<\/li>\n\n\n\n<li><a href=\"https:\/\/thecodest.co\/blog\/why-you-should-probably-use-typescript\">Use Typescript<\/a>.<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Initial setup<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"javascript\" class=\"language-javascript\"><code>npm init -y<\/code><\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Install dependencies<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"javascript\" class=\"language-javascript\"><code>npm install --save <a href=\"https:\/\/thecodest.co\/pl\/dictionary\/typescript-developer\/\">typescript<\/a> graphql aws-lambda @types\/aws-lambda<\/code><\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Let&#8217;s start<\/h2>\n\n\n\n<p>First, add the <code>tsconfig.json<\/code> to main directory:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"json\" class=\"language-json\"><code> {\n \"compilerOptions\": {\n \"target\": \"es5\",\n \"module\": \"commonjs\",\n \"allowJs\": true,\n \"strict\": true,\n \"esModuleInterop\": true,\n \"skipLibCheck\": true,\n \"forceConsistentCasingInFileNames\": true\n },\n \"include\": [\"src\/*.ts\", \"src\/**\/*.ts\", \"src\/**\/*.js\"],\n \"exclude\": [\"node_modules\"]\n }<\/code><\/code><\/pre>\n\n\n\n<p>Now, let&#8217;s create <code>src\/server.ts<\/code> for servers implementations. Then add two functions: one for local server and second for lambda.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"javascript\" class=\"language-javascript\">\/\/ src\/server.ts\nimport { ApolloServer as ApolloServerLambda } from \"apollo-server-lambda\";\nimport { ApolloServer } from \"apollo-server\";\n\n\nconst createLambdaServer = () =&gt;\n  new ApolloServerLambda({\n    typeDefs,\n    resolvers,\n    introspection: true,\n    playground: true,\n    },\n  });\n\nconst createLocalServer = () =&gt;\n  new ApolloServer({\n    typeDefs,\n    resolvers,\n    introspection: true,\n    playground: true,\n    },\n  });\n\nexport { createLambdaServer, createLocalServer };<\/code><\/pre>\n\n\n\n<p>OK, we don\u2019t have any resolvers or type definitions so we need to create some. Let&#8217;s assume that, at first, we want to create users and receive info about them.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"javascript\" class=\"language-javascript\">\/\/ src\/schemas.ts\nconst { gql } = require(\"apollo-server-lambda\");\n\nconst userSchema = gql`\n  type User {\n    id: ID!\n    email: String!\n    name: String!\n  }\n\n  type Query {\n    user(id: ID!): User!\n  }\n\n  type Mutation {\n    createUser(name: String!, email: String!, password: String!): User!\n  }\n`;<\/code><\/pre>\n\n\n\n<p>If you\u2019re not familiar with this, <a href=\"https:\/\/www.apollographql.com\/docs\/tutorial\/schema\/\" rel=\"nofollow\">Apollo prepared a very nice tutorial <\/a><\/p>\n\n\n\n<p>Now let\u2019s create a user resolver with one query and one mutation.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"javascript\" class=\"language-javascript\">\/\/ src\/resolvers.ts\nconst userResolver = {\n  Query: {\n    user: async (parent, args, context, info) => {\n      {...}\n    },\n  },\n  Mutation: {\n    createUser: async (parent, args, context, info) => {\n      {...}\n    },\n  },\n};<\/code><\/pre>\n\n\n\n<p>But we don\u2019t have any data&#8230; Let&#8217;s fix it \ud83d\ude09<\/p>\n\n\n\n<p>Don\u2019t forget to import type definition and resolver onto the server.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"javascript\" class=\"language-javascript\">\/\/ src\/server.ts\nimport { ApolloServer as ApolloServerLambda } from \"apollo-server-lambda\";\nimport { ApolloServer } from \"apollo-server\";\n\nimport { typeDefs } from \".\/schemas\";\nimport { resolvers } from \".\/resolvers\";\n\n{...}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Connect with MongoDB via mongoose<\/h2>\n\n\n\n<p>Now it&#8217;s a good time to create a connection with our database. In this particular case, it will be MongoDB. It\u2019s free and easy to maintain. But before that, let&#8217;s install two more dependencies:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"javascript\" class=\"language-javascript\">npm install --save mongoose dotenv<\/code><\/pre>\n\n\n\n<p>The first step is to create a User Model.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"javascript\" class=\"language-javascript\">\/\/ src\/model.ts\nimport mongoose, { Document, Error, Schema } from \"mongoose\";\n\nexport type User = Document &amp; {\n  _id: string,\n  email: string,\n  name: string,\n  password: string,\n};\n\ndelete mongoose.connection.models[\"User\"];\n\nconst UserSchema: Schema = new Schema({\n  email: {\n    type: String,\n    required: true,\n    unique: true,\n  },\n  name: {\n    type: String,\n    required: true,\n    minLength: 3,\n    maxLength: 32,\n  },\n  password: {\n    type: String,\n    required: true,\n  },\n});\n\nexport const userModel = mongoose.model &lt; User > (\"User\", UserSchema);<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Make passwords more safe<\/h3>\n\n\n\n<p>Security first! Let\u2019s now secure our passwords by hashing them.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"javascript\" class=\"language-javascript\"><code>npm install --save bcrypt @types\/bcrypt<\/code><\/code><\/pre>\n\n\n\n<p>Now, implement the password security inside the pre-middleware callback. Pre-middleware functions are executed one after another, when each middleware calls next. To make the passwords safe, we are using a technique which generates a salt and <a href=\"https:\/\/thecodest.co\/pl\/blog\/hash-to-use-or-not-to-use\/\">hash<\/a> on separate function calls.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"javascript\" class=\"language-javascript\">\/\/ src\/model.ts\nimport bcrypt from \"bcrypt\";\n{...}\nconst SALT_WORK_FACTOR: number = 10;\n\nUserSchema.pre(\"save\", function (next) {\n  const user = this as User;\n  if (!this.isModified(\"password\")) return next();\n\n  bcrypt.genSalt(SALT_WORK_FACTOR, function (err, salt) {\n    if (err) return next(err);\n\n    bcrypt.hash(user.password, salt, function (err, hash) {\n      if (err) return next(err);\n      user.password = hash;\n      next();\n    });\n  });\n});\n{...}<\/code><\/pre>\n\n\n\n<p>Then add comparePasswords method to UserSchema:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"javascript\" class=\"language-javascript\">\/\/ src\/model.ts\n{...}\nUserSchema.methods.comparePasswords = function (\n  candidatePassword: string,\n  cb: (err: Error | null, same: boolean | null) => void\n) {\n  const user = this as User;\n  bcrypt.compare(candidatePassword, user.password, (err, isMatch) => {\n    if (err) {\n      return cb(err, null);\n    }\n    cb(null, isMatch);\n  });\n};\n{...}<\/code><\/pre>\n\n\n\n<p>And of course, modify User type.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"javascript\" class=\"language-javascript\">type comparePasswordFunction = (\n  candidatePassword: string,\n  cb: (err: Error, isMatch: boolean) => void\n) => void;\n\nexport type User = Document &amp; {\n  _id: string,\n  email: string,\n  name: string,\n  password: string,\n  comparePasswords: comparePasswordFunction,\n};<\/code><\/pre>\n\n\n\n<p>Now we can arrange a connection between servers and databases. <code>MONGODB_URI<\/code> is an environment variable which contains a connection string needed to create the connection. You can get it from your cluster panel after you log into your MongoDB atlas account. Put it inside <code>.env<\/code><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"javascript\" class=\"language-javascript\">\/\/ .env\nMONGODB_URI = ...;<\/code><\/pre>\n\n\n\n<p>Always remember to add that file to <code>.gitignore<\/code>. Great! Now let&#8217;s add a function which allow to connect with db.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"javascript\" class=\"language-javascript\">\/\/ src\/server.ts\nimport mongoose, { Connection } from \"mongoose\";\n{...}\nlet cachedDb: Connection;\n\nconst connectToDatabase = async () => {\n  if (cachedDb) return;\n\n  await mongoose.connect(process.env.MONGODB_URI || \"\", {\n    useNewUrlParser: true,\n    useUnifiedTopology: true,\n    useFindAndModify: false,\n    useCreateIndex: true,\n  });\n  cachedDb = mongoose.connection;\n};\n{...}<\/code><\/pre>\n\n\n\n<p>The context is an object which is shared across all resolvers. To provide it, we just need to add a context initialization function to the ApolloServer constructor. Let&#8217;s do it.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"javascript\" class=\"language-javascript\">\/\/ src\/server.ts\nimport { userModel } from \".\/models\/user.model\";\n{...}\nconst createLambdaServer = async () =>\n  new ApolloServerLambda({\n    typeDefs,\n    resolvers,\n    introspection: true,\n    playground: true,\n    context: async () => {\n      await connectToDatabase();\n\n      return {\n        models: {\n          userModel,\n        },\n      };\n    },\n  });\n\nconst createLocalServer = () =>\n  new ApolloServer({\n    typeDefs,\n    resolvers,\n    introspection: true,\n    playground: true,\n    context: async () => {\n      await connectToDatabase();\n\n      return {\n        models: {\n          userModel,\n        },\n      };\n    }\n  });<\/code><\/pre>\n\n\n\n<p>As you can see, we are also passing <code>userModel<\/code> through <code>context<\/code>. We can now update resolver:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"javascript\" class=\"language-javascript\">\/\/ resolvers.ts\nconst userResolver = {\n  Query: {\n    user: async (_, { email, name, password }, { models: { userModel } }) => {\n      const user = await userModel.findById({ _id: id }).exec();\n      return user;\n    },\n  },\n  Mutation: {\n    createUser: async (_, { id }, { models: { userModel } }) => {\n      const user = await userModel.create({ email, name, password });\n      return user;\n    },\n  },\n};<\/code><\/pre>\n\n\n\n<p>Looks nice! Now create a basic server instance:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"javascript\" class=\"language-javascript\">\/\/ src\/index.ts\nimport { createLocalServer } from \".\/server\";\nrequire(\"dotenv\").config();\n\nconst port = process.env.PORT || 4000;\n\nconst server = createLocalServer();\n\nserver.listen(port).then(({ url }) => {\n  console.log(`Server ir running at ${url}`);\n});<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Starting the local server with Nodemon<\/h2>\n\n\n\n<p>Last thing before run, add <code>nodemon.json<\/code><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"json\" class=\"language-json\">{\n  \"watch\": [\"src\"],\n  \"ext\": \".ts,.js\",\n  \"ignore\": [],\n  \"exec\": \"ts-node --transpile-only .\/src\/index.ts\"\n}<\/code><\/pre>\n\n\n\n<p>Add script to <code>package.json<\/code><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"json\" class=\"language-json\">\"scripts\": {\n    \"start\": \"nodemon\"\n  },<\/code><\/pre>\n\n\n\n<p>And run!<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"json\" class=\"language-json\">npm start<\/code><\/pre>\n\n\n\n<p>You should get such info inside terminal:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"json\" class=\"language-json\">Server ir running at http:\/\/localhost:4000\/<\/code><\/pre>\n\n\n\n<p>If yes, open the <code>http:\/\/localhost:4000\/<\/code> inside your browser.<\/p>\n\n\n\n<p>The GraphQL playground should appear. Let\u2019s create a new user!<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"\/app\/uploads\/2024\/05\/createuser.png\" alt=\"createUser.png\" title=\"createUser\"\/><\/figure>\n\n\n\n<p>Take a look at how it looks in the database.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"\/app\/uploads\/2024\/05\/databasejohndoe.png\" alt=\"databaseJohnDoe.png\" title=\"databaseJohnDoe\"\/><\/figure>\n\n\n\n<p>Cool! Everything works fine!<\/p>\n\n\n\n<p>Let\u2019s try and get some user info.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"\/app\/uploads\/2024\/05\/userwithoutauth.png\" alt=\"userWithoutAuth.png\" title=\"userWithoutAuth\"\/><\/figure>\n\n\n\n<p>And add the password field&#8230;<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"\/app\/uploads\/2024\/05\/userpassword.png\" alt=\"userPassword.png\" title=\"userPassword\"\/><\/figure>\n\n\n\n<p>Nice! We receive error&nbsp;<code>Cannot query field \"password\" on type \"User\".\"<\/code>. As you can check back, we didn&#8217;t add this field inside the user type definition. It is there on purpose. We should not make it possible to query any password or other sensitive <a href=\"https:\/\/thecodest.co\/pl\/blog\/app-data-collection-security-risks-value-and-types-explored\/\">data<\/a>.<\/p>\n\n\n\n<p>Another thing&#8230; We can get user data without any authentication&#8230; it is not a good solution. We need to fix it.<\/p>\n\n\n\n<p>But before&#8230;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Configure Codegen<\/h2>\n\n\n\n<p>Let\u2019s use the GraphQL <a href=\"https:\/\/thecodest.co\/pl\/dictionary\/what-is-code-refactoring\/\">code<\/a> generator to get a compatible base type, based on our schema.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"javascript\" class=\"language-javascript\">npm install --save @graphql-codegen\/cli @graphql-codegen\/introspection\n@graphql-codegen\/typescript @graphql-codegen\/typescript-resolvers<\/code><\/pre>\n\n\n\n<p>Create <code>codegen.yml<\/code><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"yaml\" class=\"language-yaml\">overwrite: true\nschema: \"http:\/\/localhost:4000\"\ngenerates:\n  .\/src\/generated\/graphql.ts:\n    plugins:\n      - \"typescript\"\n      - \"typescript-resolvers\"\n  .\/graphql.schema.json:\n    plugins:\n      - \"introspection\"\n<\/code><\/pre>\n\n\n\n<p>Add <code>codegen<\/code> script to <code>package.json<\/code><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"json\" class=\"language-json\">\"scripts\": {\n    \"start\": \"nodemon\",\n    \"codegen\": \"graphql-codegen --config .\/codegen.yml\",\n  },<\/code><\/pre>\n\n\n\n<p>Then, when the local server is running, run script:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"json\" class=\"language-json\">npm run codegen<\/code><\/pre>\n\n\n\n<p>In case of success you will get message:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"javascript\" class=\"language-javascript\">  \u221a Parse configuration\n  \u221a Generate outputs<\/code><\/pre>\n\n\n\n<p>If you receive that info, two files should appear:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>graphql.schema.json<\/code> in the main directory<\/li>\n\n\n\n<li><code>graphql.ts<\/code> in newly created path <code>src\/generated<\/code><\/li>\n<\/ul>\n\n\n\n<p>We are more interested in the second one. If you open it, you will notice a nice structure of types.<\/p>\n\n\n\n<p>Now we can improve our resolvers:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"javascript\" class=\"language-javascript\">\/\/ src\/resolvers.ts\nimport { Resolvers, Token, User } from \".\/generated\/graphql\";\n\nconst userResolver: Resolvers = {\n  Query: {\n    user: async (_, { id }, { models: { userModel }, auth }): Promise&lt;User> => {\n      const user = await userModel.findById({ _id: id }).exec();\n      return user;\n    },\n  },\n  Mutation: {\n    createUser: async (\n      _,\n      { email, name, password },\n      { models: { userModel } }\n    ): Promise&lt;User> => {\n      const user = await userModel.create({\n        email,\n        name,\n        password,\n      });\n      return user;\n    },\n  },\n};<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Authentication<\/h2>\n\n\n\n<p>Next, let\u2019s set up a simple token-based authentication.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"javascript\" class=\"language-javascript\">npm install --save jsonwebtoken @types\/jsonwebtoken<\/code><\/pre>\n\n\n\n<p>Create <code>checkAuth<\/code> function to verify if the token is valid. We will add result to the context so that we can access it inside the resolvers.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"javascript\" class=\"language-javascript\">\/\/ src\/server.ts\nimport { IncomingHttpHeaders } from \"http\";\nimport {\n  APIGatewayProxyEvent,\n  APIGatewayProxyEventHeaders,\n  Context,\n} from \"aws-lambda\";\nimport jwt from \"jsonwebtoken\";\n{...}\nconst checkAuth = async ({ token } : APIGatewayProxyEventHeaders | IncomingHttpHeaders ) => {\n  if (typeof token === \"string\") {\n    try {\n      return await jwt.verify(token, \"riddlemethis\");\n    } catch (e) {\n      throw new AuthenticationError(`Your session expired. Sign in again.`);\n    }\n  }\n};\n{...}\nconst createLambdaServer = async (\n  { headers }: APIGatewayProxyEvent,\n  context: Context\n) => {\n  return new ApolloServerLambda({\n    typeDefs,\n    resolvers,\n    context: async () => {\n      await connectToDatabase();\n\n      const auth = await checkAuth(headers);\n\n      return {\n        auth,\n        models: {\n          userModel,\n        },\n      };\n    },\n  });\n};\n\nfunction createLocalServer() {\n  return new ApolloServer({\n    typeDefs,\n    resolvers,\n    introspection: true,\n    playground: true,\n    context: async ({ req: { headers } = {} }) => {\n      const auth = await checkAuth(headers);\n      await connectToDatabase();\n\n      return {\n         auth,\n         models: {\n          userModel,\n        },\n      };\n    },\n  });\n}<\/code><\/pre>\n\n\n\n<p>Also, we need a way to create such a token. The best way is to implement a login query inside our resolver.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"javascript\" class=\"language-javascript\">\/\/ resolvers.ts\nimport { Resolvers, Token, User } from \".\/generated\/graphql\";\n\nconst userResolver: Resolvers = {\n  Query: {\n    user: async (_, { id }, { models: { userModel }, auth }): Promise&lt;User> => {\n      if (!auth) throw new AuthenticationError(\"You are not authenticated\");\n\n      const user = await userModel.findById({ _id: id }).exec();\n      return user;\n    },\n    login: async (\n      _,\n      { email, password },\n      { models: { userModel } }\n    ): Promise&lt;Token> => {\n      const user = await userModel.findOne({ email }).exec();\n\n      if (!user) throw new AuthenticationError(\"Invalid credentials\");\n\n      const matchPasswords = bcrypt.compareSync(password, user.password);\n\n      if (!matchPasswords) throw new AuthenticationError(\"Invalid credentials\");\n\n      const token = jwt.sign({ id: user.id }, \"riddlemethis\", {\n        expiresIn: 60,\n      });\n\n      return { token };\n    },\n  },\n  Mutation: {\n    createUser: async (\n      _,\n      { email, name, password },\n      { models: { userModel } }\n    ): Promise&lt;User> => {\n      const user = await userModel.create({\n        email,\n        name,\n        password,\n      });\n      return user;\n    },\n  },\n};<\/code><\/pre>\n\n\n\n<p>You need also to update user type definitions by Token type and login query.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"javascript\" class=\"language-javascript\">type Token {\n    token: String!\n  }\n\ntype Query {\n    user(id: ID!): User!\n    login(email: String!, password: String!): Token!\n  }<\/code><\/pre>\n\n\n\n<p>Let&#8217;s now try to get user without token<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"\/app\/uploads\/2024\/05\/noauth.png\" alt=\"noAuth.png\" title=\"noAuth\"\/><\/figure>\n\n\n\n<p>OK, works fine! Try to log in<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"\/app\/uploads\/2024\/05\/token.png\" alt=\"token.png\" title=\"token\"\/><\/figure>\n\n\n\n<p>Let&#8217;s try again to get user, but this time with token added to headers<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"\/app\/uploads\/2024\/05\/withtoken.png\" alt=\"withToken.png\" title=\"withToken\"\/><\/figure>\n\n\n\n<p>Cool! And what if we set wrong credentials?<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"\/app\/uploads\/2024\/05\/wrongemail.png\" alt=\"wrongEmail.png\" title=\"wrongEmail\"\/><\/figure>\n\n\n\n<p>Nice!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Prepare to Deploy<\/h2>\n\n\n\n<p>Last step: deploy serverless api with Netlify!<\/p>\n\n\n\n<p>Create folder <code>lambda<\/code> in main dir and put two files inside:<\/p>\n\n\n\n<p>First contains <a href=\"https:\/\/thecodest.co\/pl\/case-studies\/how-the-codest-helped-bright-launch-a-scalable-edtech-platform\/\">AWS<\/a> handler. It create a ApolloServerLambda server instance and<br> then expose a handler using createHandler of that instance.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"javascript\" class=\"language-javascript\">\/\/ lambda\/graphql.ts\nimport { APIGatewayProxyEvent, Context } from \"aws-lambda\";\nimport { createLambdaServer } from \"???\";\n\nexport const handler = async (\n  event: APIGatewayProxyEvent,\n  context: Context\n) => {\n  const server = await createLambdaServer(event, context);\n\n  return new Promise((res, rej) => {\n    const cb = (err: Error, args: any) => (err ? rej(err) : res(args));\n    server.createHandler()(event, context, cb);\n  });\n};<\/code><\/pre>\n\n\n\n<p><a href=\"https:\/\/www.apollographql.com\/docs\/apollo-server\/deployment\/lambda\/\" rel=\"nofollow\">You can read more about it.<\/a><\/p>\n\n\n\n<p>Second one, is the tsconfig. Important part is the <code>outDir<\/code> field.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"json\" class=\"language-json\">\/\/ lambda\/tsconfig.json\n{\n  \"compilerOptions\": {\n    \"sourceMap\": true,\n    \"noImplicitAny\": true,\n    \"module\": \"commonjs\",\n    \"target\": \"es6\",\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"moduleResolution\": \"<a href=\"https:\/\/thecodest.co\/pl\/dictionary\/what-is-node-js-used-for\/\">node<\/a>\",\n    \"skipLibCheck\": true,\n    \"esModuleInterop\": true,\n    \"outDir\": \".\/dist\"\n  },\n  \"include\": [\".\/*.ts\", \".\/**\/*.ts\", \".\/**\/*.js\"]\n}<\/code><\/pre>\n\n\n\n<p>But there&#8217;s a problem. We can&#8217;t use <code>\/src<\/code> dir because Netlify can&#8217;t reach outside of the lambda folder. So we must bundle it.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"javascript\" class=\"language-javascript\">npm install --save ncp<\/code><\/pre>\n\n\n\n<p>It`s a package that allows as to copy directory.<\/p>\n\n\n\n<p>Add <code>bundle<\/code> script to <code>package.json<\/code><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"json\" class=\"language-json\">\"scripts\": {\n    \"bundle\": \"ncp .\/src .\/lambda\/bundle\",\n    \"codegen\": \"graphql-codegen --config .\/codegen.yml\",\n    \"start\": \"nodemon\",\n  },<\/code><\/pre>\n\n\n\n<p>Now if you run <code>npm run bundle<\/code>, you san see, that in newly created <code>lambda\/bundle<\/code> dir we have all files from <code>src\/<\/code>.<\/p>\n\n\n\n<p>Update the import path inside <code>lambda\/graphql.ts<\/code><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"javascript\" class=\"language-javascript\">\/\/ lambda\/graphql.ts\nimport { APIGatewayProxyEvent, Context } from \"aws-lambda\";\nimport { createLambdaServer } from \".\/bundle\/server\";\n\n{...}<\/code><\/pre>\n\n\n\n<p>You can now add lambda\/bundle dir to <code>.gitignore<\/code><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Deploy with Netlify<\/h2>\n\n\n\n<p>We must to tell Netlify what the build command is and where our functions live. To to it let&#8217;s create <code>netlify.toml<\/code> file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"json\" class=\"language-json\">\/\/ netlify.toml\n[build]\n  command = \"npm run build:lambda\"\n  functions = \"lambda\/dist\"<\/code><\/pre>\n\n\n\n<p>As you can see, it&#8217;s same directory as defined as a <code>outDir<\/code> field in <code>lambda\/tsconfig.json<\/code><\/p>\n\n\n\n<p>This is how your app structure should look like (well&#8230; part of it ;))<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">app\n\u2514\u2500\u2500\u2500lambda\n\u2502 \u2514\u2500\u2500\u2500\u2500bundle\n\u2502 \u2502 graphql.ts\n\u2502   tsconfig.json.ts\n\u2514\u2500\u2500\u2500src\n\u2502 \u2514\u2500\u2500\u2500generated\n\u2502 \u2502    \u2502 graphql.ts\n\u2502 \u2502 index.ts\n\u2502 \u2502 model.ts\n\u2502 \u2502 resolvers.ts\n\u2502 \u2502 schemas.ts\n\u2502   server.ts\n\u2502\n\u2502 codegen.yml\n\u2502 graphql.schema.json\n\u2502 netlify.toml\n\u2502 nodemon.json\n\u2502 tsconfig.json<\/code><\/pre>\n\n\n\n<p>Add <code>bundle:lambda<\/code> script to <code>package.json<\/code><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"json\" class=\"language-json\">\"scripts\": {\n    \"build:lambda\": \"npm run bundle &amp;&amp; tsc -p lambda\/tsconfig.json\",\n    \"bundle\": \"ncp .\/src .\/lambda\/bundle\",\n    \"codegen\": \"graphql-codegen --config .\/codegen.yml\",\n    \"start\": \"nodemon\",\n  },<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Deploy<\/h2>\n\n\n\n<p>Let\u2019s try deploying our app via Netlify.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Log to your Netlify account,<\/li>\n\n\n\n<li>Connect with your Github,<\/li>\n\n\n\n<li>Click &#8216;New site from Git&#8217; button,<\/li>\n\n\n\n<li>Select a proper repo,<\/li>\n\n\n\n<li>Set the build command npm run build:lambda,<\/li>\n\n\n\n<li>Add environment variable (MONGODB_URI),<\/li>\n\n\n\n<li>Deploy&#8230;<\/li>\n<\/ol>\n\n\n\n<p>And TAAADAAAA&#8230;<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"\/app\/uploads\/2024\/05\/pagenotfound.png\" alt=\"pageNotFound.png\" title=\"pageNotFound\"\/><\/figure>\n\n\n\n<p>That is because the endpoint is by default not the <code>http:\/\/page\/<\/code> but <code>http:\/\/page\/.netlify\/functions\/graphql<\/code>.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"\/app\/uploads\/2024\/05\/withoutredirect.png\" alt=\"withoutRedirect.png\" title=\"withoutRedirect\"\/><\/figure>\n\n\n\n<p>How to fix it? It&#8217;s very simple. Just create <code>_redirects<\/code> with:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"javascript\" class=\"language-javascript\">\/ \/.netlify\/functions\/graphql 200!<\/code><\/pre>\n\n\n\n<p>Deploy again and check.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"\/app\/uploads\/2024\/05\/redirect.png\" alt=\"redirect.png\" title=\"redirect\"\/><\/figure>\n\n\n\n<p>Hope you liked it! Feel free to improve and change.<\/p>\n\n\n\n<p><b>Read more:<\/b><\/p>\n\n\n\n<p><a href=\"https:\/\/thecodest.co\/blog\/how-not-to-kill-a-project-with-bad-coding-practices\/\">How not to kill a project with bad coding practices?<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/thecodest.co\/blog\/web-app-security-target-blank-vulnerability\/\">Web app security. Target=&#8221;_blank&#8221; vulnerability<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/thecodest.co\/blog\/web-app-security-xss-vulnerability\/\">Web app security &#8211; XSS vulnerability<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Goals Initial setup Install dependencies Let&#8217;s start First, add the tsconfig.json to main directory: Now, let&#8217;s create src\/server.ts for servers implementations. Then add two functions: one for local server and second for lambda. OK, we don\u2019t have any resolvers or type definitions so we need to create some. Let&#8217;s assume that, at first, we want [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":3167,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[8],"tags":[],"class_list":["post-3166","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-software-development"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.3 (Yoast SEO v27.3) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Deploy GraphQL\/MongoDB API using Netlify Functions - The Codest<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/thecodest.co\/pl\/blog\/wdrozenie-graphql-mongodb-api-przy-uzyciu-funkcji-netlify\/\" \/>\n<meta property=\"og:locale\" content=\"pl_PL\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Deploy GraphQL\/MongoDB API using Netlify Functions\" \/>\n<meta property=\"og:description\" content=\"Goals Initial setup Install dependencies Let&#8217;s start First, add the tsconfig.json to main directory: Now, let&#8217;s create src\/server.ts for servers implementations. Then add two functions: one for local server and second for lambda. OK, we don\u2019t have any resolvers or type definitions so we need to create some. Let&#8217;s assume that, at first, we want [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/thecodest.co\/pl\/blog\/wdrozenie-graphql-mongodb-api-przy-uzyciu-funkcji-netlify\/\" \/>\n<meta property=\"og:site_name\" content=\"The Codest\" \/>\n<meta property=\"article:published_time\" content=\"2020-10-02T11:15:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-04-27T09:55:11+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/thecodest.co\/app\/uploads\/2024\/05\/deploy-graphql.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1280\" \/>\n\t<meta property=\"og:image:height\" content=\"720\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"thecodest\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"thecodest\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minut\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/thecodest.co\\\/blog\\\/deploy-graphql-mongodb-api-using-netlify-functions\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/thecodest.co\\\/blog\\\/deploy-graphql-mongodb-api-using-netlify-functions\\\/\"},\"author\":{\"name\":\"thecodest\",\"@id\":\"https:\\\/\\\/thecodest.co\\\/#\\\/schema\\\/person\\\/7e3fe41dfa4f4e41a7baad4c6e0d4f76\"},\"headline\":\"Deploy GraphQL\\\/MongoDB API using Netlify Functions\",\"datePublished\":\"2020-10-02T11:15:00+00:00\",\"dateModified\":\"2026-04-27T09:55:11+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/thecodest.co\\\/blog\\\/deploy-graphql-mongodb-api-using-netlify-functions\\\/\"},\"wordCount\":986,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/thecodest.co\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/thecodest.co\\\/blog\\\/deploy-graphql-mongodb-api-using-netlify-functions\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/thecodest.co\\\/app\\\/uploads\\\/2024\\\/05\\\/deploy-graphql.png\",\"articleSection\":[\"Software Development\"],\"inLanguage\":\"pl-PL\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/thecodest.co\\\/blog\\\/deploy-graphql-mongodb-api-using-netlify-functions\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/thecodest.co\\\/blog\\\/deploy-graphql-mongodb-api-using-netlify-functions\\\/\",\"url\":\"https:\\\/\\\/thecodest.co\\\/blog\\\/deploy-graphql-mongodb-api-using-netlify-functions\\\/\",\"name\":\"Deploy GraphQL\\\/MongoDB API using Netlify Functions - The Codest\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/thecodest.co\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/thecodest.co\\\/blog\\\/deploy-graphql-mongodb-api-using-netlify-functions\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/thecodest.co\\\/blog\\\/deploy-graphql-mongodb-api-using-netlify-functions\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/thecodest.co\\\/app\\\/uploads\\\/2024\\\/05\\\/deploy-graphql.png\",\"datePublished\":\"2020-10-02T11:15:00+00:00\",\"dateModified\":\"2026-04-27T09:55:11+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/thecodest.co\\\/blog\\\/deploy-graphql-mongodb-api-using-netlify-functions\\\/#breadcrumb\"},\"inLanguage\":\"pl-PL\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/thecodest.co\\\/blog\\\/deploy-graphql-mongodb-api-using-netlify-functions\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"pl-PL\",\"@id\":\"https:\\\/\\\/thecodest.co\\\/blog\\\/deploy-graphql-mongodb-api-using-netlify-functions\\\/#primaryimage\",\"url\":\"https:\\\/\\\/thecodest.co\\\/app\\\/uploads\\\/2024\\\/05\\\/deploy-graphql.png\",\"contentUrl\":\"https:\\\/\\\/thecodest.co\\\/app\\\/uploads\\\/2024\\\/05\\\/deploy-graphql.png\",\"width\":1280,\"height\":720},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/thecodest.co\\\/blog\\\/deploy-graphql-mongodb-api-using-netlify-functions\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/thecodest.co\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Deploy GraphQL\\\/MongoDB API using Netlify Functions\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/thecodest.co\\\/#website\",\"url\":\"https:\\\/\\\/thecodest.co\\\/\",\"name\":\"The Codest\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/thecodest.co\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/thecodest.co\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"pl-PL\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/thecodest.co\\\/#organization\",\"name\":\"The Codest\",\"url\":\"https:\\\/\\\/thecodest.co\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pl-PL\",\"@id\":\"https:\\\/\\\/thecodest.co\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/thecodest.co\\\/app\\\/uploads\\\/2024\\\/03\\\/thecodest-logo.svg\",\"contentUrl\":\"https:\\\/\\\/thecodest.co\\\/app\\\/uploads\\\/2024\\\/03\\\/thecodest-logo.svg\",\"width\":144,\"height\":36,\"caption\":\"The Codest\"},\"image\":{\"@id\":\"https:\\\/\\\/thecodest.co\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/pl.linkedin.com\\\/company\\\/codest\",\"https:\\\/\\\/clutch.co\\\/profile\\\/codest\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/thecodest.co\\\/#\\\/schema\\\/person\\\/7e3fe41dfa4f4e41a7baad4c6e0d4f76\",\"name\":\"thecodest\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pl-PL\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/5dbfe6a1e8c86e432e8812759e34e6fe82ebac75119ae3237a6c1311fa19caf4?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/5dbfe6a1e8c86e432e8812759e34e6fe82ebac75119ae3237a6c1311fa19caf4?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/5dbfe6a1e8c86e432e8812759e34e6fe82ebac75119ae3237a6c1311fa19caf4?s=96&d=mm&r=g\",\"caption\":\"thecodest\"},\"url\":\"https:\\\/\\\/thecodest.co\\\/pl\\\/author\\\/thecodest\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Wdra\u017canie API GraphQL\/MongoDB przy u\u017cyciu funkcji Netlify - The Codest","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/thecodest.co\/pl\/blog\/wdrozenie-graphql-mongodb-api-przy-uzyciu-funkcji-netlify\/","og_locale":"pl_PL","og_type":"article","og_title":"Deploy GraphQL\/MongoDB API using Netlify Functions","og_description":"Goals Initial setup Install dependencies Let&#8217;s start First, add the tsconfig.json to main directory: Now, let&#8217;s create src\/server.ts for servers implementations. Then add two functions: one for local server and second for lambda. OK, we don\u2019t have any resolvers or type definitions so we need to create some. Let&#8217;s assume that, at first, we want [&hellip;]","og_url":"https:\/\/thecodest.co\/pl\/blog\/wdrozenie-graphql-mongodb-api-przy-uzyciu-funkcji-netlify\/","og_site_name":"The Codest","article_published_time":"2020-10-02T11:15:00+00:00","article_modified_time":"2026-04-27T09:55:11+00:00","og_image":[{"width":1280,"height":720,"url":"https:\/\/thecodest.co\/app\/uploads\/2024\/05\/deploy-graphql.png","type":"image\/png"}],"author":"thecodest","twitter_card":"summary_large_image","twitter_misc":{"Written by":"thecodest","Est. reading time":"7 minut"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/thecodest.co\/blog\/deploy-graphql-mongodb-api-using-netlify-functions\/#article","isPartOf":{"@id":"https:\/\/thecodest.co\/blog\/deploy-graphql-mongodb-api-using-netlify-functions\/"},"author":{"name":"thecodest","@id":"https:\/\/thecodest.co\/#\/schema\/person\/7e3fe41dfa4f4e41a7baad4c6e0d4f76"},"headline":"Deploy GraphQL\/MongoDB API using Netlify Functions","datePublished":"2020-10-02T11:15:00+00:00","dateModified":"2026-04-27T09:55:11+00:00","mainEntityOfPage":{"@id":"https:\/\/thecodest.co\/blog\/deploy-graphql-mongodb-api-using-netlify-functions\/"},"wordCount":986,"commentCount":0,"publisher":{"@id":"https:\/\/thecodest.co\/#organization"},"image":{"@id":"https:\/\/thecodest.co\/blog\/deploy-graphql-mongodb-api-using-netlify-functions\/#primaryimage"},"thumbnailUrl":"https:\/\/thecodest.co\/app\/uploads\/2024\/05\/deploy-graphql.png","articleSection":["Software Development"],"inLanguage":"pl-PL","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/thecodest.co\/blog\/deploy-graphql-mongodb-api-using-netlify-functions\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/thecodest.co\/blog\/deploy-graphql-mongodb-api-using-netlify-functions\/","url":"https:\/\/thecodest.co\/blog\/deploy-graphql-mongodb-api-using-netlify-functions\/","name":"Wdra\u017canie API GraphQL\/MongoDB przy u\u017cyciu funkcji Netlify - The Codest","isPartOf":{"@id":"https:\/\/thecodest.co\/#website"},"primaryImageOfPage":{"@id":"https:\/\/thecodest.co\/blog\/deploy-graphql-mongodb-api-using-netlify-functions\/#primaryimage"},"image":{"@id":"https:\/\/thecodest.co\/blog\/deploy-graphql-mongodb-api-using-netlify-functions\/#primaryimage"},"thumbnailUrl":"https:\/\/thecodest.co\/app\/uploads\/2024\/05\/deploy-graphql.png","datePublished":"2020-10-02T11:15:00+00:00","dateModified":"2026-04-27T09:55:11+00:00","breadcrumb":{"@id":"https:\/\/thecodest.co\/blog\/deploy-graphql-mongodb-api-using-netlify-functions\/#breadcrumb"},"inLanguage":"pl-PL","potentialAction":[{"@type":"ReadAction","target":["https:\/\/thecodest.co\/blog\/deploy-graphql-mongodb-api-using-netlify-functions\/"]}]},{"@type":"ImageObject","inLanguage":"pl-PL","@id":"https:\/\/thecodest.co\/blog\/deploy-graphql-mongodb-api-using-netlify-functions\/#primaryimage","url":"https:\/\/thecodest.co\/app\/uploads\/2024\/05\/deploy-graphql.png","contentUrl":"https:\/\/thecodest.co\/app\/uploads\/2024\/05\/deploy-graphql.png","width":1280,"height":720},{"@type":"BreadcrumbList","@id":"https:\/\/thecodest.co\/blog\/deploy-graphql-mongodb-api-using-netlify-functions\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/thecodest.co\/"},{"@type":"ListItem","position":2,"name":"Deploy GraphQL\/MongoDB API using Netlify Functions"}]},{"@type":"WebSite","@id":"https:\/\/thecodest.co\/#website","url":"https:\/\/thecodest.co\/","name":"The Codest","description":"","publisher":{"@id":"https:\/\/thecodest.co\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/thecodest.co\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"pl-PL"},{"@type":"Organization","@id":"https:\/\/thecodest.co\/#organization","name":"The Codest","url":"https:\/\/thecodest.co\/","logo":{"@type":"ImageObject","inLanguage":"pl-PL","@id":"https:\/\/thecodest.co\/#\/schema\/logo\/image\/","url":"https:\/\/thecodest.co\/app\/uploads\/2024\/03\/thecodest-logo.svg","contentUrl":"https:\/\/thecodest.co\/app\/uploads\/2024\/03\/thecodest-logo.svg","width":144,"height":36,"caption":"The Codest"},"image":{"@id":"https:\/\/thecodest.co\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/pl.linkedin.com\/company\/codest","https:\/\/clutch.co\/profile\/codest"]},{"@type":"Person","@id":"https:\/\/thecodest.co\/#\/schema\/person\/7e3fe41dfa4f4e41a7baad4c6e0d4f76","name":"thecodest","image":{"@type":"ImageObject","inLanguage":"pl-PL","@id":"https:\/\/secure.gravatar.com\/avatar\/5dbfe6a1e8c86e432e8812759e34e6fe82ebac75119ae3237a6c1311fa19caf4?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/5dbfe6a1e8c86e432e8812759e34e6fe82ebac75119ae3237a6c1311fa19caf4?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/5dbfe6a1e8c86e432e8812759e34e6fe82ebac75119ae3237a6c1311fa19caf4?s=96&d=mm&r=g","caption":"thecodest"},"url":"https:\/\/thecodest.co\/pl\/author\/thecodest\/"}]}},"_links":{"self":[{"href":"https:\/\/thecodest.co\/pl\/wp-json\/wp\/v2\/posts\/3166","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/thecodest.co\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/thecodest.co\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/thecodest.co\/pl\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/thecodest.co\/pl\/wp-json\/wp\/v2\/comments?post=3166"}],"version-history":[{"count":34,"href":"https:\/\/thecodest.co\/pl\/wp-json\/wp\/v2\/posts\/3166\/revisions"}],"predecessor-version":[{"id":7317,"href":"https:\/\/thecodest.co\/pl\/wp-json\/wp\/v2\/posts\/3166\/revisions\/7317"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/thecodest.co\/pl\/wp-json\/wp\/v2\/media\/3167"}],"wp:attachment":[{"href":"https:\/\/thecodest.co\/pl\/wp-json\/wp\/v2\/media?parent=3166"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/thecodest.co\/pl\/wp-json\/wp\/v2\/categories?post=3166"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/thecodest.co\/pl\/wp-json\/wp\/v2\/tags?post=3166"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}