ballerina/graphql0.2.0-beta.2
Overview
This module provides APIs for connecting and interacting with GraphQL endpoints.
GraphQL is an open-source data query and manipulation language for APIs. GraphQL allows clients to define the structure of the data required and the same structure of the data is returned from the server preventing the returning of excessively large amounts of data.
The Ballerina GraphQL implementation is using HTTP as the underlying protocol.
Listener
The graphql:Listener
is used to listen to a given IP/Port. To create a graphql:Listener
, an http:Listener
or a port number can be used.
Create a Standalone graphql:Listener
1import ballerina/graphql;23listener graphql:Listener graphqlListener = new(4000);
Create a graphql:Listener
Using an http:Listener
1import ballerina/graphql;2import ballerina/http;34listener http:Listener httpListener = check new(4000);5listener graphql:Listener graphqlListener = new(httpListener);
Additional Configurations
When initializing the Ballerina GraphQL listener, a set of additional configurations can be provided to configure the listener including security and resiliency settings.
The configurations that can be passed for this are defined in the graphql:ListenerConfiguration
record.
1import ballrina/graphql;23listener graphql:Listener graphqlListener = new (4000, timeout = 10, secureSocket = { key: { path: <KEYSTORE_PATH>, password: <PASSWORD>}});
Service
The Ballerina GraphQL service represents the GraphQL schema. When a service is attached to a graphql:Listener
, a GraphQL schema will be auto-generated. The resource functions inside the service represent the resolvers of the root type.
Then, the GraphQL listener will handle all the incoming requests and dispatch them to the relevant resource function.
Since the GraphQL endpoints are exposed through a single endpoint, the endpoint URL of the GraphQL service can be provided after the service declaration as shown in the following code snippet in which the endpoint URL is /graphql
.
The accessor of the resource function should always be get
. The resource function name will become the name of the particular field in the GraphQL schema. The return type of the resource function will be the type of the corresponding field.
1import ballerina/graphql;23service graphql:Service /graphql on new graphql:Listener(4000) {4 resource function get greeting(string name) returns string {5 return "Hello, " + name;6 }7}
The above can be queried using the GraphQL document below:
1{2 greeting(name: "John")3}
The result will be the following JSON.
1{2 "data": {3 "greeting": "Hello, John"4 }5}
Additional Configurations
Additional configurations of a Ballerina GraphQL service can be provided using the graphql:ServiceConfig
.
These configurations include security-related configurations for the GraphQL service.
Security Configurations
A GraphQL service can be secured by setting auth
field in the graphql:ServiceConfig
. Ballerina GraphQL services supports Basic Authentication, JWT Authentication and OAuth2 Authentication.
1@graphql:SeviceConfig {2 auth: [3 {4 oauth2IntrospectionConfig: {5 url: <auth_introspection_url>,6 tokenTypeHint: <access_token>,7 scopeKey: <scope_key>,8 clientConfig: {9 secureSocket: {10 cert: {11 path: <truststore_path>,12 password: <password>13 }14 }15 }16 },17 scopes: [<comma_separated_list_of_scopes>]18 }19 ]20}21service graphql:Service /graphql on new graphql:Listener(4000) {22 // Service definition23}
Maximum Query Depth
When a maximum query depth is provided, all the queries exceeding that limit will be rejected at the validation phase and will not be executed.
1import ballerina/graphql;23@graphql:ServiceConfig {4 maxQueryDepth: 25}6service graphql:Service /graphql on new graphql:Listener(9090) {7 // Service definition8}
The above service only accepts queries of less than 2 levels. For an example, consider the following document:
1query getData {2 book {3 author {4 books {5 author {6 books7 }8 }9 }10 }11}
The result for the above query is the following JSON:
1{2 "errors": [3 {4 "message": "Query \"getData\" has depth of 5, which exceeds max depth of 2",5 "locations": [6 {7 "line": 1,8 "column": 19 }10 ]11 }12 ]13}
Types
The Ballerina GraphQL resources can return the following types:
Return Types
Scalar types
The following Ballerina types are considered as Scalar types:
int
string
boolean
float
decimal
enum
1resource function get greeting() returns string {2 return "Hello, World";3}
This can be queried using the following document:
1{2 greeting3}
Result:
1{2 "data": {3 "greeting": "Hello, World"4 }5}
Record types
When a resource is returning a record type, each field of the record can be queried separately.
Each record type is mapped to a GraphQL OBJECT
type and the fields of the record type are mapped to the fields of the OBJECT
type.
1public type Person record {|2 string name;3 int age;4|};56resource function get profile() returns Person {7 return { name: "Walter White", age: 51 };8}
This will generate the following schema.
1type Query {2 profile: Person!3}45type Person {6 name: String!7 age: Int!8}
This can be queried using the following document:
1{2 profile {3 name4 age5 }6}
Result:
1{2 "data": {3 "profile": {4 "name": "Walter White",5 "age": 516 }7 }8}
Each field can be queried separately as shown in the following document:
1{2 profile {3 name4 }5}
Result:
1{2 "data": {3 "profile": {4 "name": "Walter White"5 }6 }7}
Service Objects
When a resource function returns a service object, the service type is mapped to a GraphQL OBJECT
type and the resource functions of the service type will be mapped as the fields of the OBJECT
.
When a service type is returned from a graphql:Service
, the returning service type should also follow the rules of the graphql:Service
explained above.
1import ballerina/graphql;23service graphql:Service /graphql on new graphql:Listener(4000) {4 resource function get profile() returns Person {5 return new("Walter White", 51);6 }7}89service class Person {10 private string name;11 private int age;1213 public function init(string name, int age) {14 self.name = name;15 self.age = age;16 }1718 resource function get name() returns string {19 return self.name;20 }2122 resource function get age() returns int {23 return self.age;24 }25}
This will generate the following schema:
1type Query {2 profile: Person!3}45type Person {6 name: String!7 age: Int!8}
This can be queried using the following document:
1query getProfile {2 profile {3 name4 }5}
The above will result in the following JSON:
1{2 "data": {3 "profile": {4 "name": "Walter White"5 }6 }7}
Arrays
A GraphQL resource can return an array of the types mentioned above. When a resource is returning an array, the result will be a JSON array.
1public type Person record {|2 string name;3 int age;4|};56resource function get people() returns Person[] {7 Person p1 = { name: "Walter White", age: 51 };8 Person p2 = { name: "James Moriarty", age: 45 };9 Person p3 = { name: "Tom Marvolo Riddle", age: 71 };10 return [p1, p2, p3];11}
This will generate the following schema:
1type Query {2 profile: [Person!]!3}45type Person {6 name: String!7 age: Int!8}
This can be queried using the following document:
1{2 people {3 name4 }5}
Result:
1{2 "data": {3 "people": [4 {5 "name": "Walter White"6 },7 {8 "name": "James Moriarty"9 },10 {11 "name": "Tom Marvolo Riddle"12 }13 ]14 }15}
Note: Each element in the array consists only of the required name
field.
Optional Types
A Ballerina GraphQL resource can return an optional type. When the return value is ()
, the resulting field in the JSON will be null
.
1public type Person record {|2 string name;3 int age;4|};56resource function get profile(int id) returns Person? {7 if (id == 1) {8 return { name: "Walter White", age: 51 };9 }10}
This will generate the following schema:
1type Query {2 profile: Person3}45type Person {6 name: String!7 age: Int!8}
This can be queried using the following document:
1{2 profile(id: 1) {3 name4 }5}
Result:
1{2 "data": {3 "profile": {4 "name": "Walter White"5 }6 }7}
If the following document is used:
1{2 profile(id: 4) {3 name4 }5}
This will be the result:
1{2 "data": {3 "profile": null4 }5}
Union Types
The Ballerina GraphQL service can return a union of distinct service types. This will be mapped to a GraphQL UNION
type.
Since Ballerina supports the union types by nature, directly returning a union type is also allowed (but not recommended). The recommended way is to define a union type name separately and then use that type name as shown in the following example. If a union type is returned directly without providing a type name, the type name will be T1|T2|T3|...|Tn
.
1import ballerina/graphql;23public type StudentOrTeacher Student|Teacher;45service /graphql on new graphql:Listener(4000) {6 resource function get profile(int purity) returns StudentOrTeacher {7 if (purity < 90) {8 return new Student(1, "Jesse Pinkman");9 } else {10 return new Teacher(737, "Walter White", "Chemistry");11 }12 }13}1415distinct service class Student {16 private int id;17 private string name;1819 public function init(int id, string name) {20 self.id = id;21 self.name = name;22 }2324 resource function get id() returns int {25 return self.id;26 }2728 resource function get name() returns string {29 return self.name;30 }31}3233distinct service class Teacher {34 private int id;35 private string name;36 private string subject;3738 public function init(int id, string name, string subject) {39 self.id = id;40 self.name = name;41 self.subject = subject;42 }4344 resource function get id() returns int {45 return self.id;46 }4748 resource function get name() returns string {49 return self.name;50 }5152 resource function get subject() returns string {53 return self.subject;54 }55}
This will generate the following schema:
1type Query {2 profile(purity: Int!): StudentOrTeacher!3}45type Student {6 id: Int!7 name: String!8}910type Teacher {11 id: Int!12 name: String!13 subject: String!14}1516union StudentOrTeacher Student|Teacher
This can be queried using the following document:
1query {2 profile(purity: 75) {3 ... on Student {4 name5 }6 ... on Teacher {7 name8 subject9 }10 }11}
The result will be:
1{2 "data": {3 "profile": {4 "name": "Jesse Pinkman"5 }6 }7}
If the following document is used:
1query {2 profile(purity: 99) {3 ... on Student {4 name5 }6 ... on Teacher {7 name8 subject9 }10 }11}
The result will be:
1{2 "data": {3 "profile": {4 "name": "Walter White",5 "subject": "Chemistry"6 }7 }8}
Errors (With union)
A Ballerina GraphQL resource can return an error
with the union of the types mentioned above.
Note: A resource cannot return an error
, any subtype of an error
, or, an error?
, which will result in a compilation error.
1public type Person record {|2 string name;3 int age;4|};56resource function get profile(int id) returns Person|error {7 if (id == 1) {8 return { name: "Walter White", age: 51 };9 } else {10 return error(string `Invalid ID provided: ${id}`);11 }12}
This can be queried using the following document:
1{2 profile(id: 5) {3 name4 }5}
Result:
1{2 "errors": [3 {4 "message": "Invalid ID provided: 5",5 "locations": [6 {7 "line": 2,8 "column": 49 }10 ]11 }12 ]13}
Hierarchical Resource Paths
A resource inside a GraphQL service can have hierarchical paths.
When a hierarchical path is present, each level of the hierarchical path maps to the GraphQL field of the same name, and the type of that field will be mapped to an OBJECT
type with the same name.
1import ballerina/graphql;23service graphql:Service /graphql on new graphq:Listener(4000) {4 resource function profile/name/first() returns string {5 return "Walter";6 }78 resource function profile/name/last() returns string {9 return "White"10 }1112 resource function profile/age() returns int {13 return 51;14 }15}
The above service will create the following schema:
1type Query {2 profile: profile!3}45type profile {6 name: name!7 age: Int!8}910type name {11 first: String!12 last: String!13}
Note: The field name, and the type names are equal.
Listeners
[1]
Listener | Represents a Graphql listener endpoint. |
Object types
[1]
Service | Represents a GraphQL service. |
Records
[13]
FileUserStoreConfig | Represents file user store configurations for Basic Auth authentication. |
FileUserStoreConfigWithScopes | Represents the auth annotation for file user store configurations with scopes. |
GraphqlServiceConfig | Provides a set of configurations for the GraphQL service. |
JwtValidatorConfig | Represents JWT validator configurations for JWT authentication. |
JwtValidatorConfigWithScopes | Represents the auth annotation for JWT validator configurations with scopes. |
LdapUserStoreConfig | Represents LDAP user store configurations for Basic Auth authentication. |
LdapUserStoreConfigWithScopes | Represents the auth annotation for LDAP user store configurations with scopes. |
ListenerConfiguration | Provides a set of configurations for configure the underlying HTTP listener of the GraphQL listener. |
ListenerHttp1Settings | Provides settings related to HTTP/1.x protocol, when using HTTP 1.x as the underlying protocol for the GraphQL service. |
ListenerSecureSocket | Configures the SSL/TLS options to be used for the underlying HTTP service used in GraphQL service. |
OAuth2IntrospectionConfig | Represents OAuth2 introspection server configurations for OAuth2 authentication. |
OAuth2IntrospectionConfigWithScopes | Represents the auth annotation for OAuth2 introspection server configurations with scopes. |
RequestLimitConfigs | Provides inbound request URI, total header and entity body size threshold configurations. |
Annotations
[1]
ServiceConfig | The annotation to configure a GraphQL service. |
Types
[2]
ListenerAuthConfig | Defines the authentication configurations for the GraphQL listener. |
Scalar | Represents the Scalar types supported by the Ballerina GraphQL module. |
Errors
[1]
Error | Represents any error related to the Ballerina GraphQL module. |