code: func (t *Txn) Apply(args *structs.TxnRequest, reply *structs.TxnResponse) error {
  	if done, err := t.srv.forward("Txn.Apply", args, args, reply); done {
  		return err
  	}
  	defer metrics.MeasureSince([]string{"txn", "apply"}, time.Now())
  
  	// Run the pre-checks before we send the transaction into Raft.
  	authorizer, err := t.srv.ResolveToken(args.Token)
  	if err != nil {
  		return err
  	}
  	reply.Errors = t.preCheck(authorizer, args.Ops)
  	if len(reply.Errors) > 0 {
  		return nil
  	}
  
  	// Apply the update.
  	resp, err := t.srv.raftApply(structs.TxnRequestType, args)
  	if err != nil {
  		t.srv.logger.Printf("[ERR] consul.txn: Apply failed: %v", err)
  		return err
  	}
  	if respErr, ok := resp.(error); ok {
  		return respErr
  	}
  
  	// Convert the return type. This should be a cheap copy since we are
  	// just taking the two slices.
  	if txnResp, ok := resp.(structs.TxnResponse); ok {
  		if authorizer != nil {
  			txnResp.Results = FilterTxnResults(authorizer, txnResp.Results)
  		}
  		*reply = txnResp
  	} else {
  		return fmt.Errorf("unexpected return type %T", resp)
  	}
  	return nil
  }
docs: // Apply is used to apply multiple operations in a single, atomic transaction.