|
| 1 | +# Restlet Framework Web API Reference Implementation |
| 2 | + |
| 3 | +## Prerequisites |
| 4 | + |
| 5 | +* Maven installed on your machine : [Maven documentation link](http://maven.apache.org/index.html) |
| 6 | + |
| 7 | +> The implementation is located [here](https://github.com/restlet/restlet-tutorial/tree/master/modules/org.restlet.tutorial.webapi) |
| 8 | +
|
| 9 | +> This example uses [Restlet Framework 2.2.1](http://restlet.com/download/current#release=stable&edition=jse&distribution=zip) (Java SE edition) |
| 10 | +and [H2 Database](www.h2database.com) |
| 11 | + |
| 12 | +> Restlet framework user guide is available [here](http://restlet.com/learn/guide/2.3/). |
| 13 | +> You can also clone this repository and go to ```/modules/org.restlet.tutorial.webapi/``` folder. |
| 14 | +
|
| 15 | +## Installation |
| 16 | + |
| 17 | +### Install Maven project |
| 18 | + |
| 19 | +To install maven : |
| 20 | +* Go to the directory |
| 21 | +* Execute ```mvn clean install``` |
| 22 | +* For eclipse users : run ```mvn eclipse:eclipse``` |
| 23 | + |
| 24 | +> For further instruction about running a Maven project : [Building a project with Maven](http://maven.apache.org/run-maven/index.html) |
| 25 | +
|
| 26 | +### Run this application |
| 27 | + |
| 28 | +The main class is : ```WebApiHost.java``` |
| 29 | +By default the application is launched at ```http://localhost:9000```, but you can change it in ```WebApiHost.java```. |
| 30 | +A logger is configured. Its configuration is made in ```logging.properties``` and declared in ```WebApiHost.java```. |
| 31 | +Two files will be created : |
| 32 | + * ```webapitutorial-app-x-x.log``` |
| 33 | + * ```webapitutorial-requests-x-x.log``` |
| 34 | + |
| 35 | +They are both situated in ```/tmp``` folder. |
| 36 | +To simplify the launch of the application, authentication and authorization are done in-memory |
| 37 | +(You should overwrite that with you own authentication system). Here are the login/password available: |
| 38 | + |
| 39 | +* admin/admin : to get admin role |
| 40 | +* owner/owner : to get owner role |
| 41 | +* user/user : to get user role |
| 42 | + |
| 43 | +It uses HTTP Basic authentication. |
| 44 | + |
| 45 | +> Learn more about authentication, authorization and security with Restlet Framework [here](http://restlet.com/learn/guide/2.3/core/security/). |
| 46 | +
|
| 47 | +> You can try this application easily with a REST client like [POSTMAN](http://www.getpostman.com/). |
| 48 | +
|
| 49 | +## Database access |
| 50 | + |
| 51 | +To visualize the database, open the H2 console in you browser (`http://localhost:8082`) and connect to the database with the JDBC URL `jdbc:h2:mem:restletWebApi;IFEXISTS=TRUE`. |
| 52 | + |
| 53 | +## Description |
| 54 | + |
| 55 | +This Web API contains 2 main resources : |
| 56 | + |
| 57 | +* Company : identified by an auto-generated id. |
| 58 | +* Contact : identified by its email. A contact can be part of a company and get a reference to it. |
| 59 | + |
| 60 | +This is a diagram of the API : |
| 61 | + |
| 62 | + |
| 63 | + |
| 64 | +> A Web API definition can be generated with [APISpark extension (RF 2.3)](http://restlet.com/learn/guide/2.3/extensions/apispark). |
| 65 | +
|
| 66 | +## Implementation choices |
| 67 | + |
| 68 | + * The persistence layer has been done to be as simple as possible. The aim of this example is to show how to build a reference Web API with Restlet Framework. |
| 69 | + * The API was designed to use meaningful URLs. For example, for contacts the email is used as an identifier instead of a technical id (which does not mean anything for a user). On the contrary, for companies an autogenerated id has been chosen. |
| 70 | + * There is not POST method for contacts as a contact is defined by his/her email. To add a contact, you must do a PUT on ```/contacts/{email}``` |
| 71 | + |
| 72 | +## Next steps |
| 73 | + |
| 74 | +Here are some instructions to go further with this project |
| 75 | + |
| 76 | + * Persistence layer |
| 77 | + * For each operation a new connection is created. |
| 78 | + It would be useful to use a connection pool like [DBCP](http://commons.apache.org/proper/commons-dbcp/). |
| 79 | + * It is possible to totally dissociate the persistence layer from the Server Resources. |
| 80 | + It would allow the use of several persitence layers. It would also be possible to use dependency injection. |
| 81 | + * Authentication/Authorization |
| 82 | + * It is strongly recommended to store users/roles in a database instead of in-memory. |
| 83 | + You can create a custom [SecretVerifier](http://restlet.org/learn/javadocs/2.2/jse/api/org/restlet/security/SecretVerifier.html) |
| 84 | + and [Enroler](http://restlet.org/learn/javadocs/2.2/jse/api/org/restlet/security/Enroler.html). |
| 85 | + * It is possible to handle autorizations in a filter instead of at the beginning of each class. |
| 86 | + In fact, in this example, there is a repeating schema : Role user needed to access to GET methods, |
| 87 | + Role owner needed to access the others. |
| 88 | + |
| 89 | +## Usage |
| 90 | + |
| 91 | +> These examples are made using the JSON format but you can use XML or YAML if you want. |
| 92 | +
|
| 93 | +### Ping resource |
| 94 | + |
| 95 | +A resource ```/ping``` has been created which does not need authentication. |
| 96 | + |
| 97 | +```GET http://localhost:9000/v1/ping``` |
| 98 | + |
| 99 | + |
| 100 | + |
| 101 | +> For the following examples, Basic Authentication will be needed |
| 102 | +
|
| 103 | +### Create a company |
| 104 | + |
| 105 | + ``` POST http://localhost:9000/v1/companies/``` |
| 106 | + |
| 107 | + ```json |
| 108 | +{ |
| 109 | + "name" : "Restlet", |
| 110 | + "duns" : "123456789", |
| 111 | + "address" : "2 API road", |
| 112 | + "zipCode" : "44300", |
| 113 | + "creationDate" : "2014-01-01", |
| 114 | + "website" : "http://restlet.com", |
| 115 | + "city" : "Nantes", |
| 116 | + "phoneNumber" : "+1 555 555 555" |
| 117 | +} |
| 118 | +``` |
| 119 | + |
| 120 | + |
| 121 | + |
| 122 | +> The returned status is : ```201 Created```. |
| 123 | +
|
| 124 | +The location of the created company is written is the "location" header. |
| 125 | + |
| 126 | +  |
| 127 | + |
| 128 | +### Retrieve all created companies |
| 129 | + |
| 130 | + ```GET http://localhost:9000/v1/companies/``` |
| 131 | + |
| 132 | +> The trailing slash is optional : both ```http://localhost:9000/v1/companies/``` and ```http://localhost:9000/v1/companies``` will work. |
| 133 | +
|
| 134 | + It should retrieve : |
| 135 | + |
| 136 | + ```json |
| 137 | +{ |
| 138 | + "list" : |
| 139 | + [ |
| 140 | + { |
| 141 | + "duns":"123456789", |
| 142 | + "address":"2 API road", |
| 143 | + "zipCode":"44300", |
| 144 | + "creationDate":"2014-01-01", |
| 145 | + "website":"http://restlet.com", |
| 146 | + "phoneNumber":"+1 555 555 555", |
| 147 | + "city":"Nantes", |
| 148 | + "name":"Restlet", |
| 149 | + "self":"/companies/1" |
| 150 | + } |
| 151 | + ] |
| 152 | +} |
| 153 | +``` |
| 154 | + |
| 155 | + |
| 156 | + |
| 157 | +> ```self``` element refers to the location of the object : ```http://localhost:9000/v1/companies/1```. |
| 158 | +> Try ```GET http://localhost:9000/v1/companies/1``` ! |
| 159 | +
|
| 160 | +### Create a contact related to the created company |
| 161 | + |
| 162 | + ```PUT http://localhost:9000/v1/contacts/{email}``` |
| 163 | + |
| 164 | + with ```{email}``` representing the email of the contact you want to insert. |
| 165 | + |
| 166 | + For this example, it is : |
| 167 | + ``` PUT http://localhost:9000/v1/contacts/gblondeau@restlet.com``` |
| 168 | + |
| 169 | + ```json |
| 170 | + { |
| 171 | + "name" : "Blondeau", |
| 172 | + "firstName" : "Guillaume", |
| 173 | + "age" : 22, |
| 174 | + "company" : "1" |
| 175 | + } |
| 176 | + ``` |
| 177 | + |
| 178 | + It should retrieve : |
| 179 | + |
| 180 | + ```json |
| 181 | + { |
| 182 | + "email":"gblondeau@restlet.com", |
| 183 | + "age":22, |
| 184 | + "name":"Blondeau", |
| 185 | + "firstName":"Guillaume", |
| 186 | + "company":"/companies/1" |
| 187 | +} |
| 188 | + ``` |
| 189 | + |
| 190 | +  |
| 191 | + |
| 192 | +> The returned status is : ```201 Created```. |
| 193 | +
|
| 194 | +> The field company is a reference to the location of the company, with 1 the id of the company. |
| 195 | + ie : /companies/1 refers to http://localhost:9000/v1/companies/1 |
| 196 | + |
| 197 | +### Retrieve the list of created contacts |
| 198 | + |
| 199 | +```GET http://localhost:9000/v1/contacts``` |
| 200 | + |
| 201 | +> The trailing slash is optional : both ```http://localhost:9000/v1/contacts/``` and ```http://localhost:9000/v1/contacts``` will work. |
| 202 | +
|
| 203 | +It should retrieve : |
| 204 | + |
| 205 | +```json |
| 206 | +{ |
| 207 | + "list" : |
| 208 | + [ |
| 209 | + { |
| 210 | + "email":"gblondeau@restlet.com", |
| 211 | + "age":22, |
| 212 | + "name":"Blondeau", |
| 213 | + "firstName":"Guillaume", |
| 214 | + "company":"/companies/1", |
| 215 | + "self":"/contacts/gblondeau@restlet.com" |
| 216 | + } |
| 217 | + ] |
| 218 | +} |
| 219 | +``` |
| 220 | + |
| 221 | +  |
| 222 | + |
| 223 | +> The field company is a reference to the location of the company |
| 224 | +
|
| 225 | +To display the company information, add the following query parameter : ```?strategy=load``` |
| 226 | + |
| 227 | +```GET http://localhost:9000/v1/contacts/?strategy=load``` |
| 228 | + |
| 229 | +It should retrieve : |
| 230 | + |
| 231 | +```json |
| 232 | +{ |
| 233 | + "list" : |
| 234 | + [ |
| 235 | + { |
| 236 | + "email":"gblondeau@restlet.com", |
| 237 | + "age":22, |
| 238 | + "name":"Blondeau", |
| 239 | + "firstName":"Guillaume", |
| 240 | + "company": |
| 241 | + { |
| 242 | + "duns":"123456789", |
| 243 | + "address":"2 API road", |
| 244 | + "zipCode":"44300", |
| 245 | + "creationDate":"2014-01-01", |
| 246 | + "website":"http://restlet.com", |
| 247 | + "phoneNumber":"+1 555 555 555", |
| 248 | + "city":"Nantes", |
| 249 | + "name":"Restlet" |
| 250 | + }, |
| 251 | + "self":"/contacts/gblondeau@restlet.com" |
| 252 | + } |
| 253 | + ] |
| 254 | +} |
| 255 | +``` |
| 256 | + |
| 257 | +  |
| 258 | + |
| 259 | +### Modify an existing contact |
| 260 | + |
| 261 | +```PUT http://localhost:9000/v1/contacts/gblondeau@restlet.com``` |
| 262 | + |
| 263 | +```json |
| 264 | +{ |
| 265 | + "age" : 23, |
| 266 | + "name": "Blondeau", |
| 267 | + "firstName": "Guillaume", |
| 268 | + "company": "1" |
| 269 | +} |
| 270 | +``` |
| 271 | + |
| 272 | +It should retrieve : |
| 273 | + |
| 274 | +```json |
| 275 | +{ |
| 276 | + "email": "gblondeau@restlet.com", |
| 277 | + "age": 23, |
| 278 | + "name": "Blondeau", |
| 279 | + "firstName": "Guillaume", |
| 280 | + "company": "/companies/1" |
| 281 | +} |
| 282 | +``` |
| 283 | + |
| 284 | +  |
| 285 | + |
| 286 | +> This time a ```200 OK ``` is returned because it is not a creation but an update. |
| 287 | +
|
0 commit comments