Joel: Welcome to No Compromises. A peek into the mind of two old web devs who have seen some things. This is Joel.
Aaron: And this is Aaron.
Joel: I really like writing APIs and it's not just because I don't like CSS. But one of the things I thought we could talk about today is the idea of having a formal API specification document. As developers, we enjoy when we're consuming an API, Stripe, whatever, they have documentation and they have a spec and you know what fields are required. But I don't see it a lot on Laravel projects, especially APIs for internal use only. And I think there's a benefit in having it so I just wanted to kind of throw that out there as a topic, get your take on it and kind of talk through our reasons.
Aaron: Yeah. It's funny because you bring that up and then a lot of times we'll be, as developers, like, "Ah! This API doesn't have good documentation. It's crap and I have to figure it out," blah, blah. And then when it comes time to writing your own, you're like, "Well, no, I mean... I don't."
Joel: Yeah. Just look at the code.
Aaron: "No time to do that." Yeah, just look at the code. They don't have time to write a doc. If you have access to the code, you have access to the docs.
Joel: The code is documentation. I mean, it is. But are you at least with me on the premise then that we should-
Aaron: Very much so.
Joel: ... that it's beneficial to have documentation.
Aaron: But tell me why.
Joel: I will tell you why. So I can think of a couple of reasons, maybe I'll start with the first one which I consider more non-obvious. Which is the act of formalizing your specification, writing it out. And I would just say writing it out before you build it, this is going to be key, it forces you to think through the API requirements in a more diligent way than if you're just going to sit down and start like, "All right, here's a resourceful controller, I'm going to write some form requests." It's an extra step of thought before you dive in. And I have found that very beneficial, especially with a client, where they're asking you to build this API endpoint and they've maybe even given you some requirements, but there's always something not specified, so writing that initial specification sort of surfaces a bunch of questions that might not otherwise get asked.
Aaron: It reminds me of many years ago when I joined the company that had a really large programming team and they had a lot of these systems in place. I was a very young programmer, and they would require us to do design documentation before every single ticket. So once you had quoted the project, then the next step was to actually pull out a document and just write up what you were going to do, what the risks are to your changes, et cetera. And then you give it to the systems analyst to get approved before you start doing your work. And at the time, I felt that that was super annoying because I'm a young developer and I have lots of spirit and go-get-em attitude, and I don't need any of this process. And looking back, I think there was so much benefit from doing that, but some of the stuff still felt a little kludgy. So I think the API documentation is a nice middle step, and I think you'll probably get to this because they're documentation. But they're not just documentation for one party, they're useful in many different ways.
Joel: Absolutely. I'm just kind of curious the design document that's more like software design, right? It's not UI design.
Aaron: Yeah.
Joel: But it's like, "Here's what I'm going to build and what sorts of files I'm going to use to build it," and stuff like that. Right?
Aaron: Mm-hmm (affirmative).
Joel: Maybe it would be good to pause and talk a little bit more about what's in a spec. Just if somebody's listening and they've never written one, maybe they've only consumed the HTML-generated version of somebody else's spec. But at a minimum, it's going to specify things like, what are the endpoints? What is the URL? Is it a GET? Is it a POST? Does it have parameters? Are those parameters headers? Are they in the path? Are they part of the query string? Are they required? Are they optional? What are accepted values? And that's more on the input side and there's more. Obviously, if it's a POST that has a form body, each one of those fields is going to have a level of specification. Is it a string? Is it a date time? What is the format? What's the maximum length? I could just keep rattling these off. But there's also, on the response side, what could I get back? Well, you know a lot of times we're like, "Well, you could get a 200 back." Like, "Okay, good. What if I don't have a token?" "Well, then you get a 401." "Okay, all right. What if my user isn't part of that project I'm updating?" "Oh, you get a 403." But you see what I'm saying, most endpoints are going to return multiple responses. Maybe a 404, maybe a 422. I mean, we even specify things like, "Is it 405 if you try to POST?"
Aaron: 406.
Joel: Well, 406 is the media type one, right? This is riveting, like numbers is.
Aaron: Yeah, this is the same.
Joel: But anyways, there is different things like, "Hey, this is a JSON endpoint, you didn't send me accept JSON," or, "This is a GET endpoint, you sent me a POST." But anyways, these are all different types of responses. And Laravel takes care of a lot of those for you, you're not manually constructing a 422 and returning it. But if you have a form request that fails validation, it's going to return that and it's going to have a certain shape to the payload and just... But I'm scratching the surface, but you can see kind of going through this checklist, like, "Well, could it return this? In what scenarios?" It's going to trigger a lot of conversations that might not otherwise happen. So that's where I see some value and I think we're on the same page there.
Aaron: Well, let me argue against that real quick though. Because, again, living in the real world, that seems like a lot of work to do ahead of time when maybe your requirements are not fully fleshed out. Like I said, it gives you questions to ask but at some point, the client's going to be like, "This is too much in the weeds. I don't know the answer to that," or, "I don't care what the maximum length of a first name is, so why are you asking me that? It can be forever long, I don't care."
Joel: You're right. There are going to be... It depends on who your client is. If it's a technical stakeholder, they might. I'm just thinking of a project we were working on. They provided, like, "Here's the database schema that this endpoint is going to use." So a lot of those questions would be answered. But, yeah, the non-technical business owner, "I don't know, like a hundred?" for a first name. So you're going to have to fill in some of those answers for them and maybe get them to validate it for you. But I agree, you don't want to spend a month to write an API spec for a simple endpoint that's going to take you half a day to build. So there is a balance there as well. And I would just counter because I think one of the resistance points for something like this is it is going to take a lot of time. The first one you write will. But honestly, it's a lot of copy-pasting. And there's tooling, I haven't found a tool I really like. But it isn't that hard to write a spec, it's a YAML document. And it's got some basic structure to it and there's even things for code reuse. So you don't have to specify the full payload of a 422 in every one of your endpoints, you can define it once and reference that in your endpoint. So there's ways to make this not a huge ordeal. Let's shift gears a little bit. The second half of that is the person consuming the documentation. Now, I sort of set up-
Aaron: What's the use of this? That's a good question. It's been all written up, maybe it gets approved, and then what?
Joel: Okay. Let's put aside any value you derive from the exercise of writing it to help you shape the requirements. Maybe you don't care about that. What are the other benefits? Again, I'm going to stay focused on an internal API. We're not building Stripe, we're building something that our own front-end, or mobile app, or whatever, is going to consume. I'm even going to go a step further. Let's say you are the person that's going to implement it. So you're not handing this off to some other team. I'm trying to take out a lot of reasons to ignore this, so it's-
Aaron: So you're doing the front-end and you're doing the back end?
Joel: Sure. And let's just-
Aaron: They're possibly different stacks that don't play well together for whatever reason.
Joel: Maybe, right. So because I think most people would recognize, "Oh, if there's another team building the front-end then, yeah, there's some more value for the spec," but that's not my case. Let's just say you're doing both sides of it. Having the spec keeps you honest when you're building it. So we will use some tooling. I can't remember the name of the package, but in our feature tests, when we're making requests and getting the response and asserting against it, you can make assertions, "This response adheres to the open API specification." You can also do that for the request. We've had a little bit of challenges doing that universally but the same thing exists there. Where the request that's being sent in also is something that the spec says is valid. And that has huge value because there's, especially with two separate code bases like a mobile app and a API, you don't ever want to get out of agreement as to what something should be returning. And if you're shipping an update to an API and you think, "Oh, I'm just adding a field here," but you actually broke something else. You would want to know that before it makes its way into production. And that specification is the basis for a whole bunch of fairly simple tests that can be written in your existing feature tests to catch deviations like that.
Aaron: So it really sounds like when you're working with internal APIs, the spec is definitely in the form of a contract or a PHP interface when it comes to the value for the internal API, is what you're saying. Like, if it's external, we are obvious we have to document it for people and we get that. But internal, it's more like, "Well, I want to start programming with interfaces when necessary, and so this is a step in that direction," but for APIs.
Joel: Sure. I hadn't even thought about the implementation details of it. Is that what you're talking about when you say interface, you literally mean a PHP interface?
Aaron: Yeah.
Joel: That's true. You could write interfaces that adhere to that. I'm just saying if you agreed that this endpoint is going to return a 201 versus a 200.
Aaron: Oh. I mean, conceptually.
Joel: Conceptually, okay.
Aaron: The idea is that this is an interface class in PHP to your service or you know.
Joel: Yeah, exactly. And it keeps you honest. So with a literal interface, if you don't satisfy part of its contract, you're going to get an error in PHP with your feature tests. If you deviate and you start returning a 200, when you said it was going to be a 201 it will catch that and your test will fail, and you can fix it. And if you really do want to change it, then you can change the spec and whatever mechanism you have to update the front-end at the same time. That's fine, it's not written in concrete. But it's a conscious change you're making versus, "Oops." Or maybe you update a package that's helping generate your responses or Laravel changes something. These are all things that will enforce your contract with a front-end. So I can tell, Aaron, I've convinced you that this is a valuable thing to do.
Aaron: There's lots of convincing required.
Joel: I'm laughing because you're probably the first one who made me do it, but I'm here like, "Yeah, this is my idea." But anyways I think it's worth considering. And if you've never done it and you're listening to this, I'd say give it a try and I think you will find value in it.
Aaron: Cool. I don't know if you're like me, which you're not, but if you go to a hotel-
Joel: Some ways I am.
Aaron: ... go to a hotel or get an Airbnb or something like that, what's the first thing you do when you enter?
Joel: Take my shoes off?
Aaron: Okay. So we're definitely different people. The first thing I do when I enter a strange place like that... And mind you I grew up in the late 90s, early 2000s, so a lot of how I make decisions was based on the culture at the time. There were a lot of scary movies.
Joel: Oh, you check up behind the shower curtain.
Aaron: That's literally what I do. When I come to a place I go through each room and I look in every single room behind all the different curtains, I look underneath the bed just to make sure that there's no one in there. Which there never is and there never will be but you just don't know.
Joel: Well, I think looking under the bed, you could see something scary that's not a person and some things are better unknown.
Aaron: No, man. I don't want to be sleeping above that much dirt.
Joel: Well, now I'm going to have to sweep the room myself when I stay in my next hotel.
Aaron: Oh, because of all the dirt. Nice. Joel's getting really gross with this marketing stuff, he's talking about things like funnels and newsletters. But actually the newsletter, the daily newsletter, it's actually really good.
Joel: If you want to see it for yourself, head over to masteringlaravel.io. The signup form is right at the top of the page.