🚀
ShipClojure
  • README
  • Development
    • Getting Started
    • REPL Workflow
    • AI Development with ShipClojure
    • Getting Updates
    • Formatting code
    • ShipClojure Guiding Principles
  • Backend
    • Migrations
    • Secrets
    • Routing
    • ShipClojure Blog
    • Email
  • Frontend
    • UIx + re-frame
    • HTTP Requests with Re-frame
    • Frontend Navigation with Re-frame
    • Toast Notifications
    • Icons
  • Server Side Rendering
    • Static/Landing pages
  • Auth
    • How Auth works
    • Oauth2 providers
  • Deployment
    • Deployment
  • Decisions
    • 001 - Cookie Sessions
    • 002 - Single Page Application Architecture
    • 003 - Re-frame instead of Refx
    • 003 - Move from cookie sessions to JWT Access + refresh tokens
Powered by GitBook
On this page
  • Overview
  • Basic API Requests
  • API Endpoint Specification
  • Authenticated Requests
  • Token Refresh Mechanism
  • Request Configuration Options
  • Handling Responses
  • On Success
  • Multiple Success Handlers
  • On Failure
  • Multiple Failure Handlers
  • Common Request Patterns
  • Login
  • Authenticated Data Fetch
  • Form Submission with Loading State
  • Content Types
  • CSRF Protection
  • Error Handling
  • Implementation Details
  1. Frontend

HTTP Requests with Re-frame

This document explains how to make HTTP requests in the application using Re-frame events and effects.

Overview

The application provides several ways to make HTTP requests:

  1. :http/api - For making requests to the application's API endpoints

  2. :http/auth-api - For making authenticated requests that automatically include the user's access token

  3. :http/request - For making requests to any URL, not just the application's API

These are implemented as Re-frame effects that can be used in your event handlers.

Basic API Requests

The :http/api effect is the primary way to make requests to your application's API endpoints.

(rf/dispatch
  [:http/api
   {:method :post
    :url :account/sign-up
    :body {:email "user@example.com"
           :password "password123"}
    :on-success [:sign-up-success]
    :on-failure [:sign-up-failure]}])

API Endpoint Specification

API endpoints can be specified in two ways:

  1. Keywords: When using a keyword like :account/log-in, it will be automatically converted to /api/account/log-in

  2. Strings: You can also use full paths like "/api/account/verify"

;; These are equivalent:
{:url :account/log-in}
{:url "/api/account/log-in"}

Authenticated Requests

The :http/auth-api event is used for making authenticated requests. It automatically includes the user's access token in the Authorization header.

(rf/dispatch
  [:http/auth-api
   {:url :user/profile
    :method :get
    :on-success [:profile-loaded]
    :on-failure [:profile-load-error]}])

Behind the scenes, this is converted to an :http/api call with the token included:

;; What happens internally:
{:http/api (assoc params :token (get-in db [:auth :access-token]))}

Token Refresh Mechanism

A key feature of the HTTP request system is automatic token refresh when authentication fails:

  1. When a request returns a 401 Unauthorized error

  2. The system automatically attempts to refresh the token

  3. If token refresh succeeds, the original request is retried with the new token

  4. If token refresh fails, the user is redirected to the login page

This mechanism is transparent to your application code - you don't need to handle token refresh explicitly.

Request Configuration Options

When making requests, you can specify the following options:

Option
Type
Description

:url

Keyword/String

The API endpoint to request

:method

Keyword

The HTTP method to use (:get, :post, :put, :delete, :head)

:body

Map/String

The request payload

:headers

Map

Additional HTTP headers

:query-params

Map

URL query parameters

:token

String

Authorization token (added automatically for :http/auth-api)

:success-path

Vector

Path within response to extract data from

:content-type

Keyword

Request content type (defaults to :transit-json)

:accept

Keyword

Response content type to accept (defaults to :transit-json)

Handling Responses

There are several ways to handle responses from HTTP requests:

On Success

(rf/dispatch
  [:http/api
   {:url :data/fetch
    :on-success [:data-fetched]}])

;; Define the success handler
(rf/reg-event-db
  :data-fetched
  (fn [db [_ response]]
    (assoc db :data response)))

Multiple Success Handlers

You can trigger multiple events on success:

(rf/dispatch
  [:http/api
   {:url :account/log-in
    :method :post
    :body credentials
    :on-success-n [[:auth/login-success] 
                   [:router/navigate {:route ::routes/dashboard}]]}])

On Failure

(rf/dispatch
  [:http/api
   {:url :data/fetch
    :on-failure [:data-fetch-error]}])

;; Define the failure handler
(rf/reg-event-db
  :data-fetch-error
  (fn [db [_ error]]
    (assoc db :error error)))

Multiple Failure Handlers

(rf/dispatch
  [:http/api
   {:url :data/fetch
    :on-failure-n [[:data-fetch-error] 
                   [:toast/error {:message "Failed to fetch data"}]]}])

Common Request Patterns

Login

(rf/reg-event-fx
  ::login
  (fn [_ [_ credentials]]
    {:http/api {:method :post
                :url :account/log-in
                :body credentials
                :on-success-n [[::auth-success] 
                               [:router/navigate {:route ::routes/dashboard}]]
                :on-failure [::auth-failure]}}))

Authenticated Data Fetch

(rf/reg-event-fx
  ::fetch-profile
  (fn [_ _]
    {:http/auth-api {:url :user/profile
                    :on-success [::profile-loaded]
                    :on-failure [::profile-load-error]}}))

Form Submission with Loading State

(rf/reg-event-fx
  ::save-settings
  (fn [{:keys [db]} [_ settings]]
    {:db (assoc db :saving-settings? true)
     :http/auth-api {:method :post
                    :url :user/settings
                    :body settings
                    :on-success [::settings-saved]
                    :on-failure [::settings-save-error]}}))

(rf/reg-event-db
  ::settings-saved
  (fn [db [_ result]]
    (-> db
        (assoc :settings result)
        (dissoc :saving-settings?))))

(rf/reg-event-db
  ::settings-save-error
  (fn [db [_ error]]
    (-> db
        (assoc :settings-error error)
        (dissoc :saving-settings?))))

Content Types

The API supports several content types:

  • :transit-json (default) - Transit format encoded as JSON

  • :json - Standard JSON

  • :form-encoded - URL-encoded form data

  • :text - Plain text

  • :html - HTML

  • :edn - EDN (Clojure data format)

To specify a content type:

(rf/dispatch
  [:http/api
   {:url :data/fetch
    :content-type :json
    :accept :json
    :on-success [:data-fetched]}])

CSRF Protection

For non-GET requests, a CSRF token is automatically included in the headers. The token is retrieved from a hidden form field with the ID __anti-forgery-token.

Error Handling

By default, responses with status codes >= 400 are treated as errors. The error handler will receive either the error object or the response body.

Implementation Details

The HTTP request system is implemented in:

  • src/cljs/saas/db/events.cljs: Re-frame event and effect handlers

  • src/cljs/saas/query.cljs: Actual HTTP request implementation

  • src/cljs/saas/auth.cljs: Authentication and token management

PreviousUIx + re-frameNextFrontend Navigation with Re-frame

Last updated 1 month ago