DEV Community

Kurt Kemple
Kurt Kemple

Posted on

Everything Serverless Functions in AWS Amplify - Part 2

In the second video we go deeper with serverless functions being used as resolvers in AppSync. We take a look at accessing arguments being passed to the function, as well as how to access sibling data in the resolver and how to handle pagination. We did all using the "amplify mock" command and running the environment locally.

Links from video:



Hello, everyone, and welcome back to everything service functions in AWS amplify. Yeah. So last week, where we left off, we had created a react app added amplify to it, set up a very basic graph QL API using App sync. And here's the schema. We just made a Hello World function, which we connected to a server list function. And yeah, so that returned, essentially. So it actually looked a little bit more like this.


Yeah, just like that. And yeah, so we just made a function that could return hello world, and we checked it in the browser, and everything was great or great. So if you haven't actually seen that, there'll be a link o the first one, so I definitely recommend checking it out. But where we're going to pick up today is we're going to work with this function.


And we're going to extend the capabilities of it. And then we're going to change, we're going to add another function and pull some data in from an API. And so maybe, you know, we'll see how far we get and when it feels like a good stopping point. But yeah, so basically, now that we know how to set up a service function, like we did in part one, we're going to see all the different type of things that you can do with it. So should be pretty interesting.


And, yeah, let's go ahead and dive in. So the first thing that I'm actually going to do is we don't really need the UI at this point. So we're deciding what the schema is going to look like, you know, the data structures and at this point, you know, checking that in the UI seems like a lot like a pretty slow feedback loop.


We also don't want to be deploying things out to AWS. And what I mentioned in the last episode is that we would use something called mock to go ahead and mock out the API, and data storage and all that fun stuff. And that's exactly what we are going to do. So first thing I'm going to do is run, amplify my.


And so this is going to spin up a server, but it's going to be local, but you can interact with it, and it will behave exactly as if it was deployed on AWS. So the cool thing is, you can see that there's mock endpoint running, which is just the IP from my machine, so localhost:20002. So I'm going to go ahead and open that up, and I've just configured browser preview to have that as the default. So now I can just slide this over a little bit. You know, we can hide and show the Explorer for more room. But now we have graphical rights.


So we can, we can see our query here. And then we have the server list function that it's connected to called hello world. So given this schema, it should return a string. And then that string should come from the function. So this should return hello world. So I'm just going to close the Explorer here and get rid of this. And oops, let's run the query.

Hello, world.


So we run it and we get data back and hello world. And sure enough, it's hello world. And so this is just local running on my machine. And so it's pretty cool. So to test this to see it's like essentially doing like, a hot reloading thing. We could change this to Hello universe. We save it, we rerun the query, and look at that Hello universe. So it's pretty cool. You can work with


These lambda functions locally and you know, just spin up graphical. And you get this kind of really quick feedback loop that's, you know, just allows you to essentially work a lot quicker, right, which is awesome. So one thing though is like if we want to change the schema, because graphical is doing schema introspection to figure out what's available, then in that case, we have to reload graphical, but I think I can live with that, right? So let's add a parameter for message will make it optional, and will make it a string. And so will still return a string, and we'll still call this function. So now we're passing an argument to this query, right? We want to do something specific based on a bit of data.


So how do we handle that in our lambda functions? So the way lambda functions get is it gets something called an event. And so essentially, what's happening is because it's in a pipeline, it's connected to App sync, this event gets populated for you. And everything is, you know, mapped to the event from things so like with when it's attached to this lambda function, it's attached to sorry, like a field in your graph QL schema, it knows like, okay, so if any arguments come through all attach those, and we'll take a look at how you can also access like the sibling data, just like you would in any other graph. QL project, right? Like sometimes maybe you want to grab, you know, related data, to then do something more augmented, like, take latitude and longitude and return in a dress or vice versa, right, you have a full address. So you take that and you return a latitude or longitude.

There's a multitude of use cases. So okay, so we have our event. So what we can say here is everything comes in here. Use the event and event data to see what our arguments are and so everything comes off under event arguments, right. So this is like would store any type of argument that's passed. So here we have message so we can expect event to argument stop message. Well, we can't expect it because not required, but it should be there should be something available if it is passed in.


So we can say message equals event arguments. That message or you know, you could do structure you can do whatever you want. And then here we'll just say, message. If not, hello, universe actually will leave that Hello universe. Okay, so we'll save this but now remember, we change the schema. So if I just come over here and I'm like, ah, message, ah, see, it's gonna yell at us and say, Hey, we don't know what messages right say. So we got this unknown argument. So we got


And essentially, we run our query. So we could have copied it out. But it's pretty small. But now we've got message. So it should return Hello universal, let's do hello world. It will run this a hello world. So let's remove that, right. And so if we go back and we look at this function, it should return Hello universe. So let's run it. And we get Hello universe. So that's how you can handle arguments. So pretty cool.


Okay, so we've taken a look at how we can now use arguments and pass data. So we're going to set up a new function, and we're going to use that function to call an API, and we're going to look at using some arguments to handle pagination. So I'm going to add a new property here.


So, in our list Pokemon, we are going to want to be able to set a limit. It's not required though. And also were to pick up from when we left off. And so we're going to call this next token. and in this situation, next token will be an int.


And this is going to return a oops, sorry, it's not gonna it's going to return a Pokemon connection.


And so what that means is because when we return it, because it's a list and we want pagination, we need a way to identify Hey, what was the last item that was given?


Like, or, you know, or where am I in this list of Pokemon. So when you get a response from this, what you really want is the items, the actual Pokemon, but as well as that token that next token, so it's kind of like an intermediary layer, instead of just returning the array of Pokemon. We also want that next token. So we have a type Pokemon connection, which has a next token, which is a string, and it's not, or sorry, in this case, it's an event. And it's not required because it could be not. And if it's no, that means Hey, you're at the end, there is no next token, you've hit the end. And then we want items. And so items and for brevity sake, it's not going to be too much, but it will be Pokemon.


But we have to create a type for that. So I am going to fast forward through the creation of this pokemon type, and then we'll pick back up


Okay, we've created a Pokemon connection, a Pokemon type and a Pokemon move. So the first thing that we want to do is set up a function to do the listing of the Pokemon. So say function name. And we'll have to name this will call this ES for everything server lists.


Actually no dashes just Pokemon. And then of course, we want to do dash environment. So that one is created for any environment that we have, it can be in. Okay, so we're just we're going to stick for this now, and Pokemon moves are not required just yet. So we're not going to worry about these at the moment but we are going to worry about listing the Pokemon


So what we're going to do here is run amplified function. So if you look down here in the terminal, it says, actually, let me pull that up one, just that go. Well, okay, so it says, please run amplify add function. So it's already telling us like, Hey, you added a function, but it does not exist. So let's make that exist. So we're going to say, amplify add function.


Okay, and for a name, we will call this the same thing. Yes, lyst Pokemon, or for the label, and then for the lambda function name will keep it the same. We want a Hello World function. So I'm going to pick that.


In this case, we do not want to access any other resources. We're going to access a third party API


Want to edit the local lambda function now? Yeah, we definitely do. So we're going to hit yes.


Okay, so here we have shiny function, but we are going to want to fetch some data, right we want to get we want to get some Pokemon, and we need to take into account that we might get a limit. So we need to pay attention to that. And we might also receive a next token. So


I'm going to go and get the URL for Pokemon. Okay, so coming back in here, yeah, build Pokemon URL, it's going to be a function that takes a limit and the next token and it going to return a string. And so this is the base URL for Pokemon and already know that it takes two parameters that are important. And that is limit. And next token, or sorry, the API takes limit and offset. And that's how you could do pagination. So for us, this is a pretty easy conversion. So we just say limit. And that's going to be equal to what is passed in his love it, and then we're going to have offset. And that is going to be equal to whatever is passed in as next token. So that's as easy as it is to kind of get this pagination going.


Okay, so we know that we want this URL. Now we need a limit. And we need a next token. So let's go ahead and get those. So we're going to say const limit. And we're going to say equals here and we'll do 20. It's going to be a default, because we might not get it. And then we're going to look for next token, and that's also going to be are going to have a default of zero. So that's our offset, so we don't get an X token we're starting from the beginning. And if we don't get a limit, then we're doing 20 at a time increments and that's going to be equal to event arguments.


Okay, so now we have that and we have a URL. So what we want to do, I'm just going to give this a little bit more room. We need to like fetch this data, we need to get it some way so I'm familiar with x iOS, which is not installed yet. We will install it and we're going to say get URL. And so now we're doing some basic stuff. So this is pretty cool. Let's g is equal to x Yes Get URL because that returns us promise. And we'll do a try catch here in a second.


So now we have the result. So what we want to return So remember, this is listing Pokemon. But if we come back to the schema, it's a connection. So we need to form a connection, not just return the items themselves, and we want an ID and a name. So we have to get that. So let's do this. We will say that the response is equal to. So first, let's take care of our next token, which will, we would want to check our result list and see if we're at the end. But for now, let's just do it as limit plus.


Next token, right? So wherever we started from plus what we fetched, we'll just treat that as the default, just for now to return something. And then we will say, items, is equal to I want to say result data. I think that's correct. I'm going to check the API docs and I'll be right back.


Okay, so I checked the docs and it looks like it's going to be result data results and


For our next token, so remember, we want to return this if we have more results. But what if we don't? What if this is the end so we can say, result data. Next, because that is returned if as a URL if there is more, if you can fetch more. So if we want that, if we if we know there's a next than we can just assume that will get more.


Otherwise, there's no next that we return no for a token.


So now in this function, we don't want to return this. We want to return our response that is formatted in the data structure of a connection. But right now, we are handling Oh, look, I'm person missing, in a way. I wonder how many of you saw this and we're like, oh, you're missing away. It's kind of break.


Yeah, so Okay, so we have some a sickness going on, but we're not catching any errors. So


Let's try and catch them.


I should just let prettier do that.


All right, catch. error


we will first will console log it


for funsies, but also console.log it. Oh, and we didn't return our response. So we will I context done that error. So if you hit an error, that's kind of the first parameter, this up here because used to be in that, that's looking a lot better. Okay, so we get our limits. All that looks good. So should should be good. We should be good to go here. So we're gonna hit Continue. All right, let's, uh, let's spin it up.


Okay, so because of the way the API is structured, we can't actually get back the ID that doesn't come back with the results. So when you list the resources, all it really gives you is the name and the URL to actually fetch that Pokemon. So what we're going to do is we're going to fetch them real quick. So we'll say cause.


So let's actually, so we have the name. So let's add back those, those properties.


Let's add ID back and see if this in fact, is working, which is I believe an event.


Save that. We want the items ID and Name and let's run it. So there we have everything.


And now the Pokemon API, I would imagine their caches pretty warmed up, but we get the ID of the the Pokemon were before we could not. So now we have the moves, which is a Pokemon move. And so we have a name, property and power, accuracy and priority. So what I'm actually going to do is create a new property called stats. And this is going to return Pokemon stats.


But it's going to be powered by a function.


And this function, its name will be will call it ES.


Pokemon stats. And again, we need to specify for the environment. So


what we're actually going to do here is take these out.


We're going to create a new type


and we'll call this pokemon stats.


Okay, so we have to do two things in order to make this work first right now, we are not as well, we have to add a function. So technically we have to do three things. But the The first thing, let's actually just remove this declaration for right now. don't even need that. Okay, sorry. Yeah, so we'll do this. So we don't have to create a new function


just yet, but still, we can't get the name. So right now we're not returning any moves. We're not doing any anything deep. we fetch the Pokemon, but we don't have the moves.


Hey, cool. All right. Thanks for sticking with me. So we got the name. So now, we want the deets, right, like whenever. Maybe we want to access stats about this. So we need Pokemon stats and we


We need this to be


function, right? Like we need to get that and also how we're going to get it. We're going to query the API using the name or a source property, like a sibling property to stats. So we'll see how not only can you pull data in as an argument, but you can also access the sibling data of the field that the lambda function is resolving to. Okay, so we'll save that and then we're going to get notified, it's gonna say, hey, you need a function. So let's go ahead and create that function. So here we're going back up to the root, I got it. And we're going to say amplify add function.


Okay, for the name of it, we will call it espokemonstats


Hello World function, we do not want to access other resources. And we'll get into that in a later episode.


Yeah, we definitely want to edit it now, though.


Cool. So what I'm actually going to do is we're going to use


decent amount of this stuff. So we're going to just bring it all over into our new function.


And we're going to change the thing. So first,


this won't be here. So what will be here will be name and that won't come off of that the arguments it will come off of event source. And so the source is


the sources is the sibling data, right? So, in this case for moves, next that will have stats it's the name right we want the name. So now we'll say we'll just keep it build Pokemon


URL, but instead it's going to take a name. And so appear it's going to take a name.


And we're not going to be calling Pokemon, we're going to be calling


moves. And I believe instead of having any of this, we just do slash and then name.


So I'm going to verify that really quick. On the docs.


Move. This is not news. It's move. That make sense. Okay, so now we have that we have our URL. So we're going to build our results. We won't need


all of this data and our response doesn't need a next token, and the three properties that were accessing priority, let's go to actually see what those are.


Yeah, so we have power, accuracy and priority those are root properties on the


But just so that we can see will say contest,






and the other one




And those are going to be equal to result data.


And that's what we're going to respond with.


So we could just pass result data, but I just want to show that these properties do in fact, come off of there. And we're returning them exactly because it's graph QL. And since the only three data fields that we say are available, are those three it would only like return those three to the end user. But we're just going to explicitly spread it out so that you can see,


I said our limit to five


the name moves the


Name and all the stats. All right.


Okay, so if we close this up, we can see, for sword dance, we got no, which is interesting. Maybe we hit a four or four


on there, but we can see that we are getting the stats back for most of these moves. But that's interesting. So here is another one. I guess it's another evolution of the same one. But yeah, so that's that just seems to be missing. But yeah, so we've got our data coming back. So now we have, if we go back to our schema, we have three functions.


And we've done a lot of things. So first, we've allowed to pass arguments. We've set up how to deal with pagination based on arguments. And lastly, how to access the sibling data on on service functions that might be buried within


Your schema and aren't at the root of query. So I hope this was fun and enjoyable and I will see you in the next one.

Transcribed by

Top comments (1)

andrewbrown profile image
Andrew Brown ๐Ÿ‡จ๐Ÿ‡ฆ

I was a bit surprised to see you didn't use AWS Transcribe for the transcription.
I suppose its possible uses AI under the hood.

Very cool amplify walkthrough ๐Ÿ‘ ๐Ÿ‘