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. The similarity between Ballerina and GraphQL syntax enhances the development experience. Ballerina is an ideal choice for developers looking to build reliable, efficient, and intuitive GraphQL APIs.

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 built-in GraphQL API designer, a visual tool made available via the Ballerina VS Code plugin. Easily design and prototype GraphQL APIs for a smooth development experience. Use this visual tool to understand and explain your GraphQL services better.

Built-in designer tool for GraphQL

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

Discover the Ballerina GraphQL CLI tool. Easily generate custom GraphQL clients from schemas and access endpoints. Create and share Ballerina GraphQL service schemas to streamline collaboration and development workflows.

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

Better security

Ballerina offers robust security features like encryption, authentication, and authorization, essential for businesses handling sensitive data. It also ensures query integrity with depth validation and complexity analysis.

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,
    queryComplexityConfig: {
        // Limit the complexity of the query being executed.
        maxComplexity: 50
    }
}
service /graphql on graphqlListener {

    @graphql:ResourceConfig {
        // Define complexity for the field.
        complexity: 10
    }
    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