Since the first story was published, I have talked about my blog-like application and have not talked about the web at all! In this story, I will describe the code that uses the web so that the user can access the application.

The Web Layer

This layer accepts an input from the web, executes the application specified by the input, and sends the output of the application back to the client. The most important thing in this layer is that the logic in this layer does not contain any knowledge of the application.

Access to Application through JSON

Here is an example that serves the api for creating an empty post:

(defpackage :blog.web.ningle

(:use :cl))

(in-package :blog.web.ningle) (defun bind-api (app &key db id-provider)

(setf (ningle:route app "/api/v1/post" :method :post)

(lambda (params)

(declare (ignore params))

(-> (blog:create-empty-post db :id-provider id-provider)

(as-api-response))))

app)

Here -> is a threading macros provided by a library such as cl-arrows , which is useful for describing a sequence of operations.

I assume that as-api-response be a function that takes any data and converts it to a response object suitable for both the client and the ningle framework.

(defun as-api-resonse (data)

(jsown:to-json

(jsown:obj

("ok" :true)

("result" (convert-to-jsown data))))) (defgeneric convert-to-jsown (data)) (defmethod convert-to-jsown ((data string))

data)

Access to Application through HTML

(defun bind-html (app &key db id-provider)

(setf (ningle:route app "/post" :method :post)

(lambda (params)

(declare (ignore params))

(-> (blog:create-empty-post db :id-provider id-provider)

(blog.web.page.edit:url)

(redirect)))) (setf (ningle:route app "/edit?:post-id" :get)

(lambda (params)

(let ((post-id ...))

(-> (blog:get-post db post-id)

(blog.web.page.edit:render)))

app)

This is another access to the application. After creating an empty post, I redirect the user to the edit page for the created post. This sequence seems to be common in blog applications. To show the edit page for the post, I get the post from the database, which will be described later, and render the edit page with the post content.

The both of the code accepts an input from the path, passes it to the application of creating an empty post, and sends the output data back to the client in a certain format. This is just what I want this layer to do.

The code in this layer may tend to have the pattern: accept the input, execute the application, and send back the output. Thanks to web frameworks and libraries, we can reduce the amount of the code for the pattern. The concern of web frameworks is limited to the web, not beyond into the application logic.

Which access is used does not affect the application of creating an empty post. I think that a way to access an application should not affect how the application is composed.

The Main Function

(depfackage :blog.web

(:use :cl))

(in-package :blog.web) (defun main (&key (port 8080))

(let ((db

(dbi:connect "..."))

(uuid-provider

(make-instance 'blog.entities.id:uuid-provider)))

(let ((app (make-instance 'ningle:app))

(blog.web.ningle:bind-api app

:db db

:id-provider uuid-provider)

(blob.web.ningle:bind-html app

:db db

:id-provider id-provider)

(clack:clackup app :port port)

app)))