Rajeev Mehta
Rajeev Mehta

Reputation: 820

JSON Streaming in chunks using Alamofire Swift

How to request using Alamofire to get stream JSON. I am using the below function to get the response

self.sessionManager?.request(url, method: methodType!, parameters: params, encoding: JSONEncoding.default, headers: headers)
            .validate()
            .responseJSON { (response) in
                if (response.result.error == nil) {
                    completion(response.result.value as AnyObject?, nil , response.response?.statusCode )
                } else {
                    // debugPrint("HTTP Request failed: \(String(describing: response.result.error))")
                    completion(nil, response.result.error, response.response?.statusCode)
                }
        }

And my API Url something like

http://{server Url}/services/data/{number of chunks}/{items in per chunk}

and the response I get from API if the number of chunks is 3 and items per chunk is 3

data: [
    {
        "invalidDraft": false,
        "bulkReserve": false,
        "srNo": 0,
        "returned": false,
        "status": "ACTIVE",
        "timestamp": 1580186026419,

    },
    {
        "invalidDraft": false,
        "bulkReserve": false,
        "srNo": 0,
        "returned": false,
        "status": "ACTIVE",
        "timestamp": 1580186026417,
    },
    {
        "invalidDraft": false,
        "bulkReserve": false,
        "srNo": 0,
        "returned": false,
        "status": "ACTIVE",
        "timestamp": 1580186026417,
    }
]

data: [
    {
        "invalidDraft": false,
        "bulkReserve": false,
        "srNo": 0,
        "returned": false,
        "status": "ACTIVE",
        "timestamp": 1580186026417,
    },
    {
        "invalidDraft": false,
        "bulkReserve": false,
        "srNo": 0,
        "returned": false,
        "status": "ACTIVE",
        "timestamp": 1580186026417,
    },
    {
        "invalidDraft": false,
        "bulkReserve": false,
        "srNo": 0,
        "returned": false,
        "status": "ACTIVE",
        "timestamp": 1580186026417,
    }
]

data: [
    {
        "invalidDraft": false,
        "bulkReserve": false,
        "srNo": 0,
        "returned": false,
        "status": "ACTIVE",
        "timestamp": 1580186026417,
    },
    {
        "invalidDraft": false,
        "bulkReserve": false,
        "srNo": 0,
        "returned": false,
        "status": "ACTIVE",
        "timestamp": 1580186026417,
    },
    {
        "invalidDraft": false,
        "bulkReserve": false,
        "srNo": 0,
        "returned": false,
        "status": "ACTIVE",
        "timestamp": 1580186026417,
    }
]

data:done

I did not get any response from the server but in Postman it works fine.

Upvotes: 6

Views: 3240

Answers (3)

wile_e_coyote
wile_e_coyote

Reputation: 39

Elaborating a little on Alex's most helpful answer:

fileprivate lazy var alamoSession: Session = {
    let configuration = URLSessionConfiguration.default
    configuration.timeoutIntervalForRequest = 20
    configuration.urlCache?.removeAllCachedResponses()
    return Alamofire.Session(configuration: configuration /*, interceptor: interceptor*/)
}()

fileprivate func alamofireChunked () {

    guard let url = URL(string: "http://A_Steaming_Source.com")    // Put your datasource here
    else {
        return
    }
    let urlRequest = URLRequest(url: url)

    alamoSession.streamRequest(urlRequest).validate().responseStream { response in
        if let data = response.value {
            print("received \(data.count) bytes")
            if data.count > 0 {
                // process received data here
            }
        } else {
            switch response.event {
            case .complete( _):
                // perform any post processing here
                print("stream is finished")
                break;
            default:
                break;
            }
        }
    }
}

Upvotes: 0

Alex
Alex

Reputation: 89

To receive streaming data, you can try adding

request.stream(closure: { data in ... })

Inside closure you should collect data chunks from server and parse them lately, after response is called. In that case response will be nil.

So it would be something like:

let mData = NSMutableData()

self.sessionManager?
    .request(url, method: methodType!, parameters: params, encoding: JSONEncoding.default, headers: headers)
    .validate()       
    .stream(closure: { data in mData.append(data) })
    .response { response in
       //parse mData
    }

Upvotes: 3

rodskagg
rodskagg

Reputation: 3927

The reason your request fails might be that you are using responseJSON to parse the response, and the response does not seem to be valid json.

The returned data consists of three individual arrays named data, all located at the top level. How should this be converted to a dictionary or array?

Is it possible to change the way the server formats the response, to - for example - have it return one toplevel array, with several data child arrays (one for each chunk)? Sort of like this:

[
    [
        {
            "invalidDraft": false,
            "bulkReserve": false,
            "srNo": 0,
            "returned": false,
            "status": "ACTIVE",
            "timestamp": 1580186026419
        },
        {
            "invalidDraft": false,
            "bulkReserve": false,
            "srNo": 0,
            "returned": false,
            "status": "ACTIVE",
            "timestamp": 1580186026417
        },
        {
            "invalidDraft": false,
            "bulkReserve": false,
            "srNo": 0,
            "returned": false,
            "status": "ACTIVE",
            "timestamp": 1580186026417
        }
    ],
    [
        {
            "invalidDraft": false,
            "bulkReserve": false,
            "srNo": 0,
            "returned": false,
            "status": "ACTIVE",
            "timestamp": 1580186026417
        },
        {
            "invalidDraft": false,
            "bulkReserve": false,
            "srNo": 0,
            "returned": false,
            "status": "ACTIVE",
            "timestamp": 1580186026417
        },
        {
            "invalidDraft": false,
            "bulkReserve": false,
            "srNo": 0,
            "returned": false,
            "status": "ACTIVE",
            "timestamp": 1580186026417
        }
    ],
    [
         {
            "invalidDraft": false,
            "bulkReserve": false,
            "srNo": 0,
            "returned": false,
            "status": "ACTIVE",
            "timestamp": 1580186026417
        },
        {
            "invalidDraft": false,
            "bulkReserve": false,
            "srNo": 0,
            "returned": false,
            "status": "ACTIVE",
            "timestamp": 1580186026417
        },
        {
            "invalidDraft": false,
            "bulkReserve": false,
            "srNo": 0,
            "returned": false,
            "status": "ACTIVE",
            "timestamp": 1580186026417
        }
    ]
]

If this is not possible, parse the response as a string instead, and then use regular expression to find every "data" array in the string, which can then be parsed as JSON.

Upvotes: 0

Related Questions