% -*- mode: latex; -*- mustache tags:  
\ifx\wholebook\relax\else

	\documentclass[10pt,twoside,english]{root/support/latex/sbabook/sbabook}
  \usepackage{import}
  \subimport{root/support/latex/}{common.tex}

  \hypersetup{pdfinfo = {
    Title = {TinyBlog: A Simple Teapot Web Interface},
    Author = {},
    Keywords = {pharo, smalltalk}}}
  \begin{document}
\fi

\chapter{TinyBlog: A Simple Teapot Web Interface}\section{Previous Week Solution}
You can load the solution of the previous week using the following snippet:

\begin{displaycode}{smalltalk}
Gofer new 
   smalltalkhubUser: 'PharoMooc' project: 'TinyBlog';
   package: 'ConfigurationOfTinyBlog';
   load. 
#ConfigurationOfTinyBlog asClass loadWeek2Correction
\end{displaycode}

After a loading a package, you shall run the unit tests to ensure that the loaded code is correctly working.
Open the TestRunner (World menu \textgreater{} Test Runner), find the 'TinyBlog-Tests' package and run all unit tests of the \textcode{TBBlogTest} class by clicking on the 'Run Selected' button. All tests should be green. One alternative is to press the green icon on the side of the class \textcode{TBBlogTest}.

Open a code browser to look at the code of both classes \textcode{TBBlog} and \textcode{TBBlogTest}. You can now  complete you own implementation if needed. Before continuing, do not forget to commit a new version in your repository on Smalltalkhub or SS3 if you modified your code.
\section{A Web Interface for TinyBlog with Teapot}
This week, we will create a first simple web interface for TinyBlog with Teapot (\url{http://smalltalkhub.com/#!/~zeroflag/Teapot}). We will implement a more complete version with Seaside next week.
\section{The TBTeapotWebApp Class}
Create a new class named \textcode{TBTeapotWebApp}:

\begin{displaycode}{smalltalk}
Object subclass: #TBTeapotWebApp
   instanceVariableNames: 'teapot'
   classVariableNames: 'Server'
   package: 'TinyBlog-Teapot'
\end{displaycode}

The variable \textcode{teapot} will refer to a little Teapot HTTP server. 
Here we use a different implementation of the Singleton Design Pattern by using a
class variable named \textcode{Server}. We use a Singleton to avoid to have two servers listening to the same port.

Add the instance method \textcode{initialize} to initialize the instance variable \textcode{teapot}:

\begin{displaycode}{smalltalk}
TBTeapotWebApp >> initialize
   super initialize.
   teapot := Teapot configure: {
      #port -> 8081.
      #debugMode -> true }.
\end{displaycode}
\subsection{The Home Page}
The \textcode{homePage} method defined inside in the 'html' protocol should return the HTML code of the home page of our web application as a String. Let's start with a simple version:

\begin{displaycode}{smalltalk}
TBTeapotWebApp >> homePage
   ^ '<html><body><h1>TinyBlog Web App</h1></body></html>'
\end{displaycode}
\subsection{Declare Routes}
Add a \textcode{start} method to declare to the \textcode{teapot} object the URLs it must answer to. 
So far, we only add the route \textcode{/} accessed via a GET Http method:

\begin{displaycode}{smalltalk}
TBTeapotWebApp >> start
   teapot
      GET: '/' -> [ self homePage ];
      start
\end{displaycode}
\subsection{Stop the Application}
Add also a method \textcode{stop} to stop the application. 

\begin{displaycode}{smalltalk}
TBTeapotWebApp >> stop
   teapot stop
\end{displaycode}
\subsection{Starting the application}
Add two class-side methods \textcode{start} and \textcode{stop} to start and stop the web application in the protocol 'start/stop'. These two methods use the class variable \textcode{Server} to implement a Singleton. 

\begin{displaycode}{smalltalk}
TBTeapotWebApp class >> start
   Server ifNil: [ Server := self new start ]

TBTeapotWebApp class >> stop
   Server ifNotNil: [ Server stop. Server := nil ]
\end{displaycode}
\section{Test your Application}
Execute the following snippet to start your application:

\begin{displaycode}{smalltalk}
TBTeapotWebApp start
\end{displaycode}

In a web browser, try to access the application with this URL: \url{http://localhost:8081/}. You should see the text: \symbol{34}TinyBlog Web App\symbol{34} as in Figure \ref{fighome}.


\begin{figure}

\begin{center}
\includegraphics[width=0.6\textwidth]{figures/homepage.png}\caption{A first page served by our application.\label{fighome}}\end{center}
\end{figure}

\section{Display the List of All Visible Posts}
Modify now the code of the \textcode{homePage} method to display the list of all visible posts in the current blog. Remember these posts can be obtained with: \textcode{TBBlog current allVisibleBlogPosts}. We implement that functionality by adding three methods and modifying the \textcode{homePage} method.

\begin{displaycode}{smalltalk}
TBTeapotWebApp >> allPosts
   ^ TBBlog current allVisibleBlogPosts 
\end{displaycode}

Since we need to generate a long String that contains the HTML code of the home page, we 
decided to use a Stream in the \textcode{homePage} method. We also factored out the HTML generation of the HTML page header and footer in two 
different methods: \textcode{renderPageHeaderOn:} and \textcode{renderPageFooterOn:}.

\begin{displaycode}{smalltalk}
TBTeapotWebApp >> homePage
   ^ String streamContents: [ :s | 
         self renderPageHeaderOn: s.
         s << '<h1>TinyBlog Web App</h1>'.
         s << '<ul>'.
         self allPosts do: [ :aPost |
            s << ('<li>', aPost title, '</li>') ].
         s << '</ul>'.
         self renderPageFooterOn: s.
      ]
\end{displaycode}

Note that the message \textcode{\textless{}\textless{}} is a different name for the message \textcode{nextPutAll:} that adds a collection of elements to a stream.

\begin{displaycode}{smalltalk}
TBTeapotWebApp >> renderPageHeaderOn: aStream
   aStream << '<html><body>' 

TBTeapotWebApp >> renderPageFooterOn: aStream
   aStream << '</body></html>' 
\end{displaycode}

Test your application in a web browser, you should now see a list of post titles as in
Figure \ref{figposts}. If this is not the case make sure that your blog contains some post.
You can use the message \textcode{createDemoPosts} to add some generic blog posts.

\begin{displaycode}{smalltalk}
TBBlog createDemoPosts
\end{displaycode}


\begin{figure}

\begin{center}
\includegraphics[width=0.6\textwidth]{figures/withPosts.png}\caption{Showing post titles.\label{figposts}}\end{center}
\end{figure}

\section{Details of a Post}\subsection{Add a New Web Page}
We would like that the following URL \url{http://localhost:8081/post/1} displays the whole post number 1.

To start, let us think about the worst case and define what should happen in case of errors. 
We define the method \textcode{errorPage}. 

\begin{displaycode}{smalltalk}
TBTeapotWebApp >> errorPage
   ^ String streamContents: [ :s | 
      self renderPageHeaderOn: s.
      s << '<p>Oups, an error occurred</p>'.
      self renderPageFooterOn: s ]
\end{displaycode}

Teapot supports patterns such as '\textless{}id\textgreater{}' in route definitions. The corresponding value of '\textless{}id\textgreater{}' in the incoming URL is then accessible through the \textcode{request} object passed as a block parameter. 
Now we modify the \textcode{start} method and introduce a new route into the application to display the content of a post.

\begin{displaycode}{smalltalk}
TBTeapotWebApp >> start
   teapot
      GET: '/' -> [ self homePage ];
      GET: '/post/<id>' -> [ :request | self pageForPostNumber: (request at: #id) asNumber ];
      start
\end{displaycode}

We now add a new method named \textcode{pageForPostNumber:} displaying the whole content of a post:

\begin{displaycode}{smalltalk}
TBTeapotWebApp >> pageForPostNumber: aPostNumber
   | currentPost |
   currentPost := self allPosts at: aPostNumber ifAbsent: [ ^ self errorPage ].
   ^ String streamContents: [ :s | 
         self renderPageHeaderOn: s. 
         s << ('<h1>', currentPost title, '</h1>').
         s << ('<h3>', currentPost date mmddyyyy, '</h3>').
         s << ('<p> Category: ', currentPost category, '</p>').
         s << ('<p>', currentPost text, '</p>').
         self renderPageFooterOn: s ]
\end{displaycode}

You can now test your application directly with the following URL:  \url{http://localhost:8081/post/1}

The parameter of \textcode{pageForPostNumber:} is the integer passed in the URL and it is used as an index to retrieve the post to display in the collection of posts. Obviously, this is a fragile solution because if the order of the posts changes in the collection, a given URL will not display the same post as before. 
\subsection{Add Links to Posts}
Modify the \textcode{homePage} method so that post titles in the list will be links to their own web page.

\begin{displaycode}{smalltalk}
TBTeapotWebApp >> homePage
   ^ String streamContents: [ :s | 
         self renderPageHeaderOn: s.
         s << '<h1>TinyBlog Web App</h1>'.
         s << '<ul>'.
         self allPosts withIndexDo: [ :index :aPost |
            s << '<li>';
              << ('<a href="/post/', index asString, '">');
              << aPost title ;
              << '</a></li>' ].
         s << '</ul>'.
         self renderPageFooterOn: s.
      ]
\end{displaycode}

Now, the home page of the application displays a list of clickable post titles and if you click on a post title, you will see the content of this post. 
\section{Possible Extensions}
This application is a really simple and pedagogical example through which you manipulate collections, streams, etc.  

You can improve this web application and implement new functionalities such as:

\begin{itemize}
\item adding a return to home page link on a post page,
\item adding a new page that displays the list of all post categories,
\item adding a new page that displays all posts that belong to one specific category,
\item adding CSS styles to make this web application more appealing. 
\end{itemize}


\ifx\wholebook\relax\else
\end{document}
\fi