Changes for page Your First Rest Project

Last modified by Steve Peery on 2013/09/06 11:02

From version 27.1
edited by Filippo Laurìa
on 2013/07/22 12:51
Change comment: There is no comment for this version
To version 19.1
edited by skcodes
on 2013/05/13 12:53
Change comment: Migrated to Confluence 4.0

Summary

Details

Page properties
Author
... ... @@ -1,1 +1,1 @@
1 -XWiki.filippolauria
1 +XWiki.skcodes
Content
... ... @@ -1,5 +3,3 @@
1 -
2 -
3 3  {{toc/}}
4 4  
5 5  = Introduction =
... ... @@ -122,8 +122,6 @@
122 122  
123 123  The model should show up in a window that looks like this:
124 124  
125 -[[image:attach:EOModeler.png]]
126 -
127 127  If it didn't show up, the window might have opened behind the main Eclipse window. If that's the case, open the **Window** menu and select the windows that have //Entity Modeler// in its name.
128 128  
129 129  In the Entity Modeler window, click on **Default**, and for the **URL** field, type
... ... @@ -185,12 +185,8 @@
185 185  
186 186  If you did everything well, the list of attributes should look like this:
187 187  
188 -[[image:attach:list_wlock.png]]
189 -
190 190  You will notice that the attributes have a column with a lock in it. When a lock is present, it will use the value of that attribute for //UPDATE ... WHERE attribute = ''// statement. This is to do optimistic locking, aka to prevent data conflict when the data object was modified by two different users. Using timestamps for optimistic locking is not a good idea because for certain RDBMS, the value can be different because of milliseconds, so remove the locks on the **creationDate** attribute. The final list should look like this:
191 191  
192 -[[image:attach:list.png]]
193 -
194 194  Next step is to create the **Author** entity. Create a new entity with **Author** at its name (and also as the table name), and for the class name, use **your.app.model.Author**. The attributes for this entity are:
195 195  
196 196  |=(((
... ... @@ -224,12 +224,8 @@
224 224  
225 225  Final list of attributes should look like this:
226 226  
227 -[[image:attach:author_list.png]]
228 -
229 229  Now, it's time to link the two entities together. An Author can have multiple blog entries, and a BlogEntry can only have one author. To create the relationship (the join), right-click on **Author** and select **New Relationship**. On your right, select **BlogEntry** in the list. On your left, select **to many BlogEntries**, and on your right, select **to one Author**. Now, in BlogEntry, we need to store the primary key of the author so that we can make the join. The relationship builder allow us to add that attribute, so make sure **and a new foreign key named** is checked (it is checked by default). The **Create Relationship** pane should look like this:
230 230  
231 -[[image:attach:relationship.png]]
232 -
233 233  If you check in the **Outline** tab, you should see that **Author** now have a **blogEntries** relationship, and **BlogEntry** have a **author** relationship.
234 234  
235 235  You are now ready to save the model. Save it (File -> Save) and close the **Entity Modeler** window. If you open the **Sources** in the main Eclipse window, you will notice that the **Sources** folder contains a package named **your.app.model**. (If this folder doesn't appear, you may need to set your preferences to automatically generate these source files; see the second suggestion on [[http:~~/~~/wiki.wocommunity.org/display/documentation/Useful+Eclipse+or+WOLips+Preferences>>url:http://wiki.wocommunity.org/display/documentation/Useful+Eclipse+or+WOLips+Preferences||rel="nofollow" shape="rect" class="external-link"]].)
... ... @@ -239,6 +239,7 @@
239 239  What we are going to do is to write a simple method that returns the full name of an author, e.g. a method that simply concatenate the first name, a space and the last name of the author. To do so, double-click on **Author.java** and add the following methods:
240 240  
241 241  {{code}}
230 +
242 242  public String fullName() {
243 243   return this.firstName() + " " + this.lastName();
244 244   }
... ... @@ -248,6 +248,7 @@
248 248  Nothing fancy here. Now open **BlogEntry.java** and add the following method:
249 249  
250 250  {{code}}
240 +
251 251   @Override
252 252   public void awakeFromInsertion(EOEditingContext editingContext) {
253 253   super.awakeFromInsertion(editingContext);
... ... @@ -277,6 +277,7 @@
277 277  Remove the pound char in front of those two properties:
278 278  
279 279  {{code}}
270 +
280 280  #er.migration.migrateAtStartup=true
281 281  #er.migration.createTablesIfNecessary=true
282 282  
... ... @@ -285,6 +285,7 @@
285 285  After removing the pound char, the two properties should look like this:
286 286  
287 287  {{code}}
279 +
288 288  er.migration.migrateAtStartup=true
289 289  er.migration.createTablesIfNecessary=true
290 290  
... ... @@ -293,6 +293,7 @@
293 293  You are now ready to start the application so that it creates the database! To do so, right-click on **Application.java** (in the **your.app** folder) and select **Run As** -> **WOApplication**. In Eclipse's Console tab, you should see some output, including something similar to:
294 294  
295 295  {{code}}
288 +
296 296  BlogRest[62990] INFO er.extensions.migration.ERXMigrator - Upgrading BlogModel to version 0 with migration 'your.app.model.migrations.BlogModel0@4743bf3d'
297 297  BlogRest[62990] INFO er.extensions.jdbc.ERXJDBCUtilities - Executing CREATE TABLE Author(email VARCHAR(100) NOT NULL, firstName VARCHAR(50) NOT NULL, id INTEGER NOT NULL, lastName VARCHAR(50) NOT NULL)
298 298  BlogRest[62990] INFO er.extensions.jdbc.ERXJDBCUtilities - Executing ALTER TABLE Author ADD PRIMARY KEY (id)
... ... @@ -348,6 +348,7 @@
348 348  Add this method in **BlogEntryController**:
349 349  
350 350  {{code}}
344 +
351 351  protected ERXKeyFilter filter() {
352 352   ERXKeyFilter personFilter = ERXKeyFilter.filterWithAttributes();
353 353   personFilter.setAnonymousUpdateEnabled(true);
... ... @@ -364,6 +364,7 @@
364 364  Now, let's implement the **createAction** method:
365 365  
366 366  {{code}}
361 +
367 367  public WOActionResults createAction() throws Throwable {
368 368   BlogEntry entry = create(filter());
369 369   editingContext().saveChanges();
... ... @@ -377,6 +377,7 @@
377 377  Last step in the controller: implementing the **indexAction** method. Again, the code is simple:
378 378  
379 379  {{code}}
375 +
380 380  public WOActionResults indexAction() throws Throwable {
381 381   NSArray<BlogEntry> entries = BlogEntry.fetchAllBlogEntries(editingContext());
382 382   return response(entries, filter());
... ... @@ -393,6 +393,7 @@
393 393  A route in ERRest is simply a way to define the URL for the entities and to specify which controller the route should use. When your controller extends from **ERXDefaultRouteController**, it's easy to register a controller and a route. In **Application.java**, in the **Application** constructor, add the following code:
394 394  
395 395  {{code}}
392 +
396 396  ERXRouteRequestHandler restRequestHandler = new ERXRouteRequestHandler();
397 397   restRequestHandler.addDefaultRoutes(BlogEntry.ENTITY_NAME);
398 398   ERXRouteRequestHandler.register(restRequestHandler);
... ... @@ -402,7 +402,7 @@
402 402  
403 403  The **addDefaultRoutes** method do all of the required magic, and use convention. That's why we had to name the controller **BlogEntryController**, because the convention is <EntityName>Controller.
404 404  
405 -We are now reading to add and list blog postings! Start the application and take notice of the URL. It should be something like _[[http:~~/~~/yourip:someport/cgi-bin/WebObjects/BlogRest.woa_>>url:http://youripsomeport||shape="rect"]]
402 +We are now reading to add and list blog postings! Start the application and take notice of the URL. It should be something like _[[http:~~/~~/yourip:someport/cgi-bin/WebObjects/BlogRest.woa_>>url:http://yourip:someport/cgi-bin/WebObjects/BlogRest.woa_||shape="rect"]]
406 406  
407 407  == Adding posts and authors with curl ==
408 408  
... ... @@ -417,6 +417,7 @@
417 417  The response should look this:
418 418  
419 419  {{code}}
417 +
420 420  HTTP/1.0 201 Apple WebObjects
421 421  Content-Length: 249
422 422  x-webobjects-loadaverage: 0
... ... @@ -429,6 +429,7 @@
429 429  To get a list of blog entries:
430 430  
431 431  {{code}}
430 +
432 432  curl -X GET http://192.168.0.102:52406/cgi-bin/WebObjects/BlogRest.woa/ra/blogEntries.json
433 433  
434 434  {{/code}}
... ... @@ -440,6 +440,7 @@
440 440  Now, let's build a HTML view for blog posts (you don't want your readers to get your posts by JSON, right?). Again, we will use convention to make it work easily. Open up **BlogEntryController** and add the following method:
441 441  
442 442  {{code}}
442 +
443 443  @Override
444 444   protected boolean isAutomaticHtmlRoutingEnabled() {
445 445   return true;
... ... @@ -452,6 +452,7 @@
452 452  The next step to get it to work is to make **BlogEntryIndexPage** to implement the **er.rest.routes.IERXRouteComponent** interface.
453 453  
454 454  {{code}}
455 +
455 455  import er.rest.routes.IERXRouteComponent;
456 456  
457 457  public class BlogEntryIndexPage extends WOComponent implements IERXRouteComponent {
... ... @@ -461,6 +461,7 @@
461 461  So now, the automatic HTML routing will send the request for **ra/blogEntries.html** to the **BlogEntryIndexPage** component. But we don't have any content in this component, so let's make a method to fetch all blog entries per creation date in descending order. So in **BlogEntryIndexPage.java**, add the following method:
462 462  
463 463  {{code}}
465 +
464 464  public NSArray<BlogEntry> entries() {
465 465   EOEditingContext ec = ERXEC.newEditingContext();
466 466   return BlogEntry.fetchAllBlogEntries(ec, BlogEntry.CREATION_DATE.descs());
... ... @@ -471,6 +471,7 @@
471 471  We need to use that method in a WORepetition, and for that loop, we need a BlogEntry variable to iterate in the list, so add the following code to **BlogEntryIndexPage.java**:
472 472  
473 473  {{code}}
476 +
474 474  private BlogEntry entryItem;
475 475  
476 476   public BlogEntry entryItem() {
... ... @@ -486,6 +486,7 @@
486 486  The Java part is done, so let's add the loop inside the component. Open **BlogEntryIndexPage.wo** (it's located in the **Component** folder) and right after the <body> tag, add:
487 487  
488 488  {{code}}
492 +
489 489  <wo:loop list="$entries" item="$entryItem">
490 490   <p><wo:str value="$entryItem.title" /></p>
491 491   <p><wo:str value="$entryItem.author.fullName" /></p>
... ... @@ -502,6 +502,7 @@
502 502  Open **BlogEntryShowPage.java** and make sure the class implements **er.rest.routes.IERXRouteComponent**.
503 503  
504 504  {{code}}
509 +
505 505  import er.rest.routes.IERXRouteComponent;
506 506  
507 507  public class BlogEntryShowPage extends WOComponent implements IERXRouteComponent {
... ... @@ -511,6 +511,7 @@
511 511  We need to add other methods to receive the BlogEntry object from the controller. In **BlogEntryShowPage.java**, add:
512 512  
513 513  {{code}}
519 +
514 514  private BlogEntry blogEntry;
515 515  
516 516   @ERXRouteParameter
... ... @@ -529,6 +529,7 @@
529 529  The Java part of the work is done, so save the Java class. It's time to work on the component part. Open **BlogEntryShowPage.wo** and between the <body></body> part, add:
530 530  
531 531  {{code}}
538 +
532 532  <h1><wo:str value="$blogEntry.title" /></h1>
533 533   <p><wo:str value="$blogEntry.content" /></p>
534 534   <p>Created on: <wo:str value="$blogEntry.creationDate" dateformat="%Y/%m/%d" /></p>
... ... @@ -539,6 +539,7 @@
539 539  Our view component is done, the only thing remaining is a link for the blog entry list (BlogEntryIndexPage) to the view page (BlogEntryShowPage). Save **BlogEntryShowPage.wo** and open **BlogEntryIndexPage.wo**. We are going to add a link on the title, you will replace to replace this:
540 540  
541 541  {{code}}
549 +
542 542  <p><wo:str value="$entryItem.title" /></p>
543 543  
544 544  {{/code}}
... ... @@ -546,6 +546,7 @@
546 546  with:
547 547  
548 548  {{code}}
557 +
549 549  <p><wo:ERXRouteLink entityName="BlogEntry" record="$entryItem" action="show"><wo:str value="$entryItem.title" /></wo:ERXRouteLink></p>
550 550  
551 551  {{/code}}