GraphQL's flexibility, efficient data fetching, reduced network traffic, versioning capabilities, backend aggregation, and improved developer experience make it a powerful choice for implementing the Backend for Frontend architecture, providing enhanced performance and simplified data management for frontend applications.

Ballerina is an excellent choice for GraphQL due to its GraphQL-friendly abstractions. Choose Ballerina as your go-to language for building robust and scalable GraphQL APIs.

Download Ballerina

Ballerina vs. Apollo

Ballerina is GraphQL - GraphQL is Ballerina

Ballerina, a strongly-typed language, is perfectly suited for GraphQL's declarative data fetching. With compile-time error handling, Ballerina ensures reliability and efficiency, making it an excellent choice for building robust and user-friendly GraphQL APIs. Ballerina is the perfect choice for developers who want to build reliable, efficient, and easy-to-use GraphQL APIs. The similarities between the Ballerina and GraphQL syntax are astonishing.

Object types: Using Ballerina record types is very much similar to GraphQL object definitions.
GraphQL
type Profile {
   name: String!
   age: Int!
}
Ballerina
type Person record {|
   string name;
   int age;
|};
Nullability: Ballerina supports nullable types similar to GraphQL.
GraphQL
type Profile {
   name: String
}
Ballerina
type Person record {|
   string? name;
|};
Union types: Ballerina supports union types similar to GraphQL union types.
GraphQL
union SearchResult = Human | Droid
Ballerina
type SearchResult Human|Droid;
Default values: Ballerina has in-built default value support, similar to GraphQL.
GraphQL
greeting(name: String! = "Anonymous"): String!
Ballerina
resource function get greeting(string name = "Anonymous") returns string;

Clean and simple code

Ballerina provides a simple and clean way to write GraphQL services with fewer lines of code compared to Apollo. Its concise syntax and built-in features allow streamlined development, resulting in more efficient and maintainable GraphQL services. Ballerina's focus on simplicity helps developers achieve their goals with ease and clarity.

Apollo

import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';

const typeDefs = `#graphql
    type Book {
        title: String
        author: String
    }

    type Query {
        books: [Book]
    }
`;

const books = [
    {
        title: 'Harry Potter',
        author: 'J. K. Rowling',
    },
    {
        title: 'The Lord of the Rings',
        author: 'J. R. R. Tolkien',
    },
];

const resolvers = {
    Query: {
        books: () => books,
    },
};

const server = new ApolloServer({
    typeDefs,
    resolvers,
});

await startStandaloneServer(server, {
    listen: { port: 4000 },
});

Ballerina

import ballerina/graphql;

type Book record {|
    string title;
    string author;
|};

Book[] books = [
    {
        title: "Harry Potter",
        author: "J. K. Rowling"
    },
    {
        title: "The Lord of the Rings",
        author: "J. R. R. Tolkien"
    }
];

service on new graphql:Listener(9090) {
    resource function get books() returns Book[] => books;
}
import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';

const typeDefs = `#graphql
    type Book {
        title: String
        author: String
    }

    type Query {
        books: [Book]
    }
`;

const books = [
    {
        title: 'Harry Potter',
        author: 'J. K. Rowling',
    },
    {
        title: 'The Lord of the Rings',
        author: 'J. R. R. Tolkien',
    },
];

const resolvers = {
    Query: {
        books: () => books,
    },
};

const server = new ApolloServer({
    typeDefs,
    resolvers,
});

await startStandaloneServer(server, {
    listen: { port: 4000 },
});
import ballerina/graphql;

type Book record {|
    string title;
    string author;
|};

Book[] books = [
    {
        title: "Harry Potter",
        author: "J. K. Rowling"
    },
    {
        title: "The Lord of the Rings",
        author: "J. R. R. Tolkien"
    }
];

service on new graphql:Listener(9090) {
    resource function get books() returns Book[] => books;
}

Seamlessly generate schema from code

Ballerina GraphQL simplifies the life of developers by generating the GraphQL schema directly from the Ballerina code. With this automatic schema generation, developers can focus on writing code, streamlining development, and ensuring consistency between the schema and the code. It offers convenience, efficiency, and ease of use in building GraphQL services with Ballerina.

Ballerina code

import ballerina/graphql;

service on new graphql:Listener(9090) {
    resource function get profile() returns Profile {
        return {
            name: "John Doe",
            age: 30,
            address: {street: "15 Yemen Road", city: "Yemen", country: "YM"}
        };
    }
}

type Profile record {|
    string name;
    int age;
    Address address;
|};

type Address record {|
    string street;
    string city;
    string country;
|};

Generated schema

type Query {
   profile: Profile!
}

type Profile {
   name: String!
   age: Int!
   address: Address!
}

type Address {
   street: String!
   city: String!
   country: String!
}
import ballerina/graphql;

service on new graphql:Listener(9090) {
    resource function get profile() returns Profile {
        return {
            name: "John Doe",
            age: 30,
            address: {street: "15 Yemen Road", city: "Yemen", country: "YM"}
        };
    }
}

type Profile record {|
    string name;
    int age;
    Address address;
|};

type Address record {|
    string street;
    string city;
    string country;
|};
type Query {
   profile: Profile!
}

type Profile {
   name: String!
   age: Int!
   address: Address!
}

type Address {
   street: String!
   city: String!
   country: String!
}

Out-of-the-box subscription support - No additional libraries are needed

Ballerina offers seamless support for GraphQL subscriptions out-of-the-box, eliminating the need for additional libraries like with Apollo. With Ballerina, you can effortlessly integrate systems like Apache Kafka into your GraphQL subscriptions, enhancing real-time data streaming capabilities. This simplifies development, reduces dependencies, and provides a comprehensive solution for building robust GraphQL subscription-based applications.

Apollo

import { ApolloServer } from '@apollo/server';
import { expressMiddleware } from '@apollo/server/express4';
import { ApolloServerPluginDrainHttpServer } from '@apollo/server/plugin/drainHttpServer';
import { createServer } from 'http';
import express from 'express';
import { makeExecutableSchema } from '@graphql-tools/schema';
import { WebSocketServer } from 'ws';
import { useServer } from 'graphql-ws/lib/use/ws';
import bodyParser from 'body-parser';
import cors from 'cors';
import resolvers from './resolvers';
import typeDefs from './typeDefs';

const schema = makeExecutableSchema({ typeDefs, resolvers });
const app = express();
const httpServer = createServer(app);

const wsServer = new WebSocketServer({
    server: httpServer,
    path: '/graphql',
});
const serverCleanup = useServer({ schema }, wsServer);

const server = new ApolloServer({
    schema,
    plugins: [
        ApolloServerPluginDrainHttpServer({ httpServer }),
        {
            async serverWillStart() {
                return {
                    async drainServer() {
                        await serverCleanup.dispose();
                    },
                };
            },
        },
    ],
});

await server.start();
app.use('/graphql', cors<cors.CorsRequest>(), bodyParser.json(), expressMiddleware(server));

const PORT = 4000;
httpServer.listen(PORT, () => {
    console.log(`Server is now running on http://localhost:${PORT}/graphql`);
});

Ballerina

import ballerina/graphql;
import ballerina/uuid;

service on new graphql:Listener(9090) {
    resource function get greeting() returns string {
        return "Welcome";
    }

    remote function publishMessage(NewPost newPost) returns string|error {
        check publishPost(postData);
        return new (postData);
    }

    resource function subscribe messages() returns stream<Post, error?>|error {
        string id = uuid:createType1AsString();
        PostStreamGenerator postStreamGenerator = check new (id);
        stream<Post, error?> postStream = new (postStreamGenerator);
        return postStream;
    }
}
import { ApolloServer } from '@apollo/server';
import { expressMiddleware } from '@apollo/server/express4';
import { ApolloServerPluginDrainHttpServer } from '@apollo/server/plugin/drainHttpServer';
import { createServer } from 'http';
import express from 'express';
import { makeExecutableSchema } from '@graphql-tools/schema';
import { WebSocketServer } from 'ws';
import { useServer } from 'graphql-ws/lib/use/ws';
import bodyParser from 'body-parser';
import cors from 'cors';
import resolvers from './resolvers';
import typeDefs from './typeDefs';

const schema = makeExecutableSchema({ typeDefs, resolvers });
const app = express();
const httpServer = createServer(app);

const wsServer = new WebSocketServer({
    server: httpServer,
    path: '/graphql',
});
const serverCleanup = useServer({ schema }, wsServer);

const server = new ApolloServer({
    schema,
    plugins: [
        ApolloServerPluginDrainHttpServer({ httpServer }),
        {
            async serverWillStart() {
                return {
                    async drainServer() {
                        await serverCleanup.dispose();
                    },
                };
            },
        },
    ],
});

await server.start();
app.use('/graphql', cors<cors.CorsRequest>(), bodyParser.json(), expressMiddleware(server));

const PORT = 4000;
httpServer.listen(PORT, () => {
    console.log(`Server is now running on http://localhost:${PORT}/graphql`);
});
import ballerina/graphql;
import ballerina/uuid;

service on new graphql:Listener(9090) {
    resource function get greeting() returns string {
        return "Welcome";
    }

    remote function publishMessage(NewPost newPost) returns string|error {
        check publishPost(postData);
        return new (postData);
    }

    resource function subscribe messages() returns stream<Post, error?>|error {
        string id = uuid:createType1AsString();
        PostStreamGenerator postStreamGenerator = check new (id);
        stream<Post, error?> postStream = new (postStreamGenerator);
        return postStream;
    }
}

Built-in designer tool for GraphQL

Explore the boundless possibilities with the in-built GraphQL API designer, a visual tool of the Ballerina VS Code plugin. Effortlessly design and prototype GraphQL APIs, unlocking a seamless and intuitive development experience. Empower your GraphQL services with this exceptional visual designer tool.

Built-in designer tool for GraphQL

GraphQL CLI tool - An all-in-one tool for GraphQL

Experience the exhilaration of the Ballerina GraphQL CLI tool. Effortlessly generate custom GraphQL clients from schemas, accessing endpoints with ease. Seamlessly generate and share Ballerina GraphQL service schemas, facilitating collaboration and empowering efficient development workflows.

GraphQL CLI tool - An all-in-one tool for GraphQL

Better security

Ballerina provides robust security features such as encryption, authentication, and authorization, which are essential for businesses dealing with sensitive data.

listener graphql:Listener graphqlListener = new (9090,
    secureSocket = {
        key: {
            certFile: "../resource/path/to/public.crt",
            keyFile: "../resource/path/to/private.key"
        }
    }
);

@graphql:ServiceConfig {
    auth: [
        {
            oauth2IntrospectionConfig: {
                url: "https://mytoken.endpoint/oauth2/introspect",
                tokenTypeHint: "access_token",
                scopeKey: "scp",
                clientConfig: {
                    customHeaders: {"Authorization": "Basic YWRtaW46YWRtaW4="},
                    secureSocket: {
                        cert: "../resource/path/to/public.crt"
                    }
                }
            },
            scopes: ["admin"]
        }
    ],
    // Validate the query depth
    maxQueryDepth: 5
}
service /graphql on graphqlListener {
    resource function get users() returns User[] {
        // ...
    }
    remote function createPost(graphql:Context context, NewPost newPost) returns Post|error {
        // ...
    }
}

public type NewPost readonly & record {|
    // Validate user inputs
    @constraint:String {
        maxLength: 25,
        minLength: 5
    }
    string title;
|};

Your typical Git-based workflow: edit, debug, and test in VS Code

Ballerina provides built-in editing, debugging, and testing tools making it easier for developers to test, debug, deploy, and optimize their automation workflows.

Your typical Git-based workflow: edit, debug, and test in VS Code

Diagram when you need it, Code when you don't

Ballerina diagrams provide great creativity and flexibility in the early stages of development, allowing developers to visualize and iterate on their ideas quickly. However, developers can easily switch to writing code when delivering a more polished product by taking advantage of Ballerina's powerful language features.

Diagram when you need it, Code when you don't

Connect with anything

Access thousands of connectors for HTTP APIs (OpenAPI), event APIs (AsyncAPI), GraphQL services, legacy systems, and data stores, allowing seamless data transfer to and from any system, anywhere.

configurable string token = ?;

service /graphql on new graphql:Listener(9090) {
    final github:Client githubClient;

    function init() returns error? {
        self.githubClient = check new ({auth: {token}});
    }

    resource function get repositories() returns Repository[]|error {
        stream<Repository, github:Error?> repositories = 
            check self.githubClient->getRepositories();
        return from github:Repository repository in repositories
            select repository;
    }

    remote function createIssue(CreateIssueInput createIssueInput, 
            string owner, string repositoryName) returns github:Issue|error {
        Issue issue = 
            check self.githubClient->createIssue(createIssueInput, owner, repositoryName);
        check produceIssue(issue, repositoryName);
        return issue;
    }

    resource function subscribe issues(string repositoryName) returns stream<Issue>|error {
        IssueStream issueStreamGenerator = check new (repositoryName);
        return new (issueStreamGenerator);
    }
}

Community-driven development

Ballerina is a community-driven open-source project with contributions from developers around the world. This means that developers have access to a rich ecosystem of libraries, tools, and resources that can enhance their automation workflows.

Community-driven development

(Extra!) Trivial hosting in WSO2 Choreo

Manual integrations? Scheduled integrations (cron jobs)? Triggered integrations? Integrations as APIs? No problem! Write the code, attach the repo to WSO2 Choreo, and let it do the rest.

(Extra!) Trivial hosting in WSO2 Choreo