Servoy and publishing REST web services
Servoy and publishing REST web services
Hi, welcome to today’s webinar, where Sean is going to be presenting everything about creating RESTful web services with a server. So how can you expose your business logic to external applications? And that’s pretty straightforward to do in the Servoy. And Sean is going to show you how to do it, share some best practices with you. If you do have any questions during the webinar, then feel free to post them in the questions channel. We’re here to help you out with any of the questions that you may have. And with that in place, good morning or afternoon, Sean and welcome to the session. Good morning. It’s still morning here for a little while longer. Yeah, today we’re doing all about creating RESTful web services. We’re seeing that more and more our customers, particularly those that are software vendors, are needing to expose some of their application logic as a web service. And in fact, we have some customers that are even monetizing this. And fortunately, Servoy has had the ability to do this for quite a long time. And it’s pretty easy. So I’m going to show you the basics, but I’m also going to show you some best practices as well. This is Tech webinar series number, our number 17 in the series, I think, for this year. And we’ll be using this every two weeks focusing on mainly best practices, but also what’s new in Servoy components and modules and things like that. So today it’s best practices about web services. As always, we like to start with demo demo and then do the slides and the overview of what you saw and how to do stuff. So I’m going to jump right into first of all a hello world example. Basically, the very minimal thing you need to do to make a web service. And then we’ll do a more comprehensive example using some example data. Okay, so I’m just going to get right to it. Before I begin, I’m showing you a testing tool for doing web service like on the client side. This is called postman. Some other folks use curl. There’s lots of rest testing tools out there. I like postman personally, but pick your favorite. So what I’m going to start with is simply putting in a URL to my hello world endpoint. And I’m passing in also a name to say hello to. So I’m going to change this from say Sean to he on. And you can see that the payload that’s returned in the response body has the message of whatever I put in there. So that’s sort of the the minimum amount of web service call that we can make. And let’s take a look at how it’s done on the development side. So I’m going to switch over to Servoy developer. And I hit the wrong button there. Take a look at our endpoint. So it’s pretty simple. You can expose any any logic through an endpoint and an endpoint maps to a form. So in this case, my form name is hello world. And when we were looking in our tester, the endpoint here is also hello world. So that’s that maps to a form name. And from there, you can pass in additional parameters. In this case, I’m passing in the name into this. Ws read method, Ws read maps to the HTTP get verb. So in this case, I’m calling a get request. And I’m returning a JavaScript object. So Servoy includes this rest plugin by default. You don’t have to install anything. And to really get started, all you have to do is make a form, call it whatever you want. That’s going to be the endpoint name. And then to do to handle a get request, you create this Ws read method. And that automatically exposes that method as an endpoint on that form name. You can accept parameters in the and they’ll be automatically converted to the arguments of the method. And then you can return a JavaScript object, which will automatically be serialized and returned in the JSON body as the payload of the response. So that’s the very simple example. Anyone can get started. It takes about five minutes or less to create your first web service. Real quickly, I should point out that the way this happens on the back end is that a headless client is launched. And I can sort of show this a bit. Let me make a new tab here and go to my my Servoy admin page. And look at clients. So you can see here that a Servoy headless client was launched for my solution example web services. And that is sort of the the request handler that’s running server side that’s holding all the logic. So it’s a normal Servoy client that’s doing all this. I also forgot to point out that the solution name is also part of the path. So in this case, our solution is example web services and so solution name slash form name and then whatever arguments you want. Okay, so let’s take a look at some more more robust example. So what I’d like to do is expose a bit of I don’t know my CRM application to to the world to be able to do things like create orders list orders look at products etc. So I’m going to start with a very simple request. I want to list orders. So in this case, I’ve mapped to a form orders and I’m doing the get request. So by default, I’m listing all of the orders and I’ve included a bit of pagination here because there could be quite a lot of orders in my system. So you can see this is page one if I go down to the bottom here, the page size is 10 so it’s returning 10. And that’s something that that I built in that’s not it there’s no none of this is a default because you can do whatever you want with with your voice. So I might also want to go to a specific order. So in this case, I’m going to do order 10249 and you can see that I get just one record and that has all the fields for that order. So it’s a common rest convention to be able to point to a resource if you don’t specify anything else you get a list of results. If you do specify some kind of indicator like an ID, you get back a single record. I may want to do something like paginate. So in this case, I’m going to go back to my orders request and I’m going to pass in some additional parameters in the query string like I want to go to page two. So now I’m looking at the second set of 10. You can see that the orders are they start with that 10249 is the first one there’s about 10 of those. So now we’re up to 10260 in my list of order IDs. I could also change the page size if I want. So I could append another argument here. Let’s just do a smaller one. So let’s do three per page. So I’m looking at page two which is really, you know, records four, five, six in the list of results and there’s the three orders. So it’s a common convention to build in some sort of pagination and you can do that pretty easily in Servoy. So another, another thing that’s common will be to, let’s go back to the order detail would be to specify some related information. So for this order, I’m going to include also the order details and I’ve created this argument here. Include in the query string. So you can see that I have now in my order, the order details which are the individual line items or products that were ordered. I could expand that and also include something like the customer. And you can see now. I’ve included the customer in the in the payload of the response. I could extend that again and do something like the employee. And let’s up here. So now you can see the sales rep that that process this order and all the information about that related record. So again, that’s not some sort of built in functionality. I’ll show you how it’s done in a minute, but I’m trying to show you sort of very common constructions in a in a rest request. Some other things that you might want to do is be able to limit what fields are seen. So by default, it’s showing all the fields on the record, but I might do something like. Field equals order date and customer ID. I don’t know. So now you can see that it’s it’s only returning the fields that I’ve specified. And this would also apply to a listing. So if I remove my. My order ID there. Now I get a list of orders, but. It’s only showing those and I could I could concatenate that with any of my other. So I could also go back and say, well, I’m going to include. The customer still. So now I get the order date and you know the customer, but not all the other stuff about the order. So having a flexible API is a really best practice for rest because you want. You want it to be consistent predictable way to get to get a data and remember that your end users are going to be developers so they’re going to want to be able to do things in a flexible way. Let’s look at some other examples. I could. In my listing, I could do a bit of say sorting. So I want to do. Sort. I’ll do sort equals minus order date. I’m using the minus to indicate that it’s descending. So in this case now. I should get. Well, I get the nulls first and then now I’m getting 1998 may. Those are a lot of those. I’ll tell you what I’ll limit it to just the order date. So I’ll do fields equals order date. Now I get them. It’d be easier to see. And maybe page sizes a bit bigger. Okay, so now I get a bigger page size and now you can see they’re going down and descending from, I guess, May and 1998. Again, and users are developers. They want to do things like sort. We may also want to do something like filter. So I’ve included a way to. Append to I’ll remove some of the stuff so that it’s more clear to append to the query something like. I don’t ship. Country equals. Brazil. So now you can see that. Every order here is. Shipping to Brazil so your users probably want to do something. Like filter and. We could. Keep adding additional criteria to our filter. Let’s do I don’t know employee ID. Equals. Four. So now I get everyone in these will have the employee ID for and also. The ship country is Brazil. So it’s good to provide a way to do filtering as well. So let’s take a look at how this works under the hood. I’m opening up a base form in. In the script editor and what it’s done is it’s implemented. You can see the W. S read the W. S update method. So right now I’m supporting W. S read is get. And W. S update is. Is how to update a record. We’re going to do that in a minute. So if you’re not doing that in the first argument. In our W. S read I’m. Right now I’m just accepting two arguments. The first argument. If it’s if it’s a string. Then I know it’s going to be the ID. Otherwise if it’s a more complex option then we skip the ID and that’s just the options. If I do get argument one as an ID. Then argument two would be that that options object. So I’m going to do a little bit more. I’m going to visualize this is to use debugger and one of the nice things about. Serveway is that you can debug even the headless client. So in this case I can set a breakpoint. I can go back to my testing utility and I can. I can pause and take a look. So what I’m going to do is set a breakpoint right here online. 14. I’ll go back to postman and and I’ll just. Send this again. In the debugger in. Serveway developer and I can I could print out say that options object. And so now you can really see how that query string was was serialized. I can print out the ID or there was no ID for that one. But you could see that it’s passing in basically for every. Key in that object it’s. It’s a name and then the values are in an array and they’re always strings. So it’s important to remember that it’s inside an array even though there’s only one because it could be more than one. So you get that array and that it’s going to be a string. So if it’s something like a number you might have to parse that into an integer or something like that. Serveway handles a lot of that for you in most cases. So looking at some of the stuff I did I’ll go back to the design view it’s a bit. Let me let the debugger continue I’ll remove that breakpoint go back to the design view here and have a look at how we did some of this. So if there was an ID I know that I’m doing a single record request so I’m just loading a record based on a pk. Otherwise I’m looking at some of the other options here like the sort the include the fields and I’m just parsing that out of that options object. I don’t want to get too much into the code here. But you could see that you know if there’s a sort I’m actually just sorting a found set. If there’s a filter I’m applying filter parameters I’m only using equals here of course you could be more complex and do greater than less than that sort of thing. So I did the pagination just by moving the selected index of the found set. I think in a very large result set that probably wouldn’t be very high performing. But again this is just an example of a way that you can do it. What’s important to note is the convention on the on the client side should should be consistent like that. But you can see that I’m determining if there’s a page size and if there’s a page number parameter and if there is setting the pagination even if they don’t specify it it’s paginated. So they could request a second page that that keeps the the payload size small. So finally you might notice I’m calling this method serialize a lot. And I made a sub routine on how to serialize a record and this is really any record. And basically what it does is it if the custom fields weren’t specified it gets all the fields in the table and just puts them in. I did a bit of date formatting. You know that could be something that you build in that’s a configurable. In this case I had a hard code a date format. If they include related data I’m getting some mapped relations. So for example when I specified that the order was going to include the details. I actually in my orders for my over road this method. Which just returns you know basically customers orders to customers employees is orders to employees etc. So that’s how I mapped in what the real relation name is and if they if they did specify to include related data then I’m just getting a related found set and iterating over that. So again I don’t this will be included as a as a sample solution export that will attach to the form topic for this. So you can get it all the code but I just wanted to show that. Yeah it doesn’t take too much work to create like a really common convention and and keep in mind what I did is I put this in a base form. So when I go to my orders form and I look at the code all I did was override one method. So that that orders resources automatically exposed by inheriting from a base form. And I’m now able to override stuff and put the custom things for that order in this case just what the relations are going to be called. So if I look at say another resource. Let’s do products. I can list all my products simply all I did in developer was create a products form which has nothing in. Nothing in the code other than again mapping relation names. And if I go back to here is already supported because of form inheritance and I can do things like products and include equals. I don’t supplier. Think I put supplier in there. Yeah so now I get this supplier included there so again I keep common convention across all of the endpoints and it’s pretty easy to implement that way. Let’s take a look at how we might this is all so far been gets so just reading data out but of course a web service might do something like to update a record or create a new order or something like that. So let’s take a look at that. To create something or to update something results in a different. Starts with a different HTTP verb. I’m going to give you an example where a record existing record is updated and that’s usually done with an HTTP put which maps to a method of. So let me. So. I’m going to change it from Germany to USA and we’ll change the freight from 125 to 999 and send it. So now you can see that the freight and the ship country were updated I didn’t have to put the whole record in just the fields that I want to change get updated. So what does this look like a developer again I’ll just go back to my API base form you can see I have a Ws update method that’s by naming convention that exposes that resource to the verb HTTP verb put and whenever you handle a put or a post which maps to updating a record or inserting a record. So that’s the first argument is going to be the payload that’s the response body the second argument will be in the third argument is that it will be whatever else was included. So in this case the payload is that that Jason body what’s what’s great is that the Servoy rest plug in automatically de serializes that input and gives you a JavaScript object. So if I wanted to I could I could even put some type in the JS doc here and it’s ready to go with code complete. In this case it’s a simple object with name value pairs for the the columns and the values so i’m doing this in a generic way first I load records based on the ID and I get a rate over the properties in the payload and I set it in the record and then I say the changes. So I’m going to turn again I use that serialize method and I serialize the record back and return it into the response. So so updating a record looks something like this the payload is in the first argument. Couple other topics I want to show you one would be error handling. So I want to say I wanted to update a record that that didn’t really exist so i’m going to put I think record 123 doesn’t exist. You can see that I get an error here no record found for ID equals 123. So it’s it’s a best practice in in rest web services that you give consumable errors back that you don’t just return an HTTP error. So if I were to get it like a 404 not found that that’s more of an HTTP error that that this URL didn’t resolve to anything that was found and that’s not quite accurate. What we really want to do is is give the programmer on the other end something they can consume and parse and then they can be able to handle that a bit better than if they just got a generic HTTP error. So quickly back in the code here you can see that if I didn’t get a record i’m returning this this error here with a message so it’s consumable and that’s just that’s just part of a common response. Let’s take a look at one final one final topic. I’m going to I’m going to insist that my my service be what I’m going to say secured so that I’m using security. So what I can do is pass the username and password in as well so if I were to go to my my example here and add authorization i was looking for it there it is I can do basic off and username and password i’ll do admin admin or something. So the by the by design the HD the rest plugin on server side is allowed by default it’s not it’s not authentication required. You can make it that authentication is required and we use what’s called HTTP basic authorization so username and password this gets sent in the header so you can see that actually in the header. There’s the the hash password in the and the username here and that gets sent to the server and so. There’s two ways to handle the server side one is just with Servoy built in security so if you do nothing it’ll it’ll use the built in security the users and groups and passwords and stuff. A lot of people don’t use that they have their own custom security so we provide a way for you to do custom authentication as well and basically if your endpoint implements this naming convention Ws authenticate which i’m going to rename. By by simply implementing that method I now am requiring that this resources protected and and then must pass through this authentication method before any of the other Ws XYZ methods are called so now all i’ve done here is is print out username and password but if I go back to post man and send this request now. You’ll see that I printed out admin admin in the console here by returning true i’m allowing authentication if I throw an error or return return null or false. I’ll send this request one more time in this case I really get a 401. Unauthorized HTTP code so and and that’s kind of the way you want it you don’t even want to get a response if they’re not authorized they’re not entering the service at all. So again that’s pretty easy to do you just implement this Ws authenticate method and automatically that gets that intercepts the Ws XYZ method so they never get called unless that returns true. Okay we’re getting close to our allotted time i’m going to switch over to a few slides to recap what we just saw because we’re moving pretty fast. And then we’ll get to questions so we’ll take a look at the basics about how to map verbs and resources how to consume parameters how to consume a payload how to deal with that authentication and also take a look at some best practices. So just remember that the web service plug-in ships by default you don’t have to install anything you saw the hella word example all you have to do is is follow the naming convention and automatically exposes it. It’s handled by a headless client so launches the headless client and that’s the that’s the the session that that handles requests. Here’s a quick reference of and this is available through documentation of how a HTTP verb is exposed Ws read forget Ws update for put is the examples that we saw. Remember that a form becomes an end point so any form that has one of those Ws underscore methods is now exposed and the URL looks like this it’s your host and then this serve-boy service. I think I had these backwards rest. That’s not right there’s an error in that slide. So it’s a really simple here so it’s serve-boy service rest underscore Ws then the solution name and then the form name so that’s how the resource maps. I’ll fix the slide before I share them. If you want to consume parameters there’s two ways to do it one is directly in the path so in this example here you can see that when I wanted all orders I didn’t have a parameter but as soon as I put that slash 123. That becomes the first argument. If I were to do slash 123 slash details I don’t know let’s say I wanted to get the items in an order then that becomes the second argument so anything after the end point with slash is becomes argument one argument two argument three unless there’s a payload if there’s a payload and that’s for put and post then that’s always the first argument then all the other slash. is the last is the path become the subsequent arguments. The second way to consume arguments is in the query string. So we saw with the pay the pagination page sizes we saw with the filtering the sorting whether or not to include relations or field names. That was all done in the query string. The query string gets mapped to a single object and it’s always going to be these name value pairs where the value is always in array of strings because there could be multiple values for. For a single argument that’s why it becomes an array. So that the it’s your job to parse that it’s pretty easy you just do the name value pairs you can split on on commas that’s what I was doing for for some of those. For puts and posts you actually get a payload on on the request so you saw in the example where I was updating the order you get that and it gets automatically gets serialized to a JavaScript object so. So you’re able to handle handle that almost just like native programming. You just bring it in and start programming against it now that’s the first argument is always the payload so you can see in the little example down below the second argument is the ID. If we look at that URL it goes orders 12 the 12 becomes argument to because the payload is argument one because it’s a put or it’s a post. For authentication we saw that that basic is well the rest plugin uses HD to be basic authentication. This is not the slide is messed up there we go I’m sorry. Basic authentication by default. So if you do nothing you can specify that a solution requires authentication using built in security. Most people use custom security and you just have to do that Ws authenticate method and everything goes through that. Okay best practices. Number one is important remember that rest is meant to be a stateless transactional kind of service so. You shouldn’t build in although you could you shouldn’t build in any dependency on any cash state maybe with the exception of for your authentication if you want to cash some tokens for the different clients and then expire them etc. That would be maybe one thing where you do stateful but everything else should be stateless and every transaction should be as brief as possible. Remember to manage concurrency incoming requests are put in a queue and so that had this client that that we saw that was launched is really sort of a single queue and you can scale up concurrency by increasing one of the plug-in settings the pool size. Real quick that’s on the. So if you look at server plugins you can see that the pool size you could put here so if I wanted to have a hundred queues available meaning I don’t have any wait time until I have more than 100 concurrent requests. Then I could launch 100 headless clients to do that so that’s the pool that’s the max pool size and it’ll it’ll add them as needed it’s not like it’ll automatically launch and leave 100 headless clients there. By the way if you’re doing basic are if you’re doing built in security you could just say you know only the administrators group has access to the service or you know something like that so you can put in a common it delimited list of groups. So if you’re a server to version your API and it’s good to build that into the first version so that as soon as you want to start deprecating and changing things and you will that the next version there’s already like a semantic for doing that and the best practices is to do that directly in the URL. So this is a form inheritance that makes things easy to separate generic logic from specific logic also it’s good for versioning too if you wanted to have sort of I was using you know orders and products and forms like that. But you could actually have your endpoints be a different version number and then one good and hair at the other and just override that. For that as well. Remember to to return consumable error messages when you when you encounter something and always do things with try catch and handle you know errors that you might expect like if they don’t if they pass in a ID that you don’t find something because it’s it’s no fun when you’re a programmer to just receive some you know error 500 code or something HTTP error and you don’t know what happened. Just remember in your conventions that rest is a resource based not an action based so think now not verb. Kind of paradigm so good way to do things would be you know I want to do something with orders I want to do so many orders for the ID is 12 etc. You want to avoid things like you know get order details create order you know where it looks like you’re having a method name that really goes against the rest convention. And remember to support for data access remember to support the things that we saw in the example list detail switching between those two easily. And then you’re getting allowing users to customize which fields they want to see allowing users to extend the results to include different kinds of related data sorting filtering and even maybe more advanced searching. Okay we’ve reached the end I’ll leave these useful links showing and I see that we have questions coming in on. So I’m going to ask you about the question. I’m going to ask you about the question. Yes, just a few because we are a bit light. Yes. There’s a comment from Bob which I think is correct that’s on one of you early slides where you look at the arguments you’re passing to arguments using a question mark and the second argument probably shouldn’t be through a question mark. Yes, that I was doing this late at night and right before the webinar. I’ll fix the slides up and prove from before I post them on the forum. Yeah, and I think when you’re error message there’s a missing code. Okay, also on the slide. Also on the slide. Yeah. Okay. There’s a question from Imra. What is the best practice to protect the application after login. Is that the mentioned. Okay. Okay. What other strategies can be used to build security. Right. So, remember when you get custom security. Well, I should back up. The plug in by default does. What’s called. HTTP basic meaning every request will have in the header the HTTP basic request header which includes a username and password. Now, when you implement that. Ws underscore authentic 8 method. What you do inside that method is completely up to you and basically you can return true or false. So pretty much every request that comes in. Should have the username and password. But what you could do is once you authenticate the user you could cash a token. And and and keep returning that. And they could send a token. It’s a bit difficult to build that yourself because it’s really based on. On the. The basic authentication we’re using in password comes in every time but you can do whatever you want in that method. It’s not like you have to every time say. Is this a new is this you know this is a new request every time. Let me look up the user and password. You could you could say okay there’s also a token in the payload and or in the query string or whatever. And then. You can you can just go and look up that token in memory you know that expires at some time or even it’s written to a database. So it’s totally up to you what you do inside that method. Cool. And one final question. How about consuming of observers in server. That’s. We were going to do that in this webinar and then once I started working on this I realized that we’re probably going to go long even with just producing a web service. So we’re planning that for a follow up webinar on consuming a web service and also using in memory data sources to to work with with a web service so maybe. We’ll be doing that quite soon. Thank you.