Treats

Treats

  • Getting Started

›Tutorial

Getting Started

  • Installation

Tutorial

  • 01. Creating Your First Page
  • 02. Using Redux
  • 03. Using GraphQL
  • 04. Fetch Data for SSR
  • 05. Adding Addons

Main Concepts

  • Overview
  • Routing
  • Localization
  • Code-splitting
  • Redux
  • GraphQL Client
  • Middlewares
  • Helpers
  • Server-side Events
  • Server-side Template
  • Server-side Rendering
  • Custom Server App
  • Custom Client Initialization
  • Custom React App
  • Runtime Config
  • Build Config
  • Environment Variables
  • Code Generator
  • Scripts
  • Addons
  • Typescript
  • Workbox

API Reference

  • Overview
  • Filesystem Hooks
  • Components
  • Server
  • Client
  • Router
  • Intl
  • Locale Data
  • Helmet
  • Redux
  • Graphql

Authoring Addons

  • Overview
  • Helpers
  • Middlewares
  • Generators
  • Wrapping Up

Addons

  • Treats Addons List

Contributing

  • How To Contribute

FAQ

  • FAQs

05. Adding Addons on Treats Server

Treats was designed so it could be easily customisable with addons. We will try to add addons into our todo apps. Let's start with addons-base. Add this point, the one that's useful enough for our todo-apps is circuit breaker (CB), assuming that our countries API may be slower than usual or just hang our request without response.

  1. Install @treats/addons-base in our todo projects.
~$ npm install @treats/addons-base
  1. Create _server hooks to customise our server behaviour. Inside it, create index.js with the following implementation.
/* src/_server/index.js */

import initServer from "@treats/server";
import CircuitBreaker from "@treats/addons-base/helper/circuitbreaker";

const app = initServer({
    customHelpers: CircuitBreaker
});

export default app;

By doing this, we could get our CircuitBreaker instance by const cb = app.get("circuitbreaker").

  1. By adding CircuitBreaker into our server app, we need to change our getInitialState method, since we will get our app instance from req object (read more from Express).
/* src/redux/profile-page/action.js */

...
const getInitialState = req => dispatch => {
    return Promise.all([dispatch(getCountries(req))])
}
...
/* src/page/profile-page/profile.js */

class Profile extends Component {
    static async getInitialState({ router, serverContext }) {
        const { req, reduxStore } = serverContext;
        return reduxStore.dispatch(profileActions.getInitialState(req));
    }
    ...
}
  1. Now that getCountries also get req as parameters, we need to change the implementation, too. We also need to consider that getCountries() could be run on client side (when clicking "change name" link) -- it means getCountries() would not get req object. Therefore, we need to add two cases for server and client environment.
/* src/page/profile-page/profile.js */

...
const getCountries = req => dispatch => {
    dispatch(getCountriesLoading());

    if (process.env.BUILD_TARGET === "server") {
        const { app } = req,
            cb = app.get("circuitbreaker");

        console.log("API CALL with CB")
        return cb.call(
            axios.get,
            "https://restcountries.eu/rest/v2/all",
            ["https://restcountries.eu/rest/v2/all", { method: "GET" }])
            .then(response => {
                const parsedResponse = response.data.map(country => ({
                    code: country.alpha2Code,
                    name: country.name
                }))
                dispatch(getCountriesSuccess(parsedResponse));
            }).catch(err => {
                dispatch(getCountriesError());
                console.error(err);
            })
    }
    return axios.get("https://restcountries.eu/rest/v2/all")
    .then(response => {
        const parsedResponse = response.data.map(country => ({
            code: country.alpha2Code,
            name: country.name
        }))
        dispatch(getCountriesSuccess(parsedResponse));
    }).catch(err => {
        dispatch(getCountriesError());
        console.error(err);
    });
};
...
  1. Last but not least, we need to create config for our circuit breaker. To create our circuit breaker config, we will create it in <PROJECTS_DIRECTORY>/treats.runtime-config.json.
{
    "helper": {
        "circuitbreaker": {
            "https://restcountries.eu/rest/v2/all": {
                "timeout": 3000,
                "errorThresholdPercentage": 50,
                "resetTimeout": 30000
            }
        }
    }
}
  1. All set! Let's see if our CB working by proceed to /profile. Refresh the page if you are proceed to the profile page via "Change Name" button. To check if our CB work on error, set the config timeout into 1. Most likely, the api call will timeout and logging some error in your server console.

This is some example of using addons in Treats. Explore addons concepts: middleware, helper, and generator and create your own addons!

← 04. Fetching Data for Server-Side-RenderOverview →
Tokopedia Open Source
Copyright © 2019 Tokopedia OSS