import ballerina/http;
import ballerina/mime;
import ballerina/io;
endpoint http:Client clientEP {
    targets:[{url:"http://localhost:9092"}]
};
endpoint http:Listener multipartEP {
    port:9090
};
@http:ServiceConfig {basePath:"/multiparts"}
service<http:Service> test bind multipartEP {
@http:ResourceConfig {
        methods:["GET"],
        path:"/decode_in_response"
    }
     receiveMultiparts (endpoint conn, http:Request request) {
        http:Request outRequest = new;
        http:Response inResponse = new;
        var returnResult = clientEP -> get("/multiparts/encode_out_response", outRequest);
        http:Response res = new;
        match returnResult {
            http:HttpConnectorError connectionErr => {
                res.statusCode = 500;
                res.setStringPayload("Connection error");
            }
            http:Response returnResponse => {
                match returnResponse.getMultiparts() {
                    mime:EntityError err => {
                        res.statusCode = 500;
                        res.setStringPayload(err.message);
                    }
                    mime:Entity[] parentParts => {
                        int i = 0;
                        while (i < lengthof parentParts) {
                            mime:Entity parentPart = parentParts[i];
                            handleNestedParts(parentPart);
                            i = i + 1;
                        }
                        res.setStringPayload("Body Parts Received!");
                    }
                }
            }
        }
        _ = conn -> respond(res);
    }
}
function handleNestedParts (mime:Entity parentPart) {
    string contentTypeOfParent = parentPart.contentType.toString();
    if (contentTypeOfParent.hasPrefix("multipart/")) {
        match parentPart.getBodyParts() {
            mime:EntityError err => {
                io:println("Error retrieving child parts!");
            }
            mime:Entity[] childParts => {
                int i = 0;
                io:println("Nested Parts Detected!");
                while (i < lengthof childParts) {
                    mime:Entity childPart = childParts[i];
                    handleContent(childPart);
                    i = i + 1;
                }
            }
        }
    }
}
function handleContent (mime:Entity bodyPart) {
    string contentType = bodyPart.contentType.toString();
    if (mime:APPLICATION_XML == contentType || mime:TEXT_XML == contentType) {
        var payload = bodyPart.getXml();
        match payload {
            mime:EntityError err => io:println("Error in getting xml payload");
            xml xmlContent => io:println(xmlContent);
        }
    } else if (mime:APPLICATION_JSON == contentType) {
        var payload = bodyPart.getJson();
        match payload {
            mime:EntityError err => io:println("Error in getting json payload");
            json jsonContent => io:println(jsonContent);
        }
    } else if (mime:TEXT_PLAIN == contentType) {
        var payload = bodyPart.getText();
        match payload {
            mime:EntityError err => io:println("Error in getting string payload");
            string textContent => io:println(textContent);
        }
    }
}

Inbound Response with Multiparts

Multipart response handling is supported by the Ballerina server connector. When you request multiparts from the HTTP inbound response, you get an array of body parts (An array of entities). If the received parts contain nested parts, you can loop through the parent parts and get the child parts as well.

import ballerina/http;
import ballerina/mime;
import ballerina/io;
endpoint http:Client clientEP {
    targets:[{url:"http://localhost:9092"}]
};

Creating an endpoint for the client.

endpoint http:Listener multipartEP {
    port:9090
};

Creating a listener for the service.

@http:ServiceConfig {basePath:"/multiparts"}
service<http:Service> test bind multipartEP {
@http:ResourceConfig {
        methods:["GET"],
        path:"/decode_in_response"
    }

Binding the listener to the service.

     receiveMultiparts (endpoint conn, http:Request request) {
        http:Request outRequest = new;
        http:Response inResponse = new;

This resource accepts multipart responses.

        var returnResult = clientEP -> get("/multiparts/encode_out_response", outRequest);
        http:Response res = new;
        match returnResult {

Extract the bodyparts from the response.

            http:HttpConnectorError connectionErr => {
                res.statusCode = 500;
                res.setStringPayload("Connection error");
            }
            http:Response returnResponse => {
                match returnResponse.getMultiparts() {
                    mime:EntityError err => {
                        res.statusCode = 500;
                        res.setStringPayload(err.message);
                    }
                    mime:Entity[] parentParts => {
                        int i = 0;

Setting the error response in-case of an error

                        while (i < lengthof parentParts) {
                            mime:Entity parentPart = parentParts[i];
                            handleNestedParts(parentPart);
                            i = i + 1;
                        }
                        res.setStringPayload("Body Parts Received!");
                    }
                }
            }
        }
        _ = conn -> respond(res);
    }
}

Loop through body parts.

function handleNestedParts (mime:Entity parentPart) {
    string contentTypeOfParent = parentPart.contentType.toString();
    if (contentTypeOfParent.hasPrefix("multipart/")) {
        match parentPart.getBodyParts() {
            mime:EntityError err => {
                io:println("Error retrieving child parts!");
            }
            mime:Entity[] childParts => {
                int i = 0;
                io:println("Nested Parts Detected!");
                while (i < lengthof childParts) {
                    mime:Entity childPart = childParts[i];
                    handleContent(childPart);
                    i = i + 1;
                }
            }
        }
    }
}

Get the child parts that is nested within a parent.

function handleContent (mime:Entity bodyPart) {
    string contentType = bodyPart.contentType.toString();
    if (mime:APPLICATION_XML == contentType || mime:TEXT_XML == contentType) {

The content logic that handles the body parts vary based on your requirement.

        var payload = bodyPart.getXml();
        match payload {
            mime:EntityError err => io:println("Error in getting xml payload");
            xml xmlContent => io:println(xmlContent);
        }
    } else if (mime:APPLICATION_JSON == contentType) {

Extract xml data from body part and print.

        var payload = bodyPart.getJson();
        match payload {
            mime:EntityError err => io:println("Error in getting json payload");
            json jsonContent => io:println(jsonContent);
        }
    } else if (mime:TEXT_PLAIN == contentType) {

Extract json data from body part and print.

        var payload = bodyPart.getText();
        match payload {
            mime:EntityError err => io:println("Error in getting string payload");
            string textContent => io:println(textContent);
        }
    }
}

Extract text data from body part and print.

$ ballerina run inbound-response-with-multiparts.bal
$ curl -X GET http://localhost:9093/multiparts/decode_in_response