code: func (s *Service) handleJoin(w http.ResponseWriter, r *http.Request) {
  	b, err := ioutil.ReadAll(r.Body)
  	defer r.Body.Close()
  	if err != nil {
  		w.WriteHeader(http.StatusBadRequest)
  		return
  	}
  	md := map[string]interface{}{}
  	if err := json.Unmarshal(b, &md); err != nil {
  		w.WriteHeader(http.StatusBadRequest)
  		return
  	}
  
  	remoteID, ok := md["id"]
  	if !ok {
  		w.WriteHeader(http.StatusBadRequest)
  		return
  	}
  	remoteAddr, ok := md["addr"]
  	if !ok {
  		w.WriteHeader(http.StatusBadRequest)
  		return
  	}
  	var m map[string]string
  	if _, ok := md["meta"].(map[string]interface{}); ok {
  		m = make(map[string]string)
  		for k, v := range md["meta"].(map[string]interface{}) {
  			m[k] = v.(string)
  		}
  	}
  
  	if err := s.store.Join(remoteID.(string), remoteAddr.(string), m); err != nil {
  		if err == store.ErrNotLeader {
  			leader := s.leaderAPIAddr()
  			if leader == "" {
  				http.Error(w, err.Error(), http.StatusServiceUnavailable)
  				return
  			}
  
  			redirect := s.FormRedirect(r, leader)
  			http.Redirect(w, r, redirect, http.StatusMovedPermanently)
  			return
  		}
  
  		b := bytes.NewBufferString(err.Error())
  		w.WriteHeader(http.StatusInternalServerError)
  		w.Write(b.Bytes())
  		return
  	}
  }
docs: // handleJoin handles cluster-join requests from other nodes.