"use strict";(self.webpackChunkdocs_website=self.webpackChunkdocs_website||[]).push([[79073],{15680:(e,t,n)=>{n.d(t,{xA:()=>d,yg:()=>g});var a=n(96540);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),s=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},d=function(e){var t=s(e.components);return a.createElement(l.Provider,{value:t},e.children)},c="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,l=e.parentName,d=p(e,["components","mdxType","originalType","parentName"]),c=s(n),u=r,g=c["".concat(l,".").concat(u)]||c[u]||h[u]||i;return n?a.createElement(g,o(o({ref:t},d),{},{components:n})):a.createElement(g,o({ref:t},d))}));function g(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=u;var p={};for(var l in t)hasOwnProperty.call(t,l)&&(p[l]=t[l]);p.originalType=e,p[c]="string"==typeof e?e:r,o[1]=p;for(var s=2;s{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>l,default:()=>g,frontMatter:()=>p,metadata:()=>s,toc:()=>c});n(96540);var a=n(15680);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){return t=null!=t?t:{},Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):function(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))})),e}function o(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},i=Object.keys(e);for(a=0;a=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}const p={title:"Creating a New GraphQL Endpoint in GMS",slug:"/api/graphql/graphql-endpoint-development",custom_edit_url:"https://github.com/datahub-project/datahub/blob/master/docs/api/graphql/graphql-endpoint-development.md"},l="Creating a New GraphQL Endpoint in GMS",s={unversionedId:"docs/api/graphql/graphql-endpoint-development",id:"version-1.1.0/docs/api/graphql/graphql-endpoint-development",title:"Creating a New GraphQL Endpoint in GMS",description:"This guide will walk you through how to add a new GraphQL endpoint in GMS.",source:"@site/versioned_docs/version-1.1.0/docs/api/graphql/graphql-endpoint-development.md",sourceDirName:"docs/api/graphql",slug:"/api/graphql/graphql-endpoint-development",permalink:"/docs/1.1.0/api/graphql/graphql-endpoint-development",draft:!1,editUrl:"https://github.com/datahub-project/datahub/blob/master/docs/api/graphql/graphql-endpoint-development.md",tags:[],version:"1.1.0",frontMatter:{title:"Creating a New GraphQL Endpoint in GMS",slug:"/api/graphql/graphql-endpoint-development",custom_edit_url:"https://github.com/datahub-project/datahub/blob/master/docs/api/graphql/graphql-endpoint-development.md"},sidebar:"overviewSidebar",previous:{title:"Developing on Metadata Ingestion",permalink:"/docs/1.1.0/metadata-ingestion/developing"},next:{title:"datahub-web-react",permalink:"/docs/1.1.0/datahub-web-react"}},d={},c=[{value:"GraphQL API changes",id:"graphql-api-changes",level:2},{value:"Adding an endpoint definition",id:"adding-an-endpoint-definition",level:3},{value:"Query or Mutation?",id:"query-or-mutation",level:4},{value:"Input and Output Types",id:"input-and-output-types",level:4},{value:"Building your changes",id:"building-your-changes",level:3},{value:"Java Server changes",id:"java-server-changes",level:2},{value:"Adding a resolver",id:"adding-a-resolver",level:3},{value:"Adding the resolver to the GMS server",id:"adding-the-resolver-to-the-gms-server",level:3},{value:"Testing your change",id:"testing-your-change",level:2}],h={toc:c},u="wrapper";function g(e){var{components:t}=e,n=o(e,["components"]);return(0,a.yg)(u,i(function(e){for(var t=1;t")," interface where ",(0,a.yg)("inlineCode",{parentName:"p"},"T")," is ",(0,a.yg)("inlineCode",{parentName:"p"},"CompletableFuture"),".This interface provides a ",(0,a.yg)("inlineCode",{parentName:"p"},"get")," method that takes in a ",(0,a.yg)("inlineCode",{parentName:"p"},"DataFetchingEnvironment")," and returns a ",(0,a.yg)("inlineCode",{parentName:"p"},"CompletableFuture")," of the endpoint return type. The resolver can contain any services needed to resolve the endpoint, and use them to compute the result."),(0,a.yg)("blockquote",null,(0,a.yg)("p",{parentName:"blockquote"},(0,a.yg)("strong",{parentName:"p"},"listOwnershipTypes example:")," The ",(0,a.yg)("a",{parentName:"p",href:"https://github.com/datahub-project/datahub/commit/ea92b86e6ab4cbb18742fb8db6bc11fae8970cdb#diff-d2ad02d0ec286017d032640cfdb289fbdad554ef5f439355104766fa068513ac"},(0,a.yg)("inlineCode",{parentName:"a"},"ListOwnershipTypesResolver"))," class implements ",(0,a.yg)("inlineCode",{parentName:"p"},"DataFetcher>")," since this is the return type of the endpoint. It contains an ",(0,a.yg)("inlineCode",{parentName:"p"},"EntityClient")," instance variable to handle the ownership type fetching.")),(0,a.yg)("p",null,"Often the structure of the ",(0,a.yg)("inlineCode",{parentName:"p"},"Resolver")," classes is to call a service to receive a response, then use a method to transform the result from the service into the GraphQL type returned."),(0,a.yg)("blockquote",null,(0,a.yg)("p",{parentName:"blockquote"},(0,a.yg)("strong",{parentName:"p"},"listOwnershipTypes example:")," The ",(0,a.yg)("a",{parentName:"p",href:"https://github.com/datahub-project/datahub/commit/ea92b86e6ab4cbb18742fb8db6bc11fae8970cdb#diff-d2ad02d0ec286017d032640cfdb289fbdad554ef5f439355104766fa068513ac"},(0,a.yg)("inlineCode",{parentName:"a"},"ListOwnershipTypesResolver"))," calls the ",(0,a.yg)("inlineCode",{parentName:"p"},"search")," method in its ",(0,a.yg)("inlineCode",{parentName:"p"},"EntityClient")," to get the ownership types, then calls the defined ",(0,a.yg)("inlineCode",{parentName:"p"},"mapUnresolvedOwnershipTypes")," function to transform the response into a ",(0,a.yg)("inlineCode",{parentName:"p"},"ListOwnershipTypesResult"),".")),(0,a.yg)("p",null,"Tip: Resolver classes can be tested with unit tests!"),(0,a.yg)("blockquote",null,(0,a.yg)("p",{parentName:"blockquote"},(0,a.yg)("strong",{parentName:"p"},"listOwnershipTypes example:")," The reference commit adds the ",(0,a.yg)("a",{parentName:"p",href:"https://github.com/datahub-project/datahub/commit/ea92b86e6ab4cbb18742fb8db6bc11fae8970cdb#diff-9443d70b221e36e9d47bfa9244673d1cd553a92ae496d03622932ad0a4832045"},(0,a.yg)("inlineCode",{parentName:"a"},"ListOwnershipTypeResolverTest")," class"),".")),(0,a.yg)("h3",{id:"adding-the-resolver-to-the-gms-server"},"Adding the resolver to the GMS server"),(0,a.yg)("p",null,"The main GMS server is located in ",(0,a.yg)("a",{parentName:"p",href:"https://github.com/datahub-project/datahub/blob/master/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/GmsGraphQLEngine.java"},(0,a.yg)("inlineCode",{parentName:"a"},"GmsGraphQLEngine.java")),". To hook up the resolver to handle the endpoint, find the relevant section based on if the new enpoint is a ",(0,a.yg)("inlineCode",{parentName:"p"},"Query")," or a ",(0,a.yg)("inlineCode",{parentName:"p"},"Mutation")," and add the resolver as the ",(0,a.yg)("inlineCode",{parentName:"p"},"dataFetcher")," for the name of the endpoint."),(0,a.yg)("blockquote",null,(0,a.yg)("p",{parentName:"blockquote"},(0,a.yg)("strong",{parentName:"p"},"listOwnershipTypes example:")," The following line of code is added in ",(0,a.yg)("a",{parentName:"p",href:"https://github.com/datahub-project/datahub/commit/ea92b86e6ab4cbb18742fb8db6bc11fae8970cdb#diff-e04c9c2d80cbfd7aa7e3e0f867248464db0f6497684661132d6ead81ded21856"},(0,a.yg)("inlineCode",{parentName:"a"},"GmsGraphQLEngine")),": ",(0,a.yg)("inlineCode",{parentName:"p"},'.dataFetcher("listOwnershipTypes", new ListOwnershipTypesResolver(this.entityClient))'),". This uses the ",(0,a.yg)("inlineCode",{parentName:"p"},"ListOwnershipTypes")," resolver to handle queries for ",(0,a.yg)("inlineCode",{parentName:"p"},"listOwnershipTypes")," endpoint.")),(0,a.yg)("h2",{id:"testing-your-change"},"Testing your change"),(0,a.yg)("p",null,"In addition to unit tests for your resolver mentioned above, GraphQL functionality in datahub can be tested using the built-in ",(0,a.yg)("a",{parentName:"p",href:"https://www.gatsbyjs.com/docs/how-to/querying-data/running-queries-with-graphiql/"},"GraphiQL")," endpoint. The endpoint is located at ",(0,a.yg)("inlineCode",{parentName:"p"},"localhost:8080/api/graphiql")," on Quickstart and at the equivalent URL for a production instance. This provides fast debug-ability for querying GraphQL. See ",(0,a.yg)("a",{parentName:"p",href:"/docs/1.1.0/api/graphql/how-to-set-up-graphql#graphql-explorer-graphiql"},"How to Set Up GraphQL")," for more information"))}g.isMDXComponent=!0}}]);