Calling the Runner
In the monolith, running code was a function in the application. The handler for Nadia’s POST called it like any other function:
const result = runSubmission("java", code, problem.tests);
Now that function is in the runner, a different service on different machines. The application has to send the runner a request.
Let’s design that request as a REST API first, because the application already has a REST API.
A REST request
In a RESTful API, the path names a resource and the HTTP method names the action. The closest thing to a resource here is a run, so the application could create a run:
POST /runs HTTP/1.1
Content-Type: application/json
{
"language": "java",
"code": "public static boolean isBalanced(String s) { ... }",
"tests": [ ... ]
}
When a POST creates a resource, the server responds with 201 Created. The response puts the path of the new resource in the Location header, so that the client can read it later. So should a run be a resource of its own? The results of a run are worth keeping. Nadia may open submission 8812 next week and want to see which tests passed. But the same code run against the same tests should give the same results, so I think the results belong with the submission. The application already saves the submission at /submissions/8812, and it can save the results in the same record. Then a run has nothing of its own to keep. There is no /runs/5531 to GET, no run to replace with PUT, and nothing to DELETE, so the runner does not need to store runs at all.
So the runner would respond to POST /runs with 200 OK and the results. The request looks like a REST request, but the application is really calling a function. It sends the arguments and gets back the result.
A remote procedure call
What the application wants is to call runSubmission as before, with the same arguments and the same result, and have the function run on a different machine, the runner. A call like this is a remote procedure call (RPC). The caller calls a procedure, an older word for a function, that runs in another process, usually on another machine. The request names the procedure and carries its arguments. The response carries what the procedure returns.
Recall the endpoint mistakes we listed for the Public Courses API. /getCourses was wrong because its path names an action. In RPC, the request names the action on purpose. GraphQL’s mutations work the same way: placeOrder names the action.
RPC is older than REST
In 1984, Andrew Birrell and Bruce Nelson at Xerox PARC published a paper on how to build remote procedure calls. Systems used RPC through the 1980s and 1990s, well before Roy Fielding described REST in 2000.