Back to Examples
- Binding patterns
- Typed binding pattern
- Wildcard binding pattern
- List binding patterns
- Rest binding pattern in list binding pattern
- Mapping binding pattern
- Rest binding pattern in mapping binding pattern
- Error binding pattern
- Rest binding pattern in error binding pattern
- Single use of typed binding patterns
- Single use of typed binding patterns with on fail clause
- Iterative use of typed binding patterns
- List binding pattern in match statement
- Mapping binding pattern in match statement
- Error binding pattern in match statement
- Query expressions
- Sort iterable objects
- Let clause
- Limit clause
- Join iterable objects
- Outer Join clause
- Query tables
- Create tables with a query
- Create maps with a query
- Create streams with a query
- On conflict clause
- Advanced conflict handling
- Iterate over XML with a query
- Nested query expressions
- Destructure records using a query
- Querying streams
- Aggregation
- JSON type
- Access JSON elements
- Access optional JSON elements
- Match statement with maps
- Convert from user-defined type to JSON
- Convert from table and XML to JSON
- Convert from JSON to user-defined type
- Cast JSON to user-defined type
- Resource method typing
- JSON numbers
- JSON to record
- JSON to record with projection
- JSONPath expressions
- Asynchronous function calls
- Named workers
- Sequence diagrams
- Wait for workers
- Strands
- Named worker return values
- Alternate wait
- Multiple wait
- Named workers and futures
- Inter-worker message passing
- Alternate receive
- Multiple receive
- Conditional send
- Inter-worker failure propagation
- Named worker with on fail clause
- Synchronize message passing
- Asynchronize message passing
- Flush
- Fork
GraphQL service - Context object
The Ballerina graphql
module allows defining and using a graphql:Context
object. The contextInit
field in the graphql:ServiceConfig
annotation can be used to pass the context initialization function. If it is not provided, a default, empty context
object will be created per request. When the graphql:Context
is needed to be accessed, define it as a parameter of the resource
/remote
method. Use the graphql:Context
to pass meta information between the resource
/remote
methods used as GraphQL object fields.
Hint: The
graphql:Context
is defined before the other parameters of a function as a convention.
Note: If the
graphql:Context
is defined as a parameter of a resolver function, it will be accessible inside the resolver. Passing it down is not necessary.
import ballerina/graphql;
import ballerina/http;
@graphql:ServiceConfig {
// Initialization of the `graphqlContext` should be provided to the `contextInit` field.
contextInit
}
service /graphql on new graphql:Listener(9090) {
// Defines a `Profile` field inside the service.
private final Profile profile;
function init() {
// Initializes the `profile` value.
self.profile = new ("Walter White", 51, 737000.00);
}
// If the context is needed, it should be defined as a parameter of the resolver function.
resource function get profile(graphql:Context context) returns Profile|error {
// The profile information will be returned only if the scope is `admin` or `user`.
check validateScope(context, ["admin", "user"]);
return self.profile;
}
}
// Defines a service class to use as an object in the GraphQL service.
service class Profile {
private final string name;
private final int age;
private final float salary;
function init(string name, int age, float salary) {
self.name = name;
self.age = age;
self.salary = salary;
}
resource function get name() returns string => self.name;
resource function get age() returns int => self.age;
// If the context is needed, it should just be specified as a parameter of the resolver method.
// Ballerina handles propagating the context, and therefore, it is not required to be passed
// as an argument to the `init` method from the parent resolver.
resource function get salary(graphql:Context context) returns float|error {
// The salary information will be returned only if the scope is `admin`.
check validateScope(context, ["admin"]);
return self.salary;
}
}
isolated function validateScope(graphql:Context context, string[] allowedScopes) returns error? {
// Retrieves the `scope` attribute from the context. This will return a `graphql:Error` if
// the `scope` is not found in the context.
final string scope = check context.get("scope").ensureType();
// If the scope doesn't matches any of the allowed scopes return an `error`.
if !allowedScopes.some(allowedScope => scope == allowedScope) {
// Returns an `error` if the required scope is not found.
return error("Permission denied");
}
}
isolated function contextInit(http:RequestContext requestContext, http:Request request) returns graphql:Context|error {
// Initialize the `graphql:Context` object.
graphql:Context context = new;
// Retrieves the header named `scope` from the `http:request` and set it to the context with
// the `scope` key. If the header does not exist, this will return an `error`, and thereby,
// the request will not be processed.
context.set("scope", check request.getHeader("scope"));
// Finally, the context object should be returned.
return context;
}
Run the service by executing the following command.
$ bal run graphql_context.bal
Send the following document to the GraphQL endpoint to test the service.
{
profile {
name
salary
}
}
To send the document, execute the following cURL command in a separate terminal. First, send the request with the scope
header value set to admin
.
$ curl -X POST -H "Content-type: application/json" -H "scope: admin" -d '{ "query": "{ profile { name salary } }" }' 'http://localhost:9090/graphql'{"data":{"profile":{"name":"Walter White", "salary":737000.0}}}
Now, send the same document with the scope
header value set to unknown
. This will return an error in the profile
field.
$ curl -X POST -H "Content-type: application/json" -H "scope: unknown" -d '{ "query": "{ profile { name salary } }" }' 'http://localhost:9090/graphql'{"errors":[{"message":"Permission denied", "locations":[{"line":1, "column":3}], "path":["profile"]}], "data":null}
Tip: You can invoke the above service via the GraphQL client.