Transcript
  • Meteor

The Mechanics of Methods

From the class:  RPC with Meteor Methods

Let's take a closer look at the mechanics of what happens when we make a Meteor method call. On the left, I have my client code, and on the right, my server code, just to make things a little easier. And we'll pretend that in the middle here is the internet, or what we keep calling the wire. And what I'm going to do is on the client, make a method call to this method called forward slash Items Insert. And that's just a naming convention. It looks like a URL. And you'll see this come up again when we use Meteor methods with collections.

I'm going to make this method call with a document object. And so we'll simulate the idea of inserting a document using a method. Then, over on the server, I've defined the method. And it doesn't have a body yet. But it does take a parameter called Document. And it has the name Items forward slash Insert.

So on the client, the first thing that happens when we call Meteor.apply is Meteor looks and sees whether or not there's a client stub. If you recall from the last video, a client stub is just the same method on the server defined on the client. And it will call that first so that we have a chance to do some things right away before we make a method call over the internet and introduce some latency.

Now, we don't have a stub in this case. But if we did, it would be called. And Meteor would wait until we have a result from the stub.

Then, the second thing it needs to do is to actually make the RPC call, which means to send a DDP message over the wire to the server. So this DDP message is called, as you might have guessed, Method. And this is going to tell the server, hey, we want to invoke this method on the server. And so we're going to have to pass some additional information here-- for example, the name of the method. And so the way it does that is by providing another property called Method. And in this case, the method name is going to be the forward slash Items Insert.

And I won't draw it all out, just to save some time.

And then, it'll pass up any other things, like parameters that we have, and an ID, so that we can track correspondence between the client and the server. Now, the important thing to note is that this message gets sent over the wire. And then, we forget about it. So in other words, it's asynchronous. We don't know when we're going to get a result from the server.

Now, once the server receives this message, it will say, OK, the client is trying to invoke a method. And that method's name is forward slash Items forward slash Insert. So let's go ahead and see whether that method is defined. And if it is, we can go ahead and call it.

So inside of our method body, the first thing we might want to do inside of a method is to return some result. So to return a result, let's just say we're returning an idea of a document. And I'll simulate that idea as just being the hard-coded value 1.

So now, the server needs a way to tell the client that there's a result. In this case, the value of that result is 1. And to do that, it can send a DDP message back to the client.

So at some later time when this method is finished running, another message will get sent back. And the name of this message will be Result. And then, we'll get the result value in another property. And that will contain the JSON-encoded value of the result. Now, in this case, it's 1.

Let's go ahead and change it so that it's less confusing, because our method ID is also 1. And so why don't we just say that this is the My Doc ID, or something like that. And now their results that will get passed back will be that value-- My Doc ID.

And then, the message back will also contain the ID of the original message. So in this case, that's 1. And that's how the client will know that this is the result for this message that was sent up here.

Now, on the client we can't just take that result and assign it like this, because we get the result at a later time. And in JavaScript in the browser, there's no way to block the code from running and wait until we have that result. So instead, we can pass a callback.

Now, you're probably used to using a callback where there's a function here. And we'll come back to that in a second. For now, what we're going to do is pass an object of options. And there's an option that you can use called On Result Received. And the value that can be a function that has an error and then the actual result. This function will get called when we get this result message. So if we have an error, we could print out the error. Otherwise, let's just say that the result is whatever we got back here.

And we'll open up a browser debugger so we can take a look. I've opened up the browser debugger so that we can see that the result gets printed into the console down at the bottom there.

So far, we've looked at how we make a method call to the server using the method message, and then, how the results of the method get sent back to the client using the Result DDP message.

But there's one more message that we need to take a look at. And it's called the Updated message. Let me clear up this screen a bit so I can explain.

Let's say that on the server, if our method, instead of just returning a value, like we're doing here, does some other work to update some data. For example, let's say that we're actually taking this document and inserting it into Mongo Database. So making a write to Mongo Database, in this case, is going to be asynchronous. In other words, we'll make that call, or the write. And at some later time, Mongo will tell us that the write has completed. And so just like making an asynchronous network call, that call will return after we've already returned a result here.

So there needs to be some way for the server to say that all the writes have been completed on the server, and to tell the client that that's true. And that way, the client can say, all right, the method is completely done. And the way that the DDP protocol does that is the server sends an Updated message for the method.

So what happens, to recap here, is first there's a method message. And then, when there's a result, there's another message sent back from the server called Result. And then, when all of these writes have completed-- to Mongo or to anything else-- and those DDP messages have been sent to the client-- the Added, Changed, and Removed messages-- it sends one final message called Updated. And just like with their Result message, it will pass the ID of the method back to the client, so the client knows what this updated messages for.

So when the client receives this Updated message, it knows that the method is completely done. So the server has executed the function and returned a result. And also, we have all of the updated data that may have been written to from the method.

Now, in your applications, you're probably used to providing a callback function as the last parameter to your collection insert, update, or remove, or to your method calls. This callback gets called when the client has both the result and the updated message. In other words, after our local cache has been updated with the most recent data and we have a Result message from the server, if both of those cases are met, then this function gets called.

So we might say in the log that we have a result and updated data. And down in the JavaScript debugger console, when the On Result Received function gets called, we print out Result My Doc ID. And when the server sends the Updated message, and the client says, OK, I've got the result and the Updated message, this final callback gets called. And in the debugger we print out "We have a result and the updated data."

Let's take a look at those DDP messages in the network debugger of Chrome. First you can see the method call, that message that's sent up from the client to server, and you can see the method name and the parameters, and the client has assigned an ID of 1. Then, we get a few answers back from the server. And you see those messages prefixed with this A.

In this case, we get the Updated message before the Result message. We can actually get the Result and Updated messages in either order. So sometimes, you'll get the updated message first. You'll get more intuition about that later.

In this case, you see the Updated message gets sent back with the method IDs that it applies to. And then, we have a Result message with, again, the method ID of 1, and the actual result value.

So I find that looking at DDP messages in the Network tab like this can be really useful for understanding how things are working under the hood, and what messages are getting sent back and forth, either with Meteor methods or with any other DDP functionality.

Now, you might be wondering-- on the server, when it makes writes to Mongo like that, how does it know when all of those writes are done and when to send the Updated message back to the client? And we'll look at that in the next video, when we talk about a special data structure called the Write Fence.

But in this video, we took a look at the mechanics of making a Meteor method call. So what actually happens when you use the Apply or Call method on the client? We looked at how the stub gets called first. And then, the client sends off an RPC message to the server to invoke the method. When we have a result, the server sends back a Result message to the client. And when all the data has been written on the server and the client has been notified of those changes, the server sends an Updated message to indicate that the method is completely done.