 Can you hear from the mic right? You can hear me? Okay. Okay. Hi everyone. Welcome to the PHP Meetup. Thanks for coming down and hopefully, hopefully that you came down just for my talk, right? So I'll be giving a Meetup talk on the lessons I've learned from building some APIs using PHP. And a bit about myself, I'm a PHP developer. And I have a GitHub thing here. It's like a social thing for developers, I think. And I do have some contributions to some PHP stuff. You can see that I'm bit active in PHP and Angular stuff. And this is me in San Francisco by the Golden Gate Bridge wearing the same shirt right here. And I've not washed it for three years, I think. I'm just kidding, I washed it. I'm not like the people that don't wash their clothes. So let me just go through the style of this presentation. It's kind of a casual one. First, I'll go through an example, a story of how I built an API and stuff like that. And then I'll go through some of the problems I've identified for this particular API that I helped to build. Then, thirdly, I'll go through the solution that I came up with that may or may not be correct. So it depends on how you view it. So a long time ago, a very, very long time ago, you know, sometimes when you look back at your code like five years ago, you're like, oh, god, did I really write that garbage there? And this is like kind of like a moment down here when I looked at some of the stuff that I written very long ago. So this is my first horrible API. I mean, it's quite bad, I think. But it does its job. So I contributed to this. I don't even know how to pronounce the word. Yeah, so it's like a PHP script which you store the list of servers that you have onto an SQL-like database. So basically, I contributed this part down here which allows you to grab some information from, yeah, just allows you to get some information. Yeah, it just returns you some data. So how you make the API requests is you send it through to this URL. For example, down here, then you do a get request to index.php, then with a parameter type equals JSON. Okay, it's actually quite bad, I think. And then results, you get an ID of one, then some name, then some location and CPU. Yeah, very simple API, very not very useful and stuff like that. So let me just go through some of the three amazing problems that I can find with this beautiful design. So the first problem I've identified is that it has unknown resources. The second problem is that there's an unclear retrieval method. The third problem is that it's not sufficiently useful. So what do I mean by unknown resources is that there's a swarm of pods. So in the Richardson maturity model, swarm of pods is level zero of the RESTful API. So it's quite bad. So let me just see how I can rectify this issue. Let's go through the problems that have us. So of course, before we rectify, we have to identify the issues, right? So let's look at the code here to send requests. So let's see, what's the endpoint? It's index.php. What am I trying to do? Get some information. What's the expected output? Get some JSON data with a list of server information, right? So here I've identified the resource because initially we don't know what is the resource because no way here you can tell whether what the resource is. It doesn't say that you are retrieving a server here. There's no way, absolutely no way you can tell that you are retrieving a list of servers. And we first identified that the resource that we are trying to obtain is servers. Then what are the issues with this design here? It has a very confusing endpoint. It's just index.php. So you just send all your requests to index.php. You don't know whether it's a server. It could be something else. So one of the ways to resolve this is to have a routing system like in frameworks and stuff. They do have that to route your request and then give it a bit nice looking unknown action. Secondly, we need to identify what's the action required to retrieve the server information. And of course, the resource output is also unknown, right? Then of course, identify the resource output. So now I've made a few changes to how you can request it. You do a get. Instead of index.php, now we have the routing system in place. So you make a request to slash servers instead. So you can do a party rewrite to route the request all back to index.php. And it looks like this servers down here. And then it looks nice. So from here, you can see that, at least now I know I'm retrieving a list of servers. Yeah, then what am I trying to do? Get a list of server down here. You can see that it's actually a get using HTTP verbs here. Then what's the expected output? A list of servers, right? So another problem here is that it's very unclear as to how you're going to retrieve the data because sometimes if you don't pass in the type equals to JSON, you're going to get HTML output, which is something that you don't want at all, right? So let's look at the request. So what's the expected format, right? JSON, right? We expected JSON and some, but if I don't pass in the type, it'll give me HTML. Then what do you get? You get JSON or HTML. And do I need HTML? HTML as the API consumer. No, you don't need in this scenario. So how we can see the problems are here is that one of the expectations don't meet reality. If you are using this API and you didn't pass in type, you just get HTML output. It's something very unexpected. You wouldn't want it at all. So we need to identify some expectations of the users before we make certain assumptions. Then of course we need to... The second problem is that it's unnecessary to have HTML output. So we should separate the front end from the API endpoint. And now we have a very clear-cut way to retrieve our server information. So instead of doing the question mark type equals JSON, now there's a better way you make the request to API whatever site it is. Then on the base site, you still get your front end, which is your HTML. So this separates the concern between the API and the front end and then you get a very clear way of retrieving your list of servers. So JSON... And you only get JSON. And you get JSON without passing in type. So the third problem that I've identified is that it's not very useful. It's very useless because you have limited actions. And the data you get back is also quite less. So what we can do to expand these actions available to us is that we... Again, look at the problems here. What can you do? Retrieve lists of server domain purpose, allow users to monitor their servers, right? So you get a list of server and that's really... You can't really, really monitor it, but there's a way to do that later on, which we will say. Can you do anything other than retrieve a list of servers? No, you can't because it's useless. So we've identified its limited actions. We can do things like, hey, maybe we add read single resource. So instead of just having an entire list, we can have just specific one server and maybe we can add in web sockets. So it's like so cool, right? Let's throw in some web sockets. And thirdly, maybe we need to make it not just read only, right? Maybe let them write some data to this API endpoint. So now that we have rectified this, now we have added. Let's just imagine that I've added it into the server. Now you're making a hit, again, API to this side, but now you can retrieve a single user data. So maybe followed by their ID, server slash ID. Very simple, right? Then to create a server, you can just do a post to servers and then pass in the JSON data here, full equals bar. And to monitor your response from the web socket, maybe we have a separate endpoint here. So and then you start receiving, you start subscribing to this web socket endpoint. So now we can do reading of single resource, writing new resources and monitoring servers through web sockets, which is a lot better now, right? Yes, no? I don't know. Okay, so Michael responded, yes. So next attempt of making my API. So now it's a new story now. We have our past lesson learned from this horrible mistake, horrible API there. Hopefully I don't repeat it in this second API. So I had an internship project at ASTAR where we made this chatbot and it's a cute diagram of how it works. So the user messages the Facebook messenger and then the chatbot is down there and like, hey, hey, and then use NLP to interpret some data and then like, yeah, the only part that uses PHP here is the API server, the chatbot uses Node.js, right? So like, you just book the appointments like that. Wow, so natural, so AI, right? So smart. And to use this API, we make a request to API slash version one. Notice that in this new API that we have here, it has glorious versioning of APIs, right? That means I can deprecate APIs with whenever I want and then come up with version three. Just like how Google does it all the time. So here you can retrieve a list of users. Just do a get to users endpoint because there's really a routing system in place in Larabelle framework and models. There's this thing called Eloquent models. People are also known as entity models, entity or whatever it is, right? So in this case, we use all these Eloquent models as our representation of our resources, which is user. Then you can create users, right? Do a post to users, just on, and then you get some data back. So results, you get back a success equals true, which is kind of a bit useless. Because you probably wouldn't be needing it. Later on I'll explain why we wouldn't need this success equals true. Then you have a list of users down here. It's an array with just some users down here. You can see that it's a resource of user because there's this word down here that says users, right? So there's a few issues with this design here I have as well. Firstly, it has a very informal structure. Secondly, there's a lack of data relationship. Third, there's no embedding and linking of data. So the first thing I want to talk about is how the structure is informal. And I don't really like it. It's very weak and informal. And how we can rectify this is let's analyze what we have here. So you have success. So how do you transverse through the user's list? Anyone knows? Anyone can make a guess how you're going to transverse through the user's list? Raise of hands, no? Yeah, probably you can do that. So you look through response, angular, no, square bracket users, right? So this is all good, right? It's very intuitive if you look at it. Yeah, you retrieve true users, right? So how do you know the key is users? Maybe because we are requesting to the user's endpoint, right? So yeah, is this suspicion? No, because you need to know the structure that I have, which means that it's informal. Not everyone knows that I have this structure. Another person might have another structure and all of that. So it's not a very formal way of communicating the design of the response here. So there's a better approach that we can do. Instead of transversing through the user's, because not every time you're going to get users, right? Let's say I get messages. Do I transverse through messages this time? So handling the data would be a bit of trouble. So now instead of putting in the users down there, I put it data. So now you just have to transverse through data, right? It's always data. Then how do you know what is the type of resource you're going to get back? It's true here. Type, it says here, literally it says down there type users. Yeah, and is this suspicion? It's better, but it's still not the best, right? So we aim to be the best of the best of the rest, right? Of the rest, haha, rest. Right, okay. So lack of a data relationship we have here, that's a second problem. So we don't have the relationship presented in the data just now we saw. So let's look at the issue that we have here. So you get this structure, but how do you know like you have certain relationship, right? So of course users would have a relationship with another user or maybe they have a relationship with messages and stuff like that, right? So how do you assess a user's message, for example? So you make a request to users slash one slash messages. But how is this self-explanatory? Like you can't tell at all. Like there's no way you're going to tell. No, so can this be improved? Yes, we can present the relationship data without too much information. So let's do it. Now we have success, messages, type, data, and then relationships. And then relationships is an array that stays here type, messages. Then the reference to this user slash one slash messengers. A lot better now, isn't it? You literally can see, yes, this user has messengers. Very self-explanatory now, right? But can this be improved? Well, it seems good. It seems a lot better now than the initial design that we have. And now the third problem that I'm facing is that there's no embedding and linking of data, right? So it's not self-explanatory enough. How do you go to the messengers? How do you go to users and stuff like that? Then let's look at this piece of data and analyze it again. Where do you go next for users that have an ID of two? You can't tell, right? So if I say I want to go to users as ID of two, this is a relationship that is outside. And then I only just say one, right? So can more relationship data be presented? Of course. Is that pagination? No. So you can't, not a big problem is that without embedding and linking of data from one page to another, you can't do pagination at all, right? There's like, okay, how do you know this is the maximum number of users we have? So we can solve that very easily by embedding the relationship in and the links from first page to second page and all that stuff. So let's take a look here. Now we have a lot more metadata here. So these are metadata that's very useful to us, like for example, page, first page, last page, and account. URL, the current URL, the next page, which we can transfer to, list of data. And then now you notice that the data is an array that contains all your resources. And inside each resource, you have attributes and relationships. Isn't it a lot better now? It's so beautiful. You look at it, you're like, oh man, I'm going to marry this structure already. We're going to get engaged tomorrow and then host a wedding or something. Yeah. So I envision a future where you can marry a robot, but this time you can marry an API. Yes. Maybe next time you have like, you just make a post request to this marriage endpoint and you get married. Right. So where do you go next? For users that are ID2. It's very style of explanatory here. You can see, you can observe their relationships here. Each resource has their own individual relationship. And then can more relationship data be presented? It's already been presented here. At an account which lets you know how many messages this user has. At a glance of view, you get to see a lot of things about these users already. And is that pagination? Yes. You can do pagination using all this data that we have. Right. Very useful API. I love it. You love it. Yeah. So the question now is, what makes an API design great? Right. So I believe that, you know, just take a look at this picture down here. It's some furniture and some trees and some chairs and stuff. And you know, basically these furniture are the date version of the trees outside. Anyway, so my point is that when you take a look at this picture, it looks beautiful. Or at least to me, I think it looks beautiful. It looks great. Like it's a house that you want to live in, but it looks expensive as well. Anyway, of course, there is a cost to great API design. And of course, nothing comes for free, right? And when you look at the API design, when it looks great like that, you know it's great. It's really simple, right? So tools that can make your house or your API become as beautiful as that, right? Firstly, I think frameworks help a lot in building APIs. You can also don't use frameworks and still build a great API. Like for example, I'm in love with Laravel. Symphony is pretty great too. I mean, Laravel builds on top of Symphony and Zen does have its own benefits as well. Of course, there's CakePHP, CodeInnector and all of other stuff. Because what's so great about these frameworks is that it helps with do a lot of things that you have really done, like routing, firstly your routing and stuff is really done for you in frameworks and entity and models are represented using your user database and all that stuff already. So there's a lot of scarf holding for you already. Then the second thing that can help you is specification. So there's this specification called JSON API. You can literally go to this site called JSONAPI.org and there's a specification for building APIs in JSON. There's other specifications as well such as HAL, which is a hypertext application language. I think something like that. So yeah, these are specifications that can help you organize your structure. So this is one way which helps make your API very formal. If let's say you look at an API and the structure tells you that this is JSON API, you straight away know how to do the querying. You know how to do the posting and everything. So a specification is one way to help to formalize the way you communicate your APIs. I did give a talk on it previously. Then of course turn. Let me show you a quick demo of what I've done. So I have this, let me run this thing down. Oh wait, this is not. Okay, so wait. So let me just serve up this API. So I have this server running behind in the scene. So it's a very basic application here, API. So we can do like very simple things like logging in, retrieving of users, retrieving of campaigns as well. So right now, I can log in as a admin user. I'm logging in as an admin user. So right here, right now you can see that I'm doing a request, a post request to JSON web tokens. To this resource endpoint called JSON web tokens. Then I'm creating a JSON web token for myself. Right, so as you can see, it passed me back a 201 creator. So making use of your status codes, you no longer need to use things like success equals truth. You can make full use of your status code really. So from 400 to 500 status code, you know that there's a problem that it's suddenly going to return you some form of error. So down here it returns me a data type, JSON web tokens. Then the ID is the ID I'm going to log in with. So it returns some other useful data as well that I wanted to return. It's all defined within a schema that I have. So let me just get users. So now I can retrieve a list of users without log in. I didn't pass in the JSON web tokens, but you can see when I log in I can retrieve type users, all this yeah, all this information. So all this information are included by default in the schema. You can of course modify and also request additional data to be included in the schema according to the parameters. And what's so great about this is that if you want included data so although you have the relationship here, it's just relationship. But if let's say you want the whole resource like this this are called included resources that has a relationship with the user. Right, you can see there's a relationship with this user down here, that's why it's displayed down here and I've included it as default. So one thing you'll notice is that you can't see their email addresses and that's where authorization takes place. Right, authentication and authorization. So now I log in as a I try login as an admin and displaying the data. This time I'll be able to get their their email addresses. See, now I can start spamming them with emails like sign it up for like spam mail and then email them every day and annoying them about how beautiful my API design is. Another thing is that I can I have these other endpoints which is called campaigns I think so you try to get it you can't wait did I type something wrong alright I think it's companies is it? No, let me just check what I do here. Look at this horrible code I have down here so campaigns, yeah it's campaigns so yeah so I send a request to campaigns you see it tries to get a campaign and then it's going to return me with an error code where's my status code I can't see anything where's the status am I? where do you see it I can't see oh yeah I missed it so it says here 401 unauthorized because I'm not login so this is the authorization part so it says and then you can see the error that's passing it passed back to me 401 unauthenticated so I know that yes I need to login to be able to view this campaign so let me just login by passing in my token very simple so intuitive so smart I'm a genius I compliment myself all the time right so you have all this included data so yeah so you can see all this included data campaigns and stuff so this is a very simple example of me making use of JSON design and stuff like that and let me just go back to the slides so this is a very simple view of what the what an API usually includes the routing authentication authorization and then you finally wish your controller down there which returns your result in a very formal way informative and you can request for details that you want and details that you don't want why you don't have to request for everything yeah unless you put it in a default right so some of the lessons we can learn from this talk is that expecting written documentation is bad because not everyone's going to read through a documentation before they read their before they start using the API so only doing get is useless yes it's useless so we only APIs are basically not very useful for my first story you can tell and not presenting relationship causes confusion because you don't know if the user has messengers you don't know where to go next and everything else so the good thing that we should take away from is that formal and consistent structures are very good and it's suitable for a lot of use cases and in this case I've shown that it's suitable for mine right so especially in consistency if your API is not consistent throughout the whole place it's going to be hell of a problem right because nobody's going to know how you going to communicate with this API and of course usefulness is important you need to drive it towards domain design and what's the point of having just a read-only API and embedding relationships makes things more self explanatory like shown in my third example so cause there's some non-technical lessons we can learn from it's good to make mistakes because when you make mistakes you gain some experience and you get to laugh at something like yourself look in the mirror everyday ha ha ha yeah you know so another thing we should do is gear towards domain we should design our API according to what the domain requirements are and everything and not just design blindly because APIs can be badly designed and of course give a talk about it right because what's the point of doing all this and then not sharing it nobody is going to learn from it other than yourself I guess so that's the end of my talk and I thank you if you all have any questions I'll be happy to take them