Skip to content
Ryan Neufeld edited this page Jul 9, 2013 · 9 revisions

To follow along with this section, start with tag v2.0.4.

The application will need to publish the local counter value via the service. In this section you will enhance the service simulator to simulate this behavior. While making this change you will learn about the following pedestal-app concepts:

  • Effect functions
  • Consuming effects from the effect queue

Effecting the outside world

The application is now receiving input from the outside world. In this section you will let it have an effect on the outside world by allowing it to send its counter value to a service.

So far, this tutorial has introduced two kinds of dataflow functions: transforms and emitters. Transform functions deal with input and emitters deal with output. Emitters take an input map as input and return a vector of rendering deltas. Applications need to produce another kind of output. They need the ability to have an effect on the outside world. The pedestal-app dataflow accomplishes this with the effect function.

An effect function takes its inputs as arguments and returns a vector of messages which are to be sent out of the application. These messages can be arbitrary Clojure data and there are no rules about what can be done with them.

In this section, you will use an effect function to publish the local counter value to the service.

In the namespace tutorial-client.behavior, create the following effect function.

(defn publish-counter [count]
  [{msg/type :swap msg/topic [:other-counters] :value count}])

As with all dataflow functions except for transform functions, the exact arguments to an effect function will depend on how that function is configured. The publish-counter function takes the current count as an argument.

The returned message is similar to the message which we expect to receive from the service except that the path does not include the id value. When this message arrives at the service, the session id will be added to the topic before the message is forwarded to the other clients.

To add this function to the dataflow, you add an :effect key. Effects are configured as a set of vectors. Sets are used because order is not important and there can be no duplicates. Each vector has three elements: a set of inputs, the effect function and the arguments specification.

:effect #{[#{[:my-counter]} publish-counter :single-val]}

The arguments specification indicates that the function should be passed a single value which will be the value at :my-counter in the data model. For more information on argument specifiers, see [[Derived Values]].

This configuration will cause the publish-counter function to be called whenever the value at :my-counter changes.

The complete dataflow definition will now look like the one shown below.

(def example-app
  {:version 2
   :transform [[:inc  [:my-counter] inc-transform]
               [:swap [:**]         swap-transform]]
   :effect #{[#{[:my-counter]} publish-counter :single-val]}
   :emit [{:init init-main}
          [#{[:my-counter] [:other-counters :*]} (app/default-emitter [:main])]]})

Consuming effects

What happens to effects after they are generated? Effect messages are put on a queue and can be consumed by a service. The simulated service will handle these messages by printing them to the JavaScript console.

In the tutorial-client.simulated.services namespace, add the following function which will be used to process outgoing messages. In the real service, this function would send the message over the network to a back-end service.

(defn services-fn [message input-queue]
  (.log js/console (str "Sending message to server: " message)))

The handler function receives the message and the input-queue. The input-queue is used to allow callbacks to send results back to the application. Here it is ignored.

The main function in the namespace tutorial-client.simulated.start is where the simulated version of the application starts. This is where you will arrange for some function to receive each message that is placed on the effects queue.

First, require the io.pedestal.app namespace.

[io.pedestal.app :as app]

Next, use the consume-effects function to cause services/services-fn to receive each message from this queue.

(app/consume-effects (:app app) services/services-fn)

The main function should now look like the one shown below.

(defn ^:export main []
  (let [app (start/create-app d/data-renderer-config)
        services (services/->MockServices (:app app))]
    (app/consume-effects (:app app) services/services-fn)
    (p/start services)
    app))

To test that this works, refresh the Data UI page, open the JavaScript console and click on the Increment Counter button. You should see the message printed in the console.

Next steps

This simple application can now store a few basic values in its data model and can send and receive messages. The next section will introduce dataflow in a bit more detail as it describes how to use derive functions to generate new values.

The tag for this section is v2.0.5.

Home | Derived Values

Clone this wiki locally