Erlanger ~ Truthisanoddnumber.com (original) (raw)
Here’s an end-to-end REST implementation in Chicago Boss. Not sure has anyone a nice concise guide out there so hope this is useful.
Overview
A very simple model (Book[title, author, insertTimestamp, updateTimestamp])
CRUD implementation where
- Â Â Â Â Â Â Create is a POST request
- Â Â Â Â Â Â Read is a GET request
- Â Â Â Â Â Â Update is a PUT request
- Â Â Â Â Â Â Delete is a DELETE request
Focus on the service approach, use a WS client (eg. SoapUI) to test
Use local mysql for simplicity
Assumptions
Erlang is installed (I’m using R16B01)
Access to a mysql server where you can create a schema and user. I have one running locally
DDL
As mentioned, we have a very simple model. A book has two attributes, which are user driven, and two meta attributes which the service will manage.
``
CREATE DATABASE IF NOT EXISTS bookdb
/*!40100 DEFAULT CHARACTER SET utf8 */;
USE bookdb
;
DROP TABLE IF EXISTS books
;
-- Author: jason o riordan Database: bookdb
-- Date: 10/15/13
-- File: books_ddl.sql
CREATE TABLE books
(id
bigint(20) unsigned NOT NULL AUTO_INCREMENT,book_name
varchar(128) DEFAULT NULL,author_name
varchar(128) DEFAULT NULL,insert_timestamp
timestamp DEFAULT '0000-00-00 00:00:00',update_timestamp
timestamp DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (id
),
UNIQUE KEY id
(id
)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
``
Project Creation
Create a new ChicagoBoss project as follows git clone https://github.com/evanmiller/ChicagoBoss.git cd ChicagoBoss
I added the following line to rebar.config dependency section in order to include the cb_admin project
{cb_admin, “.*”, {git, “git://github.com/evanmiller/cb_admin.git”, “HEAD”}}
Now, pull down all ChicagoBoss’s dependencies and create out new project ./rebar get-deps make app PROJECT=bookRestCatalogue
In the bookRestCatalogue dir I edited the boss.config file – boss.config
Note: port  is set to 8004, mysql connection details are set in db section
Model
Very simple model as outlined in the ddl %% %% %% @title book.erl %% @author jasonoriordan %% Created on 07. Oct 2013 9:48 AM %% %% %% @doc book.erl is a module that represents book model %% @end -module(book,[Id, BookName, AuthorName, InsertTimestamp::datetime(), UpdateTimestamp::datetime()]). -author("jasonoriordan"). -compile(export_all). %% %% @doc Validate input, no empty fields are allowed in system %% @end validation_tests() -> [ %% BookName Required {fun() -> BookName =/= undefined andalso length(BookName) =/= 0 end, {book_name, "Book Name required"}}, %% AuthorName Required {fun() -> AuthorName =/= undefined andalso length(AuthorName) =/= 0 end, {author_name, "Author Name required"}} ].
The model and ddl can be verified by hitting cb_admin and going to the model section
REST Contract/Controller
As mentioned we are going to have do CRUD actions on the book entity by have four services exposed. The logic is contained in a controller class, relevant extracts are explained below and full file is available on github
Create – HTTP POST
Pass the bookname and author name as URI arguments
%% Book CREATE %% %% Create a new carrier based on the passed params eg. book/save?authorname=jk&bookname=hp save('POST', []) -> AuthorName = Req:post_param("authorname"), BookName = Req:post_param("bookname"), NewBook = carrier:new(id,AuthorName, BookName, calendar:universal_time(),calendar:universal_time()), % have record and return the newly created if ok or errors otherwise, in json format case NewBook:save() of {ok, SavedBook} -> {json, SavedBook}; {error, Errors} -> {json, Errors} end.
Read – HTTP GET
Read the book names by passing the id %% BOOK Read %% %% Read the bookId from the url eg. book/view/book-7 view('GET', [BookId]) -> error_logger:info_msg("GET-book/view/~p request recieved~n",[BookId]), Book = boss_db:find(BookId), case Book of [] -> {output,<<"[]">>,[{"Content-Type","application/json"}]}; _Else -> {json, Book} end.
Read all carriers by hitting view_all %% BOOK Read ALL %% %% Return all eg. book/view_all view_all('GET', []) -> error_logger:info_msg("GET-book/view_all request revieved~n"), Books = boss_db:find(book, []), case Books of [] -> {output,<<"[]">>,[{"Content-Type","application/json"}]}; _Else -> {json, Books} end.
Update – HTTP PUT
Update the book by passing the  bookname and authorname as URI arguments. Also updates the update_timestamp
%% Book Update %% %% Note: can also update by populating id with an actual value and calling 'new' %% UpdatedBook = book:new(BookName,AuthorName, calendar:universal_time(),calendar:universal_time()), %% Updates the book based on the passed params eg. book/update?bookid=myid&bookname=cuckoo&authorname=jk update('PUT', []) -> BookId = Req:post_param("bookid"), BookName = Req:post_param("bookname"), AuthorName = Req:post_param("authorname"), Book = boss_db:find(BookId), % update via attribute setting (as we don't want to update create_timestamp) BookWithUpdatedName = Book:set(book_name,BookName), BookWithUpdatedAuthor = BookWithUpdatedName:set(author_name,AuthorName), BookWithUpdateTS = BookWithUpdatedAuthor:set(update_timestamp,calendar:universal_time()), case BookWithUpdateTS:save() of {ok, UpdatedBook} -> {json, UpdatedBook}; {error, Errors} -> {json, Errors} end.
Delete – HTTP DELETE
Delete the book entity by passing %% Book DELETE %% %% Delete the specified book from the system eg. book/delete/book-7 delete('DELETE', [BookId]) -> boss_db:delete(BookId), case boss_db:counter(BookId) of 0 -> {output,<<"{ \"Deleted Status\": \"Book Deleted\" }">>,[{"Content-Type","application/json"}]}; _Else -> {output,<<"error">>,[{"Content-Type","application/json"}]} end.
Testing
Focus of this post is on service level so have added a SoapUI testsuite in order to test functionality
SoapUI test file is available from Git
Note: be sure to set attributes to Method level for create and update as per screenshot