Building a GraphQL Service to Expose Data in a SQL Database

Videos

 

GraphQL Building a Service In this video we show how you can build a GraphQL API to expose data in a SQL database.

Watch Video
GraphQL Testing your Service Once you have defined a GraphQL API you can use the built-in tester to test your GraphQL API.

Watch Video
GraphQL Testing your Service - Using Variables You can use variables in your query parameters rather than using hard coded literal values.

Watch Video
GraphQL Testing your Service - Getting Multiple Records You can use a GetMany query to return multiple records. When you return multiple records, you can specify a page size, number of records to skip over etc.

Watch Video
GraphQL Paginated Queries When you use a GetMany query, you can do paginated queries.

Watch Video
GraphQL Update Mutations Using an Update mutation you can perform Updates on any of the tables exposed in the API.

Watch Video
GraphQL Add Mutations Using an Add mutation  you can add records to a table.

Watch Video
GraphQL Delete  Mutations Using a Delete mutation you can delete  records to a table.

Watch Video
GraphQL Executing a GraphQL Query Directly from the Browser When you execute a GraphQL query, you can either do the query in server-side code or client-side code.

In this video we show how you can make a request to a GraphQL endpoint directly from the browser and then populate a List control with the data returned by the query.

Watch Video

 

 

Creating a GraphQL API

GraphQL has become a very popular approach for defining APIs. Unlike REST APIs, which have multiple endpoints, a GraphQL API exposes a single endpoint that allows many different types of queries and mutations (a mutation is a method that changes data). Alpha Anywhere has a built-in genie that makes creating a GraphQL service (i.e. API) to expose data in a SQL database extremely easy.

 

Enabling the GraphQL Service Builder

GraphQL is not yet released as an official part of Alpha Anywhere. You can get access to the GraphQL features by entering the following feature key: FPb76c8988ab834b.

From the Web Control Panel, select the Tools, Feature Packs command and then enter the feature key.

 

How to Create a GraphQL API

Alpha Anywhere has a built-in genie that automatically generates a GraphQL API that can be used to query a SQL database, perform CRUD operations against tables in a SQL database, execute custom mutations (i.e. call custom function defined in Xbasic classes or Node APIs that you write).

To create a GraphQL API select the Web Services category in the Web Control Panel.

 

 

Then click the New button.

 

 

This will display the New Service Type dialog.

 

 

Click the Create a new definition to create a GraphQL service button. This will open the builder.

 

 

 

The GraphQL service builder assumes you will be creating a service to expose data in a SQL database. Therefore, you must specify the connection string to your SQL database. You will then be able to select which tables in your SQL database you want to expose in your service.

Click the Change Connection String.. hyperlink and select a connection string.

Next, click the Pick Tables... hyperlink. The Select Tables to Expose dialog will be shown.

 

 

 

 

 

Pick the tables that you want your service to expose. The genie will automatically detect relationships between tables. For example, if you select a connection string for the sample Northwind database, the builder will automatically infer that there is a one-to-many relationship between the Customers and Orders tables, between the Orders and Orders Details table and so on. The builder will also be able to automatically infer that that there is a one-to-one relationship between the Order Details and the Products table, etc.

Custom Views

In addition to exposing the physical tables in your database you can also expose views (virtual tables) by clicking the Add a Custom View hyperlink. A custom view lets you define which columns to expose and what WHERE clause to apply. You can also specify if you want DISTINCT records. (When executing a GraphQL query against a Custom View, the user will be able to apply additional filter parameters - in addition to the WHERE clause defined for the Custom View.)

NOTE Another way in which to limit the columns you expose from a particular table is to modify the schema that Alpha Anywhere generates after you click the Save button to close the Database GraphQL Service window.

Click the Create button button to define the Custom View and return to the Database GraphQL Service window.

 

Once you are back at the Database GraphQL Service window, click the Save button when you are done and give your service a name. Alpha Anywhere will then automatically generate a schema for your service.

 

A sample of the Schema is shown below (in abbreviated form to save space):

 

Notice that for each table you selected, the schema specifies which type of CRUD operations are allowed, and it specifies which fields from the table are exposed. In addition, each table may have a children property which specifies the one-to-many tables that are linked to the table and a join property which specifies the one-to-one tables that are linked to the table.

			
			{
    "connection": "::Name::sqlserver_northwind",
    "tables": [
        {
            "name": "Customers",
            "actualname": "Customers",
            "query": true,
            "insert": true,
            "update": true,
            "delete": true,
            "first": true,
            "cursor": true,
            "skip": true,
            "totalCount": true,
            "orderBy": true,
            "fields": [
                {
                    "name": "CustomerID",
                    "type": "String"
                },
                {
                    "name": "CompanyName",
                    "type": "String"
                },
                {
                    "name": "ContactName",
                    "type": "String"
                },
                more fields.....,
                {
                    "name": "cursor",
                    "expression": "CustomerID",
                    "type": "String"
                }
            ],
            "children": [
                {
                    "name": "Orders",
                    "parent": "CustomerID",
                    "child": "CustomerID"
                }
            ]
        },
        {
            "name": "Employees",
            "actualname": "Employees",
            "query": true,
            "insert": true,
            "update": true,
            "delete": true,
            "first": true,
            "cursor": true,
            "skip": true,
            "totalCount": true,
            "orderBy": true,
            "fields": [
                {
                    "name": "EmployeeID",
                    "type": "Double"
                },
                {
                    "name": "LastName",
                    "type": "String"
                },
                {
                    "name": "FirstName",
                    "type": "String"
                },
		more fields....

                {
                    "name": "cursor",
                    "expression": "EmployeeID",
                    "type": "String"
                }
            ],
            "children": [
                {
                    "name": "Employees",
                    "parent": "EmployeeID",
                    "child": "ReportsTo"
                },
                {
                    "name": "Orders",
                    "parent": "EmployeeID",
                    "child": "EmployeeID"
                }
            ]
        },
        {
            "name": "OrderDetails",
            "actualname": "Order Details",
            "query": true,
            "insert": true,
            "update": true,
            "delete": true,
            "first": true,
            "cursor": true,
            "skip": true,
            "totalCount": true,
            "orderBy": true,
            "fields": [
                {
                    "name": "OrderID",
                    "type": "Double"
                },
                {
                    "name": "ProductID",
                    "type": "Double"
                },
                more fields...
                {
                    "name": "cursor",
                    "expression": "OrderID+ProductID",
                    "type": "Double"
                }
            ],
            "join": [
                {
                    "name": "Orders",
                    "parent": "OrderID",
                    "child": "OrderID"
                },
                {
                    "name": "Products",
                    "parent": "ProductID",
                    "child": "ProductID"
                }
            ]
        },
        {
            "name": "Orders",
            "actualname": "Orders",
            "query": true,
            "insert": true,
            "update": true,
            "delete": true,
            "first": true,
            "cursor": true,
            "skip": true,
            "totalCount": true,
            "orderBy": true,
            "fields": [
                {
                    "name": "OrderID",
                    "type": "Double"
                },
                {
                    "name": "CustomerID",
                    "type": "String"
                },
                {
                    "name": "EmployeeID",
                    "type": "Double"
                },
                more fields...
                {
                    "name": "cursor",
                    "expression": "OrderID",
                    "type": "String"
                }
            ],
            "children": [
                {
                    "name": "OrderDetails",
                    "parent": "OrderID",
                    "child": "OrderID"
                }
            ],
            "join": [
                {
                    "name": "Customers",
                    "parent": "CustomerID",
                    "child": "CustomerID"
                },
                {
                    "name": "Employees",
                    "parent": "EmployeeID",
                    "child": "EmployeeID"
                }
            ]
        },
        {
            "name": "Products",
            "actualname": "Products",
            "query": true,
            "insert": true,
            "update": true,
            "delete": true,
            "first": true,
            "cursor": true,
            "skip": true,
            "totalCount": true,
            "orderBy": true,
            "fields": [
                {
                    "name": "ProductID",
                    "type": "Double"
                },
                {
                    "name": "ProductName",
                    "type": "String"
                },
                more fields...
                {
                    "name": "cursor",
                    "expression": "ProductID",
                    "type": "Boolean"
                }
            ],
            "children": [
                {
                    "name": "OrderDetails",
                    "parent": "ProductID",
                    "child": "ProductID"
                }
            ],
            "join": [
                {
                    "name": "Suppliers",
                    "parent": "SupplierID",
                    "child": "SupplierID"
                }
            ]
        }
	more tables...

    ]
}
			

 

 

Testing Your GraphQL API

Right click on the service in the Web Control Panel and select the Test API with GraphIQL. GraphIQL is a graphical GraphQL query tester.

You can either perform the testing using Working Preview mode (Development Server does not need to be running) or Live mode (Development server must be running and service will be published to the Live Preview folder).

 

 

If you select the  Working Preview mode, a dialog will open shown the GraphIQL tester.

 

If you select Live mode, the browser will open, showing the GraphIQL tester page and your GraphQL API definition will be loaded.

The Document Explorer panel will be shown on the right where you can explore the Queries and Mutations defined in your GraphQL Service.

NOTE If you do not see the Document Explorer panel, click the Docs button in the toolbar.

 

 

 

 

Enter a GraphQL query and then click the Run button to execute your query.

GraphQL syntax is described in many articles you can read on-line.

Assuming you have build a service that exposes the Customers, Orders, Order Details and Products table from the sample Northwind database, here are some example queries and the corresponding data return by the query.

 

Query 1 - A simple query that only returns fields from the Customer table. The query uses the GetCustomer query and it specifies the Id (CustomerID: BONAP) of the customer to fetch.

			{
  GetCustomer(CustomerID: BONAP) {
    CustomerID
    ContactName
    City
    Country
  }
}

Result of Query 1

{
  "data": {
    "GetCustomer": {
      "CustomerID": "BONAP",
      "ContactName": "Laurence Lebihan",
      "City": "Marseille",
      "Country": "France"
    }
  }
}

 

Query 2 - Builds on Query 1, but includes data from the child Orders table. The OrderID and OrderData fields from the Orders table are retrieved

{
  GetCustomer(CustomerID: BONAP) {
    CustomerID
    ContactName
    City
    Country
    Orders{
      OrderID
      OrderDate
    }
  }
}

Result of Query 2


{
  "data": {
    "GetCustomer": {
      "CustomerID": "BONAP",
      "ContactName": "Laurence Lebihan",
      "City": "Marseille",
      "Country": "France",
      "Orders": [
        {
          "OrderID": 10331,
          "OrderDate": "1994-11-16 00:00:00"
        },
        {
          "OrderID": 10340,
          "OrderDate": "1994-11-29 00:00:00"
        },
        {
          "OrderID": 10362,
          "OrderDate": "1994-12-26 00:00:00"
        },
        {
          "OrderID": 10470,
          "OrderDate": "1995-04-11 00:00:00"
        },
        .......truncated

 

 

Query 3 - Builds on Query 2, but includes data from the Order Details table (which is aliased as OrderDetails). OrderDetails is a child table of the Orders table.

 

{
  GetCustomer(CustomerID: BONAP) {
    CustomerID
    ContactName
    City
    Country
    Orders{
      OrderID
      OrderDate
      OrderDetails{
        ProductID
        Quantity
        UnitPrice
        Products_ProductName
      }
    }
  }
}
			
			

Result of Query 3

			
			{
  "data": {
    "GetCustomer": {
      "CustomerID": "BONAP",
      "ContactName": "Laurence Lebihan",
      "City": "Marseille",
      "Country": "France",
      "Orders": [
        {
          "OrderID": 10331,
          "OrderDate": "1994-11-16 00:00:00",
          "OrderDetails": [
            {
              "ProductID": 54,
              "Quantity": 15,
              "UnitPrice": 5.9,
              "Products_ProductName": "Tourtière"
            }
          ]
        },
        {
          "OrderID": 10340,
          "OrderDate": "1994-11-29 00:00:00",
          "OrderDetails": [
            {
              "ProductID": 18,
              "Quantity": 20,
              "UnitPrice": 50,
              "Products_ProductName": "Carnarvon Tigers"
            },
            {
              "ProductID": 41,
              "Quantity": 12,
              "UnitPrice": 7.7,
              "Products_ProductName": "Jack's New England Clam Chowder"
            },
            {
              "ProductID": 43,
              "Quantity": 40,
              "UnitPrice": 36.8,
              "Products_ProductName": "Ipoh Coffee"
            }
          ]
        },
			

 

 

 

Using Variables in a Query

You can use variables, rather than hard coded literal values in your CraphQL queries.  For example in the above samples, the CustomerID parameter is hard coded as BONAP.

 

To use a variable, define your variables in QUERY VARIABLES section in the GraphIQL builder.

 

Query Variables are defined using a JSON syntax. For example:

 

{

    "customerId": "BOLID",

    "city": "London"

}

 

To consume a query variable in the query definition, use the variable name with a $ prefix. For example:

 

			
{
  GetCustomer(CustomerID: $customerId) {
    CustomerID
    ContactName
    City
    Country
  }
}

 

 

Using Aliases

You can define an alias for any of the property names in the query result. For example in the sample Query 3 above, the Product Name is called  Products_ProductName in the query result. You might want to change this to (say) ProductName. To do this you specify an alias in the query definition. To specify an alias for a property name, prefix the property name with aliasName: . For example:

{
  GetCustomer(CustomerID: BONAP) {
    CustomerID
    ContactName
    City
    Country
    Orders{
      OrderID
      OrderDate
      OrderDetails{
        ProductID
        Quantity
        UnitPrice
        ProductName:Products_ProductName
      }
    }
  }
}
			
		

 

Getting Multiple Records

In the previous examples we have executed queries that returned a single record. The Alpha Anywhere genie also generates queries to return multiple records. For example, the genie generates these queries for the Customer table: GetCustomer and GetManyCustomers.

When executing a GetMany* query (e.g. GetManyCustomers, GetManyOrders, etc.), you can optionally specify that you want to return a "page" of records (by specifying a "page size" parameter -- called first. You can also specify a cursor property to indicate at which record you want to start, and a skip property which indicates how many records you want to skip - after the record with the specified cursor) . For example, to return the first page of records where the Country field is "USA" and the page size is 3 records, you would define this query shown below:

Notice that the fields to be returned by the query are specified in an object called records. Your query definition can also include a property called pageInfo, which returns information about the pages in the query result, specifically if there are more pages of data

{
  GetManyCustomers( country: usa, first: 3, skip: 0  ){
    records{
      CustomerID
      City
      ContactName
      Cursor
    }
    pageInfo{
      hasNextPage
      
    }
  }
}			
			
			

Here is the result of this query:


{
  "data": {
    "GetManyCustomers": {
      "records": [
        {
          "CustomerID": "GREAL",
          "City": "Eugene",
          "ContactName": "Howard Snyder",
          "cursor": "eyJjdXJzb3IiOiJHUkVBTCJ9"
        },
        {
          "CustomerID": "HUNGC",
          "City": "Elgin",
          "ContactName": "Yoshi Latimer",
          "cursor": "eyJjdXJzb3IiOiJIVU5HQyJ9"
        },
        {
          "CustomerID": "LAZYK",
          "City": "Walla Walla",
          "ContactName": "John Steel",
          "cursor": "eyJjdXJzb3IiOiJMQVpZSyJ9"
        }
      ],
      "pageInfo": {
        "hasNextPage": true
      }
    }
  }
}

 

Notice that in the query result pageInfo.hasNextPage property we can see that  there are more pages of data. To get the second page of data we include the cursor property in the query parameters and we set the skip property to 1.  (If we did not set the skip property to 1 then the last record in the previous query would become the first record in this query).

 

Here is the query to get the second page of records:


{
  GetManyCustomers( country: usa, first: 3, skip: 1 cursor: "eyJjdXJzb3IiOiJMQVpZSyJ9" ){
    records{
      CustomerID
      City
      ContactName
      Cursor
    }
    pageInfo{
      hasNextPage
      
    }
  }
}

Calling a Mutation

By default the GraphQL genie will automatically create mutations to update, insert, and delete records in each of the tables in your API definition.

In the next example, we show how to do an update on the Customers table.

mutation {
  UpdateCustomer(
	where: {CustomerID: bolid}, 
	set: {City: Madrid}
) {
    CustomerID
    CompanyName
    ContactName
    ContactTitle
    City
    Country
  }
}			
			
			

 

The syntax for the mutation includes a where clause with values for certain fields (in the above example, the record for CustomerID = BOLID will be updated) and a set clause that contains a comma delimited list of fields and corresponding values. You can use arguments in both the where clause and the set clause. You can also optionally specify fields to be returned after he update is completed. In the above example, after the update is performed, the query returns data for the CustomerID, CompanyName, ContactTitle, City and Country fields.

In addition to the automatically created mutations (such as the UpdateCustomer mutation shown above), you can also create custom mutations (using either Xbasic or NodeJS). This is discussed below.

 

This mutation will update multiple records (because the Set clause specified city = London and there are multiple matching records):

 

mutation {
  UpdateCustomer(where: {city: london}, set: {ContactTitle: Apprentice}) {
    CustomerID
    CompanyName
    ContactName
    ContactTitle
    City
    Country
  }
}
			

Here is a mutation to insert a new record:

 

mutation {
  AddCustomer(CustomerID: ABCD, ContactName: Jim Smith, CompanyName: Alpha Software) {
    CustomerID
    CompanyName
  }
}			
			

Notice that the inserted record has set three field values and after the insert is completed, the query returns the value in the CustomerID field and the CompanyName field.

In this case, the table primary key (CustomerID) is not an auto-increment field (and it is explicitly set when the new record is added). But in many cases the primary key will be an auto-increment field and you will want to  know what the primary key of the inserted record is. By specifying the primary key field in the list of fields returned by the query, you can get the value of the primary key.

 

Required Fields

When you define a GraphQL API to perform CRUD operations on a SQL table, you can mark certain fields in your definition as required fields (i.e. non nullable). For example in the sample definition show earlier, we indicated that the Categories table exposed certain fields. If we want to indicate that the CategoryName field is a required field (so that when you use the AddCategories mutation you will be required to specify a value for this field, change the definition for the CategoryName field to use an ! character after the type name. For example:

 

 


{
    "name": "CategoryName",
    "type": "String!"

}

 

Reporting Errors

When you execute a mutation, by default errors are not reported unless you add a directive to your GraphQL definition.

For example, say we want the mutations that operate on the Categories table to report errors. You would need to add a new property to the definition. You can add the "nativeErrors" or "errors" property to the definition (set the property value to true or false). The nativeErrors property will report errors returned by the SQL database. The errors property will return error reported to Xbasic.

For example:

"totalCount": true,
"orderBy": true,
"nativeErrors": true,

....

 

 

To see the errors in the query result add the __error column to the query result specification.

You can easily set or unset the error properties for all tables in your GraphQL service definition by clicking on the Runtime Error Settings hyperlink the the builder.

 

This will open a builder when you can select the error setting.

 

 

How to Create Custom Mutations

Alpha Anywhere automatically adds mutations to perform update, insert and delete operations for all of the tables you select when you define the service (unless you set the corresponding query, update, insert or delete property to false in the service definition). You may also want your GraphQL service to define custom mutations -- that you write using either Xbasic or Node.

To add custom mutations to your GraphQL API create a new Xbasic class or Node API. Your Xbasic class definition or Node API will include one or more methods. Your GraphQL API will expose all of the methods defined in the Xbasic class or Node API.

In the walkthrough that follows we will define a custom mutation (called parseNameXB based on a method in an Xbasic class) that will take a string of the form:

firstname lastname,streetNumber streetName,city state zip

and will return and object with these properties:

firstname

lastname

address

    streetNumber

    streetName

    citystatezip

        city

        state

        zip

 

We will then show a second custom mutation (called parseNameNode) that does the same thing, but this time based on a method defined in a Node API.

 

Here is a summary of the steps we will go through

Step 1 - Create an Xbasic class with a method called parseNameXB.

Step 2 - Test the method in the Interactive Window

Step 3 - Create a new GraphQL service and define a Custom Mutation using the Xbasic class you created.

Step 4 - Test the custom Mutation in the GraphIQL tester

 

Step 1 - Create an Xbasic class

At the Web Projects Control panel, select the Xbasic category. Click the New button and create a new Xbasic Class. Enter the following code in the editor:

 

define class customMutations::class1
	function parseNamexb as customMutations::name (fullnameandaddress as c)
		dim text as c = fullnameandaddress
		dim line1 as c 
		dim line2 as c
		dim line3 as c 
		text = comma_to_crlf(text)
		line1 = alltrim(word(text,1, crlf()))
		line2 = alltrim(word(text,2, crlf()))
		line3 = alltrim(word(text,3, crlf()))
		if w_count(line1," ") = 2 then 
			dim fname as c  = word(line1,1," ")
			dim lname as c = word(line1,2," ")
		else 'account for possible middle initial
			dim fname as c  = word(line1,1," ")
			dim lname as c = word(line1,-1," ")
		end if 
		dim streetNumber as c  = word(line2,1," ")
		dim street as c
		street = alltrim(stritran(line2,streetNumber,"")) 'remove streetnumber from line2
		dim zip as c = word(line3,-1," ")
		dim state as c = word(line3,-2," ",1)
		dim city as c = alltrim(stritran(line3,zip,"")) 'remove zip from line3
		city = alltrim(stritran(city,state,"")) 'remove state from city

		dim address as customMutations::address
		dim citystatezip as customMutations::citystatezip 
		address.streetNumber = streetNumber
		address.street = street
		
		citystatezip.zip = zip 
		citystatezip.city = city 
		citystatezip.state = state 
		
		address.citystatezip = citystatezip
		parseNamexb.firstname = fname
		parseNamexb.lastname = lname
		parseNamexb.address = address 
	end function 
end class       	

define class customMutations::name 
	dim firstname as c 
	dim lastname as c 
	dim address as customMutations::address
end class

define class customMutations::citystatezip
	dim zip as c 
	dim state as c 
	dim city as c 
end class 

define class customMutations::address
	dim street as c 
	dim streetNumber as c 
	DIM citystatezip as customMutations::citystatezip
end class
			

Here are some key points about the code in the method definition:

 

 

 

When you are done entering the Xbasic class definitions, click the Save button on the toolbar. Alpha Anywhere will suggest a default file name, which you can accept.

 

To test the code in the mutation from the Interactive window, go to the Interactive window and enter these lines (pressing enter after you enter each line)

dim x as customMutations::class1
p = x.parseNamexb("fred smith, 123 main street,boston ma")
?json_generate(p)
= {
	"firstname": "fred",
	"lastname": "smith",
	"address": {
		"street": "main street",
		"streetNumber": "123",
		"citystatezip": {
			"zip": "ma",
			"state": "boston",
			"city": ""
		}
	}
}
			
			

Next you will need to add the custom mutation to your GraphQL service definition. Edit the service definition and then click on the User-defined mutations hyperlink at the bottom of the window.

 

 

This will open a dialog where you can specify the classes that define the methods you want to expose in your custom mutations:

 

Click the Select class hyperlink.

 

Click OK twice, then save the service definition.

 

 

To test the mutation in the GraphIQL tester, right click on the service name in the Web Control Panel and select the Test with GraphIQL command.

Enter this mutation:

mutation {
  parseNamexb(fullnameandaddress: "Fred Smith,123 Main St,Ithaca NY 12345") {
    firstname
    lastname
    address {
      street
      streetNumber
      citystatezip {
        city
        state
        zip
      }
    }
  }
}

When you run the query, you should see this result:

{
  "data": {
    "parseNamexb": {
      "firstname": "Fred",
      "lastname": "Smith",
      "address": {
        "street": "Main St",
        "streetNumber": "123",
        "citystatezip": {
          "city": "Ithaca",
          "state": "NY",
          "zip": "12345"
        }
      }
    }
  }
}			
			

 

 

Security

By default, the GraphQL API that you create is not authenticated. You can add authentication to your API by clicking on the Authorization hyperlink in the GraphQL Service builder.

 

 

This will open a dialog where you can specify the name of the method to call to authorize the user. You can use either Xbasic or Node to write the authorization method.

 

 

 

You can also specify if the arguments to the authentication method are supplied in the request header, or in the query string.

The authentication method should return an HTTP status code. For example if your method returns 200, the user is authorized. If your method returns 401, the user is denied permission to use the API.

For example, here is a Xbasic class that defines an authorize method that you can specify in the Authentication method dialog. This class must be defined in the Xbasic section of the Web Control Panel. The method authorizes the user if they specify a value of "alpha" for the apikey.

define class graphql::auth
    function authorize as n (apikey as c )
        if apikey = "alpha"
            authorize = 200
        else
            authorize = 401
        end if
    end function
end class
 

 

 

 

Creating a Test Page For Your GraphQL API

You might want your published application to include a page where users can test your GraphQL API (in the same way that you can test it at development time by right clicking on the service name in the Web Control Panel, and then selecting the Test API with GraphiQL command.

To create a page for testing your GraphQL service open the GraphQL service definition and click the Create GraphQL API test page hyperlink.

 

 

Xbasic Helper Functions

The following Xbasic helper functions are available:

 

a5wcb_graphQLQueryBuilder()

Syntax:

P result =  a5wcb_graphQLQueryBuilder(C websiteBaseURL ,C servicename [,C authorizationType [,C queryString [,C variablesJSON [,C authorizationVariable [,L flagShowWarningOnExit ]]]]])

Where

For example, assume you have defined a GraphQL service (called Northwind.a5svc) that exposes data from tables in the sample Northwind database.

To build a query, go to the Interactive window and type (pressing Enter after each line):

 

Dim P as p

p = a5wcb_graphQLQueryBuilder("[workingpreview]","northwind")

 

The GraphIQL tester will open in a window. You can enter a query definition and test it. When you are done, click the Save button in the bottom right corner.

To see the query string that you defined, enter:

showvar(p.query)

To see any query variables that you defined, enter

showvar(p.vars)

 




a5_graphQL_Execute()
Executes a GraphQL query against a GraphQL service defined in Alpha Anywhere.

Note: This function is not intended to execute against a 3rd party GraphQL service. To execute a query against a 3rd party GraphQL service use the Xbasic CURL object to make an HTTP POST request.

Syntax:

p result =  a5_graphQL_Execute as P (C serviceName as c, C queryString [, C headers [,C variables [, C queryParameters]]])

 

 

Where

 

Example:

Assume you have built a service called Northwind.a5svc in the current Web Project. Here is a script to execute a query against this service:

	
	
	dim servicename as c = "[demo]\northwind"
	dim queryString as c = <<%str%
	{
	  cust1: GetCustomer(CustomerID: $var1) {
	    CustomerID
	    ContactName
	    CompanyName
	    City
	    Country
	  }
	  cust2: GetCustomer(CustomerID: $var2) {
	    CustomerID
	    ContactName
	    CompanyName
	    City
	    Country
	    ContactTitle
	    Orders {
	      OrderID
	      OrderDate
	      OrderDetails {
	        ProductID
	        Quantity
	        UnitPrice
	        __typename
	      }
	    }
	  }
	 
	}
	
	%str%
	
	dim variables as c = <<%str%
	{
	    "var1": "blaus",
	    "var2": "bolid"
	}
	%str%
	
	
	
	dim p as p 
	t1 = now()
	p = a5_graphQL_Execute(servicename,queryString,"",variables)
	t2 = now()
	if p.error = .f. then 
		DIM _result as c = p.result
		_result = convert_utf8_to_acp(_result)
		showvar(_result)
	else
		showvar(p.errortext)
	end if 

Here is the result returned by this query:

			{
			    "data": {
			        "cust1": {
			            "CustomerID": "BLAUS",
			            "ContactName": "Hanna Moos",
			            "CompanyName": "Blauer See Delikatessen",
			            "City": "Mannheim",
			            "Country": "Germany"
			        },
			        "cust2": {
			            "CustomerID": "BOLID",
			            "ContactName": "Martín Sommer",
			            "CompanyName": "Bólido Comidas preparadas",
			            "City": "Madrid",
			            "Country": "Spain",
			            "ContactTitle": "Owner",
			            "Orders": [
			                {
			                    "OrderID": 10326,
			                    "OrderDate": "1996-10-10 00:00:00",
			                    "OrderDetails": [
			                        {
			                            "ProductID": 4,
			                            "Quantity": 24,
			                            "UnitPrice": 17.6,
			                            "__typename": "OrderDetail"
			                        },
			                        {
			                            "ProductID": 57,
			                            "Quantity": 16,
			                            "UnitPrice": 15.6,
			                            "__typename": "OrderDetail"
			                        },
			                        {
			                            "ProductID": 75,
			                            "Quantity": 50,
			                            "UnitPrice": 6.2,
			                            "__typename": "OrderDetail"
			                        }
			                    ]
			                },
			                {
			                    "OrderID": 10801,
			                    "OrderDate": "1997-12-29 00:00:00",
			                    "OrderDetails": [
			                        {
			                            "ProductID": 17,
			                            "Quantity": 40,
			                            "UnitPrice": 39,
			                            "__typename": "OrderDetail"
			                        },
			                        {
			                            "ProductID": 29,
			                            "Quantity": 20,
			                            "UnitPrice": 123.79,
			                            "__typename": "OrderDetail"
			                        }
			                    ]
			                },
			                {
			                    "OrderID": 10970,
			                    "OrderDate": "1998-03-24 00:00:00",
			                    "OrderDetails": [
			                        {
			                            "ProductID": 52,
			                            "Quantity": 40,
			                            "UnitPrice": 7,
			                            "__typename": "OrderDetail"
			                        }
			                    ]
			                }
			            ]
			        }
			    }
			}

			
			

 

 

 

Javascript Helper Functions

The a5_graphQL_Execute() function is an Xbasic function. This means that is must be used in server-side code. However, you can also execute queries against GraphQL services directly from the browser (bypassing the Alpha Anywhere server completely) using a function defined in the Alpha Anywhere Javascript library.

The {dialog.object}.graphQLQuery() method executes a GraphQL query.

The {dialog.object}.graphQLQueryPromise() method is a variant of the {dialog.object}.graphQLQuery() method, but instead of taking a callback function as an argument, it returns a promise.

Syntax:

{dialog.object}.graphQLQuery(url,querySefinition,variables,headers,queryParameters,onSuccess,onFail)

 

var promise = {dialog.object}.graphQLQueryPromise(url,querySefinition,variables,headers,queryParameters)

 

 

Where

 

Here is an example of a Javascript function that you might have on a button in a UX component to populate a List control with the results from a GraphQL query:

 

			var url = 'http://www.mygraphqlservice.com/northwind.a5svc';
			var query = `
			  {
				  GetManyCustomers {
				    records {
				      CustomerID
				      ContactName
				      CompanyName
				      City
				      Country
				    }
				  }
				}
			`
			
			{dialog.object}.graphQLQueryPromise(url,query,'','')
			.then(data => { 
				var j = JSON.parse(data);
				var lObj = {dialog.object}.getControl('list1')
				lObj.populate(j.data.GetManyCustomers.records)
			})