GraphQL is a query language for APIs that provides a type system to describe the data model in a structured way. It provides a strongly typed schema to describe the data model of an API in a structured way. Additionally, clients of an API use the query language to describe the data they want to request. GraphQL is similar to OData because they both provide a structured, typed schema for APIs and also enable clients to write powerful queries to request exactly the data they need using a single request.
The GraphQL adapter builds on the same metadata as the OData adapter.
To keep things simple, we will be using the Graph sandbox endpoint. All you need to use this endpoint is your favorite GraphQL tool, for example the Altair GraphQL client, and your API key from SAP API Hub. To retrieve your API key, log into SAP API Business Hub, go to settings and copy your API key from the Show API Key button.
To make requests against the Graph sandbox, add your API key as an HTTP header in your requests: apiKey: <your API key>. Then you can use the Graph sandbox through the following endpoint:
https://sandbox.api.sap.com/sapgraph/graphql
Usually, GraphQL requests are done using POST requests. But, the sandbox is limited to GET requests, so we need to do GET requests for this tutorial. For most GraphQL clients this is just a setting and we are not creating too large request. A productive Graph instance is able to receive POST requests.
The API key is just used for the purposes of this sandbox endpoint and not relevant in the context of requests to productive Graph instances.
Also note that the URL of the Graph sandbox differs from the a productive URL of Graph.
Every GraphQL service defines a schema that completely describes the set of types you can use for querying that service. GraphQL allows asking about what queries it supports using the introspection system.
Most GraphQL clients automatically load and scan the complete schema automatically, so you might not need to do that on your own and use the client to explore the schema.
To see what types are available, you can query the __schema field:
{
__schema {
types {
name
}
}
}
This will return all service specific and build-in types of the service:
{
"data": {
"__schema": {
"types": [
{
"name": "Query"
},
{
"name": "sap_c4c"
},
{
"name": "sap_c4c_BusinessAttributeCollection_connection"
},
{
"name": "sap_c4c_BusinessAttributeCollection"
}
...
]
}
}
}
To get more information for a specific type, you can either extend the query above or do a separate query for the __type field. If you introspect the Query with
{
__type(name: "Query"){
name
fields {
name
}
}
}
you get all namespaces. These include Graph's build-in namespaces as well as user-defined custom namespaces for custom entities.
{
"data": {
"__type": {
"name": "Query",
"fields": [
{ "name": "sap_c4c" },
{ "name": "sap_graph" },
{ "name": "sap_hcm" },
{ "name": "sap_s4 "}
]
}
}
}
You can use a similar query to get the list of entities in a namespace, by using the namespace instead "Query" as the name.
To get more information in a single request, you can extend the query, for example to get all fields of sap_graph_SalesQuote with their name and kind, you simply query this:
{
__type(name: "sap_graph_SalesQuote"){
name
fields {
name
type {
name
kind
}
}
}
}
returning all available properties of the sap_graph_SalesQuote:
{
"data": {
"__type": {
"name": "sap_graph_SalesQuote",
"fields": [
{"name": "id", "type": {"name": "String", "kind": "SCALAR"}},
{"name": "createdAt", "type": {"name": "DateTime", "kind": "SCALAR"}},
{"name": "changedAt", "type": {"name": "DateTime", "kind": "SCALAR"}},
{"name": "displayId", "type": {"name": "String", "kind": "SCALAR"}},
{"name": "netAmount", "type": {"name": "Decimal", "kind": "SCALAR"}},
{"name": "quoteType", "type": {"name": "String", "kind": "SCALAR"}},
{"name": "soldToParty", "type": {"name": "String", "kind": "SCALAR"}},
{"name": "_soldToParty", "type": {"name": "sap_graph_SalesDocumentReason", "kind": "OBJECT"}},
{"name": "_soldToParty_id", "type": {"name": "String", "kind": "SCALAR"}},
{"name": "items", "type": {"name": "sap_graph_SalesQuote_items_connection", "kind": "OBJECT"}},
...
]
}
}
}
We can see that a SalesQuote has several properties of different types, such as String or Decimal, but also more complex structured types like the items property, which is a collection of several sap_graph_SalesQuote_items, that are also defined in the same data model. The _connection types allow for retrieving data of entities of a to-many relation.
{
"data": {
"__type": {
"name": "sap_graph_SalesQuote_items_connection",
"fields": [
{"name": "nodes", "type": {"name": null, "kind": "LIST", "ofType": {"name": "sap_graph_SalesQuote_items"}}},
{"name": "totalCount", "type": {"name": "Int", "kind": "SCALAR", "ofType": null}}
]
}
}
}
Let us look at an example. We want to get a SalesQuote. For that, we create the following GraphQL request:
{
sap_graph {
SalesQuote (top: 1){
nodes {
id
displayId
netAmount
}
}
}
}
In GraphQL, you always specify exactly what fields you would like to receive. In the example request above we selected the id, displayId and the netAmount of the SalesQuote. To make the query fast and have an easy to read result, we have added (top: 1) to get only one SalesQuote.
{
"data": {
"sap_graph": {
"SalesQuote": {
"nodes": [
{
"id": "c4c~1",
"displayId": "1",
"netAmount": "890"
}
]
}
}
}
}
We now want to get the items and the soldToParty of that SalesQuote as well, so we simply add these attributes to the query with the fields we would like to see.
Note that the attributes of the items attribute are encapsulated with nodes like it is done with the attributes of the SalesQuote as well. This has to be done for all list types. _soldToParty is a to-one association, so here the attributes are directly. The reason for this extra level is so that you can get the total amount of elements next to the actual elements of the list like here for the SalesQuote:
{
sap_graph {
SalesQuote (top: 1){
totalCount
nodes {
id
displayId
netAmount
_soldToParty {
id
name
}
items {
nodes {
itemId
itemText
product
quantity
}
}
}
}
}
}
This will result in the items of the SalesQuote and the associated soldToParty being returned. The total count of found SalesQuotes is now available as well:
{
"data": {
"sap_graph": {
"SalesQuote": {
"totalCount": 135,
"nodes": [
{
"id": "c4c~1",
"displayId": "1",
"netAmount": "890",
"_soldToParty": {
"id": "c4c~10014",
"name": "System Tec"
},
"items": {
"nodes": [
{
"itemId": "10",
"itemText": "Green Emission Calculator",
"product": "P300100",
"quantity": "1"
}
]
}
}
]
}
}
}
}
When working with collections of entities, we typically want to filter the entities by some criteria or arrange them in a specific order. In Graph's GraphQL schema this is supported via the filter and order arguments.
Let us continue with our example above. Say, we want to retrieve all SalesQuotes with a value greater than 100 U.S. Dollars. The value condition can be formulated with the filter rule netAmount: {ge: 100}. For the currency condition we need to compare it with a string for equality: netAmountCurrency: {eq: "USD"}. Filter rules that are in one filter object are combined with logical conjunction (and). If you want to combine rules with logical disjunction (or), you would pass multiple filters as a list in the filter argument.
In addition, we define an ascending ordering on the netAmount property: orderBy: {netAmount: asc}.
With top and skip we can additionally define a sliding window over the result to implement pagination. top specifies how many result entities should be returned: the page size. How many result entities should be skipped from the beginning of the ordering is defined with the skip argument.
{
sap_graph {
SalesQuote (
top: 5,
skip: 5,
orderBy: {netAmount: asc},
filter: {
netAmount: {ge: 100},
netAmountCurrency: {eq: "USD"}
}
){
totalCount
nodes {
id
netAmount
netAmountCurrency
}
}
}
}
In this tutorial we had a look at using Graph with GraphQL. We covered all the features that you as a developer working with Graph need to know, like how to:
GraphQL itself offers much more than what we showed in this tutorial. You can read more about it in the the GraphQL documentation and the Graph documentation .
You as a developer now have a second data protocol option you can use with Graph. The structure of all entities in the business data graph is exactly the same as if you access Graph with the OData protocol. You have one API to retrieve data in one unified format, no matter the source system.
________________________________________________________________
Alexander Hoffert, Senior Developer – Graph
Visit Graph on the SAP Community
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
29 | |
13 | |
13 | |
10 | |
9 | |
9 | |
9 | |
8 | |
8 | |
7 |