Skip to content

Instantly share code, notes, and snippets.

@mimol91
Last active September 18, 2016 20:40
Show Gist options
  • Save mimol91/47257a66b46ef39ebbae8b1f76239f55 to your computer and use it in GitHub Desktop.
Save mimol91/47257a66b46ef39ebbae8b1f76239f55 to your computer and use it in GitHub Desktop.
HAL + SPA

HAL + SPA

Technology
  • React - A JavaScript library for building user interfaces
  • Redux - RESTful HTTP client for JavaScript
  • Rest - Predictable state container for JavaScript apps

Introduction

React containers should be self aware and be able to fetch required data to pass it to components. Using HAL may cause to send multiple request to obtain this same data. This document shows possible solutions how this can be solved.

Lets assume that real API looks similar to:

  • [root] - Contains only links to other endpoints
  • [users] {userId} - Store information about user, Has link to user address
  • [users] {userId} [address] - Returns information about user address

Graphical representaion

(root)
├──get-user(userId)
│ └──get-address
└─ ...

If react consist component as described bellow:

  • UserView
  • UserContainer
  • UserDetailsComponent
  • UserAddressComponent

UserContainer could fetch all data and pass it to components. It has drawback because if a new data should be present on view (for example: Group names where user belong) it will require change of login in UserContainer.

Solutions

The basic solution is to move logic, so that each component-container pair will be self aware to fetch data and present it. The only required parameter will be resoure from whcih the data can be obtained.

If react consist component as described bellow:

  • UserView
  • UserContainer
  • UserDetailsContainer
  • UserDetailsComponent
  • UserAddressContainer
  • UserAddressComponent

UserDetailsContainer and UserAddressContainer depends on resource property, which is a resource from restjs which allow to fetch desired data.

Each components should have this same hierartical order as presenter in HAL API.

(UserView)
├──UserContainer  
│ ├──UserDetailsContainer
│ │ ├ UserAddressContainer
│ │ └─UserAddressComponent
│ └──UserDetailsComponent
...

Responsibilities:

UserContainer :

  • Should fetch root api and pass Resource allowing to fetch UserDetails to UserDetailsContainer

UserDetailsContainer :

  • Should fetch user details using resource
  • Should pass fetched data to UserDetailsComponent
  • Should pass UserAddress resource to UserAddressContainer

UserAddressContainer :

  • Should fetch user details using resource
  • Should pass fetched data to UserAddressComponent

HTML Structure (UserView)

<UserContainer resource={rootResource}>
    <UserDetailsContainer resource={userDetailsResource}>
        <UserDetailsComponent data={userDetails} />
        <UserAddressContainer resource={userAddressResource} >
            <UserAddressComponent data={userAddress} />
        <UserAddressContainer />
    </UserDetailsContainer>
</UserContainer>

Each component have to:

  • Fetch Data using resource passed by parent and pass it to container

Ech component may to:

  • Pass to childeren resource allowing to fetch data required by children

Adventages

  • Resource is stored in store so there is no necessary to start building resource and set 'follow' from rootApi -> Amount of request is reducet
  • When there is necessary to display a new data only the parent container has to change. (Its easy, because the structure is this same as in HAL)

Store

The resource should be stored inside store, thanks to resourceReducer. Because of HTTP specification only GET requests may be cached. It solve a lot of problem, because to cache respirce information only resourceName and resourceParameters are required

Store resource representation

{
	"resource": {
		"root": [{
			"parentParams": null,
			"resource": "ResourceObject",
			"links": {
				"userDetails": [{
					"parentParams": null,
					"resource": "ResourceObject",
					"links": {
						"userAddress": [{
							"parentParams": {
								"userId": 4
							},
							"resource": "ResourceObject"
						}, {
							"parentParams": {
								"userId": 5
							},
							"resource": "ResourceObject"
						}]
					}
				}]
			}
		}]
	}
}

Thanks to this solution its very easy to fetch user details (just grab the userDetails resource and execute) and also to get userAddress. If passed userId does not exist, need to call parent resource, with given userId and fetch userAddress again.

To simplify usuage, spereate service should be created, which will accept follow path which is an array of objects.

getResource(["userDetails", {name:"userAddress", params:{ userId:4 }}])

Service should automatically traverse all stored resources by name, and check if parentParams match. If argument is a string where it should be automatically resolved to an object, where name key is set to stringValue, and params should be null

Thanks to nesting component we may be sure that required follow path has been already stored and it may be used without generating requests again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment