How to create GraphQL schema dynamically?
Tags: graphql, java, beginners, opensource
Published: 2020-06-16 10:27:12

Hey everyone. 🤩 I am writing this article to guide you through to a create a dynamic GraphQL schema programmatically as java code. We would be primarily using the `graphql-java` library for this.

### GraphQL Schema 
GraphQL has its type system that’s used to define the schema of an API. The syntax for writing schemas is called Schema Definition Language (SDL). We can either define the schema using SDL or define it programmatically as java code. But both of them are static ways of representation. In case you are building schema during runtime, it becomes difficult to recursively add new fields to your predefined definition.

#### SDL Schema Definition
```
type Customer {
   name : String
   address : String
   contact : Int 
}
```
#### Programmatic Schema Definition
```
GraphQLObjectType.Builder graphQLObjectType = GraphQLObjectType.newObject();
graphQLObjectType.name("Customer")
                 .field(newFieldDefinition()
                       .name("name")
                       .type(Scalars.GraphQLString))
                 .field(newFieldDefinition()
                       .name("address")
                       .type(Scalars.GraphQLString))
                 .field(newFieldDefinition()
                       .name("conatct")
                       .type(Scalars.GraphQLInt)
                 .build();
```

We will be focusing on how to extract the metadata of the data source to which you are connecting. Metadata characterizes your data and makes easier for anyone to understand and consume it. To put it simply, metadata is the data describing the data that is being stored in your data source. It generally includes the name, size and number of rows of each table present in a database, along with the columns in each table, their data types, precisions, etc. 

*Let's get started!* :rocket:

To read and store database meta data  we will be using two interfaces `DatabaseMetaData` and `ResultSet`.The DatabaseMetaData interface is huge, containing hundreds of methods for reading capabilities of a DBMS. You can refer to [Javadoc](https://docs.oracle.com/javase/8/docs/api/java/sql/DatabaseMetaData.html) for the complete list of methods.

#### Obtaining DatabaseMetaData Instance

Here I am using jdbc-url for `Teiid`, you can choose others too. We obtain the `DatabaseMetaData` object from a `Connection` object, like this: 
```
String URL = "jdbc:teiid:customer@mm://localhost:31000";
String USERNAME = "sa";
String PASSWORD = "sa";
Connection connection = DriverManager.getConnection(URL, USERNAME ,PASSWORD );
DatabaseMetaData databaseMetaData = connection.getMetaData();
```

#### Listing Database Tables

We can obtain a list of the defined tables in your database or data source with the help of DatabaseMetaData. Here is how that is done: 
```
String table[] = {"TABLE"};

ResultSet resultSet = databaseMetaData.getTables(null,null,null,table);
ArrayList<String> tables = new ArrayList();

    while(resultSet.next()) {
        tables.add(resultSet.getString("TABLE_NAME"));
    }
``` 
#### Listing Database Columns

We can obtain the columns of a table via the DatabaseMetaData object in this manner : 
```
ResultSet columns = databaseMetaData.getColumns(null,null, tableName, null);
     while(columns.next()) {
         String columnName = columns.getString("COLUMN_NAME");
         String datatype = columns.getString("DATA_TYPE");
         String columnsize = columns.getString("COLUMN_SIZE");
    
         System.out.println(columnName + "---" + datatype + "---" + columnsize);
      }
```
#### Creating Schema 

Next step would be to create a schema using `GraphQLObjectType` object, store it's corresponding metadata in HashMap and read it's type from `ReturnType` class defined in the next section.
```
ResultSet resultSet = databaseMetaData.getColumns(null, null, (String) tableName, null);

     GraphQLObjectType objectType = null;
     GraphQLObjectType.Builder graphQLObjectType = GraphQLObjectType.newObject();

     System.out.println("-------Schema for Table " + tableName + "-------");
     HashMap <String,String> data  = new HashMap<>();

      while (resultSet.next()) {
           data.put(resultSet.getString("COLUMN_NAME"), resultSet.getString("TYPE_NAME"));

           for (Map.Entry<String, String> hm : data.entrySet()) {

                graphQLObjectType
                        .name(tableName)
                        .field(GraphQLFieldDefinition.newFieldDefinition()
                                .name(hm.getKey())
                                .type(ReturnType(hm.getValue())));
                objectType = graphQLObjectType.build();

            }
        }
```
#### Defining the Field Type in Schema

This class returns the type of field in each case, here I have defined only two types `GraphQLLong` and `GraphQLString`. You can define accordingly for other types.
```
public static GraphQLScalarType ReturnType(String type) {
      if(type.equals("long"))
           return Scalars.GraphQLLong;
      else if (type.equals("string"))
           return Scalars.GraphQLString;
      return null;
    }
}
```
#### Building and Printing Schema

To print schema is a defined manner we are using `SchemaPrinter` object which takes an object of GraphQLSchema type.
```
GraphQLSchema graphQLSchema = GraphQLSchema.newSchema()
                    .query(objectType)
                    .build();

SchemaPrinter schemaPrinter = new SchemaPrinter();
String printer = schemaPrinter.print(graphQLSchema);
System.out.println(printer);
```

### Conclusion 
There you have it! You have successfully connected to your data source to fetch database metadata and using the data you constructed  your graphQL schema. 

You can visit the Github Repo [Schema Builder](https://github.com/ani-sha/schemabuilder) to view the source code. Also check [GraphQL Java](https://www.graphql-java.com/) website to learn more. 

You're learning. I'm learning. We're all learning. Let's continue to learn and get better together. Thank you. Happy Reading! 🎉

You can connect with me on [Twitter](https://twitter.com/anisha__mohanty) and [LinkedIn](https://www.linkedin.com/in/anisha-mohanty-97a7a7169/) :heart: