Web apps and mobile apps are the face of digital organizations. Therefore, back-ends powering these apps need to be highly secure, scalable, and responsive. In addition, such back-ends need to aggregate data from multiple services, transform data as necessary, and transmit those to front-ends over required protocols.

Ballerina's support for various protocols, availability of connectors, built-in security features, and advanced data transformation capabilities make it the ideal choice for developing back-ends for modern front-ends.

Download Ballerina

BFF

Simplify back-end development with native REST features

Ballerina provides REST features like path/query parameters, HTTP headers, status codes, and complex JSON structures as first-class citizens within the language itself.

service /sales on new http:Listener(9090) {

    resource function get orders() returns Order[] {
        return orders.toArray();
    };

    resource function get orders/[string id]() returns Order|http:NotFound {
        return orders[id] ?: <http:NotFound>{
            body: string `Order not found. Order ID: ${id}`
        };
    };

    resource function post orders(Order orderRequest)
            returns Order|http:BadRequest {
        if orders.hasKey(orderRequest.id) {
            return <http:BadRequest>{
                body: string `Order id already exists.`
            };
        }
        orders.add(orderRequest);
        return orderRequest;
    }
}
Rest-API

Streamline back-end data handling

Ballerina has built-in support for multi-part payloads, constraint validations, transformations, and, enrichments for working with complex payloads.

service /crm on new http:Listener(9090) {
    
    resource function get customers/[string customerId]/agreement() 
            returns byte[]|http:InternalServerError {
        byte[]|error agreementForm = getAgreementForm(customerId);
        if agreementForm is error {
            return http:INTERNAL_SERVER_ERROR;
        }
        return agreementForm;
    }

    resource function post customers(http:Request request) 
                returns http:Created|http:InternalServerError {
        do {
            mime:Entity[] bodyParts = check request.getBodyParts();
            string formData = check bodyParts[0].getText();
            CustomerData data = check formData.fromJsonStringWithType();
            byte[] image = check bodyParts[1].getByteArray();
            byte[] agreemntForm = check bodyParts[2].getByteArray();
            check registerCustomer(data, agreemntForm, image);
            return http:CREATED;
        } on fail {
            return http:INTERNAL_SERVER_ERROR;
        }
    }
}
Advanced Payload Validation

Validate payload constraints in web back-ends

Ballerina's inherent JSON capabilities enable the direct mapping of JSON data into Ballerina records, incorporating functionalities such as constraint validations.

type Order record {|
    readonly string id;
    @constraint:String {
        pattern: {
            value: re `C-[0-9]{3}`,
            message: "Customer id should be in the format C-XXX"
        }
    }
    string customerId;
    string? shipId;
    string date;
    OrderStatus status;
    @constraint:Int {
        minValue: {value: 1, message: "Quantity should be greater than one"},
        maxValue: {value: 10, message: "Quantity should not exceed 10"}
    }
    int quantity;
    string item;
|};

service /sales on new http:Listener(9090) {
    resource function post orders(Order orderRequest)
            returns Order|http:BadRequest {
        if orders.hasKey(orderRequest.id) {
            return <http:BadRequest>{
                body: string `Order id already exists.`
            };
        }
        orders.add(orderRequest);
        return orderRequest;
    }
}
Advanced Payload Validation

Efficiently expose complex data with GraphQL

With Ballerina's built-in GraphQL functionality, developers can simply expose Ballerina records via GraphQL services, facilitating querying and selectively fetching complex data structures.

type Order record {|
    readonly string id;
    string customerId;
    string? shipId;
    Address? shippingAddress;
    string date;
    OrderStatus status;
    int quantity;
    string item;
|};

type Address record {|
    string number;
    string street;
    string city;
    string state;
|};

service /sales on new graphql:Listener(9090) {
    resource function get orders(string? customerId) returns Order[] {
        if customerId is () {
            return orders.toArray();
        }
        return from Order entry in orders
            where entry.customerId == customerId
            select entry;
    }
}
GraphQl

Expose real-time data to front-ends via webSockets

Ballerina allows real-time data to be streamed just by implementing a service. This comes with enterprise-ready security features like TLS, mutual TLS, and OAuth2.

service /logistics on new websocket:Listener(9091) {
    resource function get vehicles/[string vehicleId]() 
                            returns websocket:Service {
        return new LocationService(vehicleId);
    }
}

distinct service class LocationService {
    *websocket:Service;

    remote function onOpen(websocket:Caller caller) returns error? {
        // Create a new strand and allocate it to send the locations
        _ = start self.routeLocationFromServerToClient(caller, self.vehicleId);
        return;
    }

    function routeLocationFromServerToClient(
            websocket:Caller caller, string vehicleId) returns error? {
        while true {
            Location currentLocation = {
                latitude: check random:createIntInRange(668700, 1246700) * 1.0 
                                        / 10000.0,
                longitude: check random:createIntInRange(258400, 493800) * 1.0 
                                        / 10000.0
            };
            check caller->writeMessage(currentLocation);
            runtime:sleep(3);
        }
    }
}
Websockets

Simplify user authentications and authorizations

Ballerina apps can be seamlessly integrated with any OAuth2-compatible identity provider using a simple set of annotations.

@http:ServiceConfig {
    auth: [
        {
            jwtValidatorConfig: {
                issuer: issuer,
                audience: audience,
                signatureConfig: {
                    jwksConfig: {
                        url: jwksUrl
                    }
                }
            },
            scopes: ["order_insert", "order_read", "cargo_insert", "cargo_read"]
        }
    ]
}
service /sales on new http:Listener(9090) {
    @http:ResourceConfig {
        auth: {
            scopes: ["order_insert"]
        }
    }
    resource function post orders(Order orders) returns http:Ok {
        orderTable.add(orders);
        return <http:Ok>{body: {message: "Order submitted successfully"}};
    };
}
Auth & AuthZ

Comprehensive security for web back-ends

Ballerina-based back-ends can simplify securing sensitive data during transit, validating server identity, managing CORS, and enforcing message type restrictions via annotations.

@http:ServiceConfig {
    cors: {
        allowOrigins: ["http://localhost:3000", "http://www.hmart.com"],
        allowHeaders: ["REQUEST_ID"],
        exposeHeaders: ["RESPONSE_ID"],
        maxAge: 84900
    }
}
service /sales on new http:Listener(9090,
    secureSocket = {
        key: {
            certFile: "../path/to/cert",
            keyFile: "../path/to/private-key"
        }
    }
) {
    @http:ResourceConfig {
        cors: {
            allowOrigins: ["http://localhost:3000", "http://www.hmart.com"],
            allowCredentials: true
        }
    }
    resource function post orders(Order orderEntry) returns http:Ok {
        orderTable.add(orderEntry);
        return <http:Ok>{body: {message: "Order submitted successfully"}};
    };
}
Comprehensive-Security

Securely interact with internal/external services

Ballerina back-ends can securely call services with the necessary security features such as client-side OAuth2, mutual TLS, and JWT-encapsulated user data.

service /logistics on new http:Listener(9090) {
    resource function post cargos(Cargo cargo) 
            returns http:Ok|http:InternalServerError {
        cargoTable.add(cargo);
        http:Client serviceClient = getServiceClient(cargo.cargoType);
        http:Response|error res = serviceClient->post("/shipments", cargo);
        if res is http:Response && res.statusCode == 202 {
            return <http:Ok>{body: "Successfully submitted the shipment"};
        }
        return <http:InternalServerError>{
            body: {message: "Error occurred while submitting the shipment"}
        };
    };

    resource function get cargos() returns Cargo[] {
        return cargoTable.toArray();
    };
}
Internal/External services

Automate data access with Ballerina

Ballerina's persistence features offer a straightforward way to create a data access layer for any complex application by providing a simplified interface for CRUD operations.

Client dbClient = check new ();

service /sales on new http:Listener(9090) {
    resource function get orders() returns Order[]|error {
        return from Order entry in orderDatabase->/orders(Order)
            select entry;
    };

    resource function post orders(Order orderEntry)
            returns http:Ok|http:InternalServerError|http:BadRequest {
        orderEntry.cargoId = getCargoId();
        string[]|persist:Error result = orderDatabase->/orders.post([orderEntry]);
        if result is string[] {
            return http:OK;
        } 
        if result is persist:ConstraintViolationError {
            return <http:BadRequest>{
                body: {message: string `Invalid cargo id: ${orderEntry.cargoId}`}
            };
        }
        return http:INTERNAL_SERVER_ERROR;
    };
}
Persist Support

Develop flexible & scalable back-ends

Ballerina-based back-ends offer the flexibility to manage varying loads. Components can be deployed and scaled independently, providing flexibility and scalability, particularly on platforms like Kubernetes.

In addition, Ballerina back-ends can be instantly taken to production by deploying in Choreo, a comprehensive app development platform with pre-built CI/CD pipelines, multi-environment support, and robust monitoring for Ballerina apps.

Develop flexible & scalable back-ends