 As soon as everyone can hear me all right, seems really loud to me up here. So this is building confidence in APIs with Postman. My name is John Ferris. I'm the director of front-end engineering at Atten Design Group. Atten is a full-service design strategy and development agency based out of Denver, Colorado. We work with a lot of organizations that are doing really good work. We like to think that we work with organizations that are really trying to make the world a better place. And increasingly, our clients are coming to us with ask for more, like, application like websites. Not just content publishing, but data visualization, more interactive and intuitive forms. Things that don't work very well necessarily or very efficiently with the standard like full-page refresh kind of site architecture. So we're doing a little bit more decoupled work. And that requires using a lot of APIs. And me personally, I got into web development through design. I started graphic design and I did do a little bit of schooling with actual computer science degree, but it wasn't visual enough for me. And so I gravitated to the front-end naturally because it's that mix of visual kind of the art side and actual programming. So my experience with JavaScript was more like making drop-downs and animating things and a whole lot of action script and flash interaction back in the day. So the idea of actually getting data through an API and doing authentication, those kind of things, that was really intimidating for me when I was getting into it. It just seemed like a lot of pressure, you got to get this right. And so a few years ago, I found a tool called Postman. At the time, it was a Chrome app or Chrome extension that you can use to actually test APIs. Can I get a show of hands of people that have actually used Postman? Cool. A lot of people. Awesome. Of those people, who's actually used the native app? Cool. So yeah, traditionally Postman was a browser extension for Chrome. And they've released a native app that is just incredibly intuitive, really useful. And the reason I wanted to share it with you today is like there was a lot of things. I just used Postman to grab an API, send a request, get the response back and view it. And I recently learned there's so much more to it and there's so many more features that I just didn't know about. I got really excited. It felt very empowering. So I wanted to share that with you today. And I want to do that in the context of Contenta. Everybody familiar with the Contenta distribution for Drupal? Anyone not? Cool. So Contenta is basically, it's a distribution made for API-first Drupal development. So it has a lot of things turned off like there's not really a front end or like blocks per se. It's designed just to allow you to model your content and expose that as APIs. So it has a lot of functionality like simple OAuth built into it, JSON API, which we're going to talk about, and GraphQL, which I've never used. So you can ask me a question and I won't answer it or tell you where to Google it, I guess. So we're going to talk a little bit about JSON API. If you're not familiar with JSON API, yes, it is a module for Drupal, but JSON API is actually a specification for sending requests to a server and getting responses back. So the specification outlines like basically if you were sending a JSON request or a JSON body in a request to a server that's formatted in a very specific way, you know, how you filter is fairly prescribed, how you sort and those kind of things. And then the response, the shape of that data as it comes back is all in the specification. And there's really two big advantages in my mind at least for the specification. The first is you don't have to spend a bunch of time like architecting what your API is going to look like. JSON API, basically everything is entity formatted or entity-based. So you have specific endpoints for a resource. You can fetch those resources, you can post them, you can get collections back. And that maps really well with Drupal. So if you think of a node as an entity or a taxonomy term as an entity, that maps really well with JSON API. So you don't have to spend time arguing over like what's the shape of this data? What is the endpoint we're going to post to? What are we going to get back? And then the other big advantage, because it's a specification, that allows us to make tools that make assumptions about, you know, what that shape, the shape of the data should be. So we don't have to write a lot of boilerplate code in order to, you know, fetch a node from Drupal per se. So we're going to, the examples we're going to look at in postman are all going to be based on JSON API, the JSON API module. As I say here, I highly encourage you to actually read the spec. It's a 30, 40 minute read and I'm a really slow reader. Also, once you're done with that, there's really good modules or really good documentation for the module itself. So it's definitely worth the time reading those. It'll save you a bunch of time. Yeah, do that. So I want to talk a little bit about APIs in general. Sounds like just based on the hands of people in the room that have used postman, you know what a REST API is. But essentially, we are just sending a request just like you would for an image or an HTML page. You're sending a request for data. So you send that to the server and you get a response back. Those responses have status code. So you're familiar with 200, you know, everything worked. It's usually a good sign. 201 created. So if you're actually posting a new entity to the server, in our examples coming up, we're going to post a recipe to the server. And if it works successfully, we'll get a 201 status code. 301 moved permanently. 403 forbidden. So if you don't have, you're not authenticated to get a resource. 404 not found. You probably put the wrong URL in. 418, I'm a teapot. If you send a request to a teapot trying to make coffee, you're going to get the 418. I'm a teapot response. There's also a spec for that. Google it. I'm not lying. But the general idea is the 100 responses are hold on. Two, here you go. Everything's working well. Three, you go away. 400, you screwed up. 500, I screwed up. Usually when you get the white screen of death, that's in the 500s. So it's actually since requests. Okay, so here's the postman interface. Postman has a concept of workspaces. So you can switch. Usually I'll have a workspace set up for like a different project that I'm working on. And then you have collections here on the side. So collections are just groups of requests. And then within those you can, I don't have any here, but you can organize those in folders as well. So in this example, can everyone see that all right? Is it big enough? I need to zoom in. Cool. So here's, I've got a local instance of Contento running. It's namespace with this API path. And I want to get recipes. So I send that, I should get a whole list of recipes back. And this is the JSON API format. You get, if everything goes correctly, you get one object. And inside of that, it's got a property called data, or it must have the property data. And if it's a collection, like you're getting a group of entities, in this case, we want all the recipes. We didn't specify any filtering or anything. So it's going to send back an array. Even if it's just one, it'll send back an array because we're getting a collection. So yeah, we just have a bunch of entities and you'll see that there's a lot of data here. In a lot of cases, when you just want to show a list of recipes, you don't necessarily need all that data. You don't need the created data. You might not need if it's published or not. You don't need the user ID. So we'll look at ways to just get what you need there. So Postman allows for URL parameters. So in this case, we want to get a specific recipe. So we know the UUID for that. And if we just hit params, you can see I already have it defined. I've got one of the UUIDs for a recipe. And we send that. And in that response, you notice that now this is an object. So we just get one single entity. It's a recipe, basically all the same information that we had before. It's just now a single entity. So it's an object. Categories are taxonomy terms. We can send those. Get those. And that's what you might expect. It's categories, a bunch of field data. Now, JSON API allows you to filter those queries, get specific fields. So first, I'll turn on the sort parameter. This is one thing I really like about Postman, is you can load a bunch of test query parameters up in here and just enable and disable and delete them as you need. So you don't have to worry about always going back and copying and pasting things in. Disable specific parameters. So we'll send that. And it should be sorted by name. So we have main course. Let's see. It's kind of hard to scroll through this, right? Because there's a lot of information that we don't need. So JSON API has this idea of sparse field sets, which lets you define what fields you want back. So really all we're interested in is the name for our hypothetical purposes. So if I send that, now I mainly just get the name attribute. I don't have the created or the published or anything like that. It makes for a smaller request, easier to look at, a little more efficient in terms of what you're downloading from the server. So now we can see that these are indeed sorted by name. And you can actually get pretty complicated with this. So here I've got searching for recipes. I want the title and the category. Again, using sparse field sets. Again, we're going to sort by title. But now I've got this new parameter called include. And include allows us to include any of the other entities that are being referenced. So in this case, if we run this, and I also limited it by only two resources. So all these are paginated. I believe the default is 50. Is that right, Gabe? Thanks. He's paying attention. So I'm liberating by 50. And also for the categories, I only want the name. So with this syntax, we can say fields, categories, only give me the name. So let's see what that looks like. Sorry, my little scroll target is really tiny. So here we have recipes. And we have these relationships. So in the category, the data is, so this is in the category, 9 1 F 0 7 3 E F, yada, yada, yada. It's not very useful to humans anyway. But we have included that. So if I collapse this, we now have an included parameter. And that includes any of the categories that are referenced from the entities that we searched. So in this way, we don't have to make two requests. We don't have to get our recipes and then turn around and fetch all of our categories. So there's only one included category here because both the two recipes that we got back were both main course recipes. So it only included one of those entities. Cool. Does that all make sense so far? Pretty basic, which is why I labeled this basic. So now we're going to talk about authentication. This is one of the things that was really, really scary for me. There's a number of different ways you can authenticate with an API. The example we're going to use right now is OAuth. So the general idea with OAuth is you have a specific endpoint that will return tokens, like an access token. In this case, it's OAuth slash token. And this stuff pretty much works out of the box when you install Contenta. I think you have to upload a public and private key, but that's generally about it. So we can see what we get back here. We're actually doing a post now. We're not doing a get request. So we're posting for a token. The grant type is password, the client ID, which is the UUID of a client. The client secret, which is kind of like the client password. The username is admin, and here's my user one password. Feel free if you want to try to hack my local content environment and download recipes for grilled cheeses. And then there's the scope, which is content administrator. I'm not really going to get too deep into this because there's a bunch of great resources out this, specifically for the simple OAuth module. But this is what we need to send in order to get this token. So I sent that. I got this really long token back. It expires in 300 seconds, which is, what, five minutes? So we have our access token, and then we have our refresh token. So five minutes, it's a pretty short period of time. So this access token is going to expire in five minutes. And then after that, it's just not going to be usable anymore. Refresh token has a much longer expiration date. So instead of having to send our password every time, we can just send a refresh token. So I am going to copy this out, switch over. And so the idea here, if you're building a JavaScript application, you would do your fetch for your token, and then you store that locally in objects, in memory or local storage, something like that. And then when you need to get a new token, I'm sorry, I'll back up. Then once you post request, you just include that token, and that'll give you access to do whatever, delete things, add things, edit things. And then when you need to refresh, so five minutes has gone by, it's been 10 minutes, and now you want to post a new recipe. What you would do is send the refresh token that you saved. So in this case, let me replace that. I'll send that. And now I got a new token. And so this cycle just goes on forever as long as you need it. If you're past the refresh token expiration date, then you have to go back and that's when, you know, if you're on a website and it's like, you've been logged out too long, you need your username and password. Most likely the refresh token has expired. Cool. So now let's actually post a recipe. So you see we have all our HTTP methods here. So far we've just been looking at gets in terms of entities. But now we're going to post. So we include the accepting content type headers. It's JSON API. You'll notice now that we have an authorization header. I believe if I send this, it should get rejected. Yep, 403 forbidden because this is the token that I sent earlier. So if I go back to this response, if I haven't been talking for five minutes, this should work. So the general syntax is just a string bearer with capital B, space, and then whatever your token is, we'll send that bummer. Try again. I don't think I copied the whole thing. There's better ways of doing this, especially hitting shift instead of caps lock. I'll try this one more time. Okay, there we go. So we posted a grilled cheese. I guess I should have explained that with the post, we're sending JSON object in the body. This looks very similar to what we got back when we were trying to get a single resource. So these are probably everything that somebody would have put in in like a form or whatever you're using to actually generate the fields that you're sending up. I'm not going to get too deep into that. I do want to show the authorization options. So everything we've done so far was very manual. We were just copying and pasting those tokens. If we change the authorization type, we can just put in a bearer token. And if I paste that directly in there, still copying and pasting, we just posted another grilled cheese. Here's our contentus site. We should have two grilled cheeses. So it's working. It's posted data locally. So there's quite a few authorization options in here. You can just do basic auth, which is filling in your username and password. And it'll take that and it'll encode it into a string and you would send that. There is actually a built-in functionality for OAuth. Actually, we want OAuth 2. And this is just another interface for actually getting that data. I haven't found this really useful because it doesn't handle the refresh token. At least I haven't figured out how to get it to handle the refresh token. So we'll look at other ways for handling that. But you do have these options there. Another one I want to point out is inherent auth from parent. So we can actually set whatever our authentication settings are on the parent request. So in this case, or I'm sorry, the parent, whatever you want to call it, collection, I guess, we can edit that and we could set the specific authorization settings here. So we'd update that. And now any request within this collection using the type inherent auth from parent will actually use that. So you don't have to worry about setting it on every single request. As you'll see in a little bit, you can get a lot of requests in a collection. Okay. Now I want to talk a little bit about variables. So Postman allows you to add variables in pretty much anywhere you can type a string in Postman. You can replace it with a variable. It looks very similar to like Twig syntax, double curly braces. And those variables have different scopes. So just like with our authentication, we had a collection that was handling the authentication. And we said inherent that from the parent variables do that naturally. So you can have there's five different scopes of variables in Postman. You have your global scope, which is, if you remember when I first started talking, I clicked on the content of workspace at the top. Those are specific to the workspace. So if you switch workspaces, your global variables change. And we have collections, which we're looking at the, we had a number of different collections. And then we have environments. So I haven't talked about environments yet, but I will in a second. But an environment is essentially just a group of variables that you can share across collections, across workspaces. I typically use environment settings for like my development environments. So I'll have a group of settings, maybe specific passwords for my local environment, like different domain, maybe my locals using HTTP. So I have a variable for that protocol where our dev servers using HTTPS. So you can have those environments, or those variables grouped together in environments. And then when you run a request, you specify which environment you want to run. And then you have local variables, which we'll get into that. Those are specific to scripts. We'll talk more about scripts. And then you have a data variable. And I hope to at least touch on this, but we'll talk about that in a bit when we get into running a collection. So you can run all your requests together. Data variables allow you to have a different set of variables each time you run that request. And I'll talk about some use cases for that. But it ends up, these various layers of abstraction give you a lot of power in what you can do with Postman. So, real quick, simple variables. Here I've replaced the initial request with a protocol variable and a domain. And Postman has a lot of nice UI touches in it. So if I hover over a variable that I've typed in, it'll tell you what scope it's coming from. In this case, the value of this variable is contenta.test and the scope is environment. And if I screw up the name, it actually, I don't know if you can see, but it turns red. So it's simple to use. NPM install numen-g, so install it globally. It's a node package. And then you can run your collection. So Numen run, Postman echo, this is just an example from the site and you can see it runs through all that stuff. Just to give you an example of what we just did. So I saved these, my collection and my environment outs. And I did that by just going here, clicking export, saves it as a JSON file. Same with the environment. You can go in and edit it. Save it as a JSON file. And then command line, just type numen run. You give it the collection file that you want to run. In this case, I want to run it with a specific environment. So you just pass it the E flag for environment. And if I run that and it just ran all the tests that I had. So it's super, super powerful, super easy to use. And there's a bunch more. I feel like I'm just scratching the surface with Postman. Everything you've seen here is all part of the free tool. Obviously they need to make money. They have pro-level features. One of the main things there is sharing things with the team. Like I said, you can export a collection to get and share it. But if you have the pro version, you can actually share workspaces and all that stuff stored in the cloud. So everybody on your development team can work with it. What other things are there? You can run monitors super easy. So if you've ever used something like Pingdom that's just every so often, it'll ping a site to see that it's getting a 200 or whatever test. You can run a whole collection with a monitor tool. And you'll get reporting back on that. So I set that up for one of our client sites. It just pings their site and lets me know, yeah, it's up every five minutes or so. That's something that if you pony up for a pro subscription, you get more of those monitors, like you get more executions. You're limited by the free account. I recently used this. I wrote a collection for actually doing a very basic migration. So we have a client site that has an event management system. It's an older system. It has like a pretty basic XML feed for all their events. I was able to take that, convert it into JSON and turn it into one of those data collections. And my migration script from a postman perspective was essentially just one, it was like an authentication request to authenticate with the server and then a post request. That looped through all the different entity types. And because I was using JSON API and it had a standard, like Drupal has a standard for what those endpoints should look like, I was able to figure out from the data what URL to post to and was able to migrate like 700 events fairly quickly. And for me being a front-end guy who hasn't written a migration myself, I was pretty damn proud of myself for doing that. May not be the most efficient way, but it worked and the client was really happy with the result. So there's a lot of other things. I'm sure I've missed a ton. But with that, say thanks. Definitely have a couple minutes for questions. I do also want to say that we're hiring developers right now. So if any of this stuff looks interesting to you, come talk to myself. Come talk to Joel in that shirt down there. We'd love to talk to you. I think we're doing really fun work. I'm always excited about the stuff we're working on. We get to work with some amazing clients. So yeah, come talk to me. And if you have any questions, please step up to the mic. I do also have, I don't work for Postman. I'm just a big fanboy. It's been really helpful for me. So I reached out to them and asked them if I could use some of their assets. And they actually sent a bunch of stickers and they're really nice stickers, if that's your thing. So come up and see me. Come visit us at the booth. I'd love to answer some questions if anyone has any. Like these right here? Yeah, well I definitely, I've exported all the collections here as part of my slides. So they're up on GitHub and I'll post a link to that. But I could definitely post the collection for, like I've got one that just creates a ton of entities and one that deletes a bunch. Yeah, happy to do that. Anything else? Somebody's got to have a question. Alright, well thanks for coming.