We currently do this by using the queue's features to handle the response. The user is forced by security rule to write their user ID as a property of the request and they may read only items in the queue that contain their ID.
Security Rule (relevant part for client):
"queue": {
"tasks": {
".indexOn": [
"_state"
],
"$id": {
".read": "auth !== null && ((!data.exists()) || (data.child('user').val() === auth.uid))",
".write": "auth !== null && ((!data.exists() && newData.child('user').val() === auth.uid && newData.child('_state').val() === '<start state goes here>') || (data.exists() && data.child('user').val() === auth.uid && !newData.exists()))"
}
}
}
This allows a client to create new jobs and delete jobs, but not modify their content.
To ensure that the client can only add an entry in the start state you will need to fill in the <start state goes here>
in the rule above.
Spec
{
"error_state" : "error",
"finished_state" : "finished",
"in_progress_state" : "in_progress"
}
You need a non-default spec to specify a finished state, which the client may watch for to know when the request is resolved.
Other Considerations
The client cannot be relied upon to clean up tasks used like this. You should configure the server to delete the response automatically after a timeout. The user might refresh or leave the page before a response is returned for example. This may only happen less than 1% of the time but if the queue fills up with finished responses your performance will degrade.