 So we're going to try doing something a little fun with the API today and you know, hopefully, hopefully it'll be somewhat fun and interesting, which is we're going to try life coding. An example usage of the fixie API. And we're going to use a go API so it's a little bit a little bit more verbose on the Python one but hopefully it'll be it'll be fun to follow along. It shouldn't take very long because, you know, ultimately, the contract is fixle script goes in data comes out there's really not that much, much code over there, but it'll be a quick, you know, fun, fun life code. So without in mind, you know, I'll just hop in and get started, but if folks aren't familiar with with go, I'll try to put in enough queues that'll be easy to follow but please feel free to ask questions. Okay, well let's try this part of the adventure. So, diving in. So the first thing I'm going to do is I'm actually just going to switch over to the pixie UI, the live UI and then demonstrate a script. I'm not going to actually go into the details of what the script does, because we have covered like how scripts work in the past to a fair but this script that we're here, basically, when you run it gives you a summary by service and it shows you the total number of requests and error counts. Right. Okay, so what we're going to try to do is actually programmatically call this script from a go program. And, you know, ultimately you can make this all configurable and all that stuff but for now, let's let's go and see how we would do this with go. Before I dive into details, I will quickly just go over to the package.go.dev, which has all the, you know, it has all the high level information about the pixie API. So I just posted on gowithpixie.dev slash pixie. And, you know, it's a relatively straightforward API to use. There is really two main entities, there's a client. So you can construct a new client. And then there's something called a vizier client, which if you, you know, been following along, we basically have the main cloud and then we call our back ends viziers. We can connect to a specific back end and then run scripts on that back end. There are a few other, you know, objects over here, but for the most part, those are the two relevant ones. And as we dive in, you'll see that it's not not too bad views. As usual, you know, we'll be we're up for feedback on the API. This is a very, very early version. So please, please provide us with comments and suggestions. So with that in mind, I'm just going to switch over to my ID over here, which is go land. And then I will, you know, quickly code up an example right so I'm just going to go and say new project because I'll just start from scratch. Apparently I'm going to create awesome project to, and we'll go with a go module project. So create that. Let's say new window. Okay, perfect. So what I'm going to do over here is I'm just going to create a new file. Main.go. So that's called, it's called this package main. Since we're going to be running this as executable. The first thing I'm going to do is switch over to terminal, and I will go get. The pixie library, I have a specific version code in here but you should be able to use the latest. So when you run go get it'll add it to the go modules. So we'll take a couple of seconds. There it goes. So now this is this is available to us to use. I'm going to let's see, you know, when everyone's watching you type it's always a fun experience so I haven't done this a lot so we'll, we'll start from here. So what I'm going to do is I'll grab the pixel script first. So this is the pixel script that I got. Clearly, this is not valid go but we can put this inside a variable called pixel. Okay, so this is not not the cleanest solution right now but this allows us to basically pass in the the pixel script as a variable over here. The next next thing I want to do over here is go ahead and create a new pixie client. So there's a px API dot client, right, and then this thing over here. So basically what I want to use apologies is new client. So new client taking a context and a bunch of options. So as most people are probably aware and go. You have this, you know, concept of context which keeps track of all your your network requests and add an additional information. So I'll just create a background context but you know obviously passing whatever context you have available. So I'm going to create a new contacts. And then the next thing it asked was for the API options. I happen to know that we need to provide an API key. So I say created API option with the API key. So we'll just say that's the API key and we'll come fill that in in a second. And then this returns a client and an error. Right, so I'll just do the standard, you know, go check for this and then I'll just panic if there is an error. It's fine. Um, okay, so yes, I'm coming. Somebody can you go on mute. Thanks. So now I need to grab the API key. I don't really want to hard code my API key in here. So what I'll do is, I will go ahead and grab the API key, and I know I'll need the cluster ID from the environment variables. It's getting easy. So I'm going to, I'm going to cheat a little bit. And copy over these two lines. So what this does over here is it looks up the environment variable for PX API key and open the API key in here. It'll look up the cluster ID and stick the cluster ID in here. From this environment variable. And then if they're not set, it'll, it'll panic. So now that we have the client all set up. The next step for us to be over here is to create a new vizier client. So what this will do over here is that it'll create a client that talks to a specific cluster. So when we do this now it says, okay, go talk to cluster ID, and it creates a new vizier client. So let's call this vizier and error, and then we'll do the same error check. So then, you know without further ado, the zero has a command to execute a script. Right, so execute script takes three variables the first one is the context. The second one is the actual pixel script. And over time will provide a few other options so you can pass arguments and stuff safely, you know without having to do string substitution. So the third option is a thing called a table mixer. So we haven't talked about what a table market is yet but we will do that in one second. But let me fill out the other arguments in here. So they're sorry about that context. And the second argument is the pixel script and the third argument is this mux, right. So we know that we need to create this mux. I'm just going to explain a little bit about what a table mux or does. And for that I think it's probably best for me to quickly sit over to the docs. So what happens in pixie when you run a pixie script is that the API of streaming that streams over all the data to you, you know, live. But a particular script can actually define multiple tables, which are basically like substrings. And what the table mux or does is that allows you to basically accept the table stream. So if you're if your script has, you know, two tables output, you can basically look at the metal metadata and decide you want to only read one one table or you want to format one table in a different way or wherever it is. So we'll implement this in a second but there's a table mux or interface it says I want to accept this table. The key thing over here is that it returns this thing called a table record handler. The table record handler does is it's a type of interface that is responsible for handling table records, right so as every record comes in, it'll basically call in at once. It'll call handle record with the record every single time. And then it'll call handle done when the table is completed. Right so it's like a streaming API and you just implement the interface and you get a record at a time. So I'll quickly go and implement this table mux or interface. So I will create a new, a new type over here. That I'll call simple mux. Okay, doesn't really need to have anything in it other than that one function, which is the simple mux. And then it needs to have the accept table. It says accept table takes a context and a metadata right and returns. So copy and paste that. And then table record handler needs to be imported. Cool. So this is basically the, the interface for accessing a table. You can just widely accept every table now instead of instead of like doing any kind of filtering. Normally, you know, if you're interested, you could take a look at the metadata, which has information about the table name the column informations and all of that and decide you don't care about reading a particular table. So, but in order to accept this table I need to have another thing that implements that table record handler. So very quickly, I will implement a simple table handler. Actually, you know what, let's call this a table printer. And this also in the current state doesn't need to be that complicated. But I will copy and paste a couple of lines, make this a little faster. But basically the first function is handling it handle and it says I got a new table. I need to do something over here. Let me just put return now and we'll come back to this. The second interface is handle record, which gets called every single time a new table record shows up. And then the third type, or the third function is handled done, which gets called every single time. The table has been completed. So it's been fully streamed. So what I'm going to do over here, very quickly, just to complete this is return the table printer and say that there is no error, right. So now what happens is every time a new table comes in, it will get forwarded to the table printer. If I want, you know, I could set up a much fancier table printer. And I'm actually going through the details over here. There are a bunch of like pre built printers that were released so that you don't actually have to think about this too hard. But if you just want JSON, you can just say give me JSON and build string JSON instead. Okay, so now that we have this entire process set up. Let me go back down over here and create this mux. So I can say the mux is equal to what are they called a simple mux. Okay, cool. So now we have the mux. And that's all that's done over here. And then I'll basically check this thing returns a result set and error. If error is not equal to null, I'll do my standard panic on error. And then one of the things you need to do as with most of these APIs is that you need to call close to actually shut down the stream and clean up all the allocated memory. And the last thing we're going to do over here is call results at that stream, which will actually start streaming the data. And then I'll save error not equal to nil. Let's just, you know, die again. Cool. So what we've done over here is this executed a script gone results that we're going to close the results that and then look at the, and then stream the data. So when you start streaming the data, what's going to happen is this function is going to start getting called. So we've written a lot of code so far, let's go ahead and actually try, try running this and see what happens before we, you know, move moving any further with this. I'm going to bring up my terminal here and I'm going to very quickly export my variables while no one is watching this. I have my environment variables set up. So I'm going to do go run main dot go. And then we'll see that it'll compile. We'll take a little bit of time the first time that's kind of build all the dependencies. Okay, well, nothing happens that there are no errors. But we also got got nothing interesting. That's because we're not doing anything. Right. So I'm going to very quickly put in a print up over here and say got table in net. And then you can say something like metadata name. And then I will run main dot go. I'm going to put up table in it for the table call status. So let's make this a little bit, a little bit better by basically going over here and adding in a print for the column names. So all the column information is in this metadata. So now we can go ahead and just print this out. I'm going to be, I'm going to be a little bit lazy over here and do a poor person's formatting on the string. So that it always, it always pads it. This way it'll be a little bit easier to read when it prints out. Now let's see what it looks like. So now it says that there is a service total request and error count. So if you remember from the user interface, those are the three columns that we saw. And that's the column names that we filled out over here. Cool. So the last step we need to do is actually implement this handle record interface. And handle record returns a type of record. So, it'll give you a good time to some like 30 seconds on this and I don't want to get into too many details, but the API is pretty strongly typed. And there is this package called types, which actually defines all of our various types. So every type that's represented in pixie has a specific type built in. And then there is this interface called datum. It basically defines a whole bunch of things on the type. So the thing that it defines over here is a string. So there is a function that always returns a string representation. Then you can get the data type and the semantic type and a bunch of other things, which, you know, we don't need to get into there right now. But if you call string on the center face will always return like the canonical string representation of the data, regardless of what the underlying type is. So with that in mind, let's go back here. And then what we can do is this data is row based so we can just go and print out a single row, our data. And then we just say print this out. I'll do the same thing over here so it always formats nicely. I'll say print out the string representation. So without having to do any type gas over here because it's using the interface, it'll just print out the string string representation. And then I will go and put in the white new line. And then we can run this. There it goes. Being a little bit slow. There you go. So this is the data that was in the UI. And now it has shown up in the API. And that is actually it for the live coding demo. There are a few other things that the API can do but you know there are plenty of examples online to look at along with documentation on our website.